blob: 42ea0f1e9b04d5fae624c3c0c99621c68c94325d [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Linker.h"
18#include "Logger.h"
Adam Lesinski24aad162015-04-24 19:19:30 -070019#include "NameMangler.h"
20#include "Resolver.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080021#include "ResourceParser.h"
22#include "ResourceTable.h"
23#include "ResourceValues.h"
24#include "StringPiece.h"
25#include "Util.h"
26
27#include <androidfw/AssetManager.h>
28#include <array>
Adam Lesinskica2fc352015-04-03 12:08:26 -070029#include <bitset>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080030#include <iostream>
31#include <map>
32#include <ostream>
33#include <set>
34#include <sstream>
35#include <tuple>
36#include <vector>
37
38namespace aapt {
39
40Linker::Args::Args(const ResourceNameRef& r, const SourceLine& s) : referrer(r), source(s) {
41}
42
Adam Lesinski24aad162015-04-24 19:19:30 -070043Linker::Linker(std::shared_ptr<ResourceTable> table, std::shared_ptr<IResolver> resolver) :
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080044 mTable(table), mResolver(resolver), mError(false) {
45}
46
47bool Linker::linkAndValidate() {
48 std::bitset<256> usedTypeIds;
49 std::array<std::set<uint16_t>, 256> usedIds;
50 usedTypeIds.set(0);
51
52 // First build the graph of references.
53 for (auto& type : *mTable) {
54 if (type->typeId != ResourceTableType::kUnsetTypeId) {
55 // The ID for this type has already been set. We
56 // mark this ID as taken so we don't re-assign it
57 // later.
58 usedTypeIds.set(type->typeId);
59 }
60
61 for (auto& entry : type->entries) {
62 if (type->typeId != ResourceTableType::kUnsetTypeId &&
63 entry->entryId != ResourceEntry::kUnsetEntryId) {
64 // The ID for this entry has already been set. We
65 // mark this ID as taken so we don't re-assign it
66 // later.
67 usedIds[type->typeId].insert(entry->entryId);
68 }
69
70 for (auto& valueConfig : entry->values) {
71 // Dispatch to the right method of this linker
72 // based on the value's type.
73 valueConfig.value->accept(*this, Args{
74 ResourceNameRef{ mTable->getPackage(), type->type, entry->name },
75 valueConfig.source
76 });
77 }
78 }
79 }
80
81 /*
82 * Assign resource IDs that are available.
83 */
84 size_t nextTypeIndex = 0;
85 for (auto& type : *mTable) {
86 if (type->typeId == ResourceTableType::kUnsetTypeId) {
87 while (nextTypeIndex < usedTypeIds.size() && usedTypeIds[nextTypeIndex]) {
88 nextTypeIndex++;
89 }
90 type->typeId = nextTypeIndex++;
91 }
92
93 const auto endEntryIter = std::end(usedIds[type->typeId]);
94 auto nextEntryIter = std::begin(usedIds[type->typeId]);
95 size_t nextIndex = 0;
96 for (auto& entry : type->entries) {
97 if (entry->entryId == ResourceTableType::kUnsetTypeId) {
98 while (nextEntryIter != endEntryIter &&
99 nextIndex == *nextEntryIter) {
100 nextIndex++;
101 ++nextEntryIter;
102 }
103 entry->entryId = nextIndex++;
104
Adam Lesinski24aad162015-04-24 19:19:30 -0700105 std::u16string unmangledPackage = mTable->getPackage();
106 std::u16string unmangledName = entry->name;
107 NameMangler::unmangle(&unmangledName, &unmangledPackage);
108
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800109 // Update callers of this resource with the right ID.
110 auto callersIter = mGraph.find(ResourceNameRef{
Adam Lesinski24aad162015-04-24 19:19:30 -0700111 unmangledPackage,
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800112 type->type,
Adam Lesinski24aad162015-04-24 19:19:30 -0700113 unmangledName
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800114 });
115
116 if (callersIter != std::end(mGraph)) {
117 for (Node& caller : callersIter->second) {
118 caller.reference->id = ResourceId(mTable->getPackageId(),
119 type->typeId,
120 entry->entryId);
121 }
122 }
123 }
124 }
125 }
126
127 return !mError;
128}
129
130const Linker::ResourceNameToSourceMap& Linker::getUnresolvedReferences() const {
131 return mUnresolvedSymbols;
132}
133
134void Linker::visit(Reference& reference, ValueVisitorArgs& a) {
135 Args& args = static_cast<Args&>(a);
136
Adam Lesinski769de982015-04-10 19:43:55 -0700137 if (!reference.name.isValid()) {
138 // We can't have a completely bad reference.
139 assert(reference.id.isValid());
140
141 // This reference has no name but has an ID.
142 // It is a really bad error to have no name and have the same
143 // package ID.
144 assert(reference.id.packageId() != mTable->getPackageId());
145
146 // The reference goes outside this package, let it stay as a
147 // resource ID because it will not change.
148 return;
149 }
150
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800151 Maybe<ResourceId> result = mResolver->findId(reference.name);
152 if (!result) {
153 addUnresolvedSymbol(reference.name, args.source);
154 return;
155 }
156
157 const ResourceId& id = result.value();
158 if (id.isValid()) {
159 reference.id = id;
160 } else {
161 // We need to update the ID when it is set, so add it
162 // to the graph.
163 mGraph[reference.name].push_back(Node{
164 args.referrer,
165 args.source.path,
166 args.source.line,
167 &reference
168 });
169 }
170
171 // TODO(adamlesinski): Verify the referencedType is another reference
172 // or a compatible primitive.
173}
174
175void Linker::processAttributeValue(const ResourceNameRef& name, const SourceLine& source,
176 const Attribute& attr, std::unique_ptr<Item>& value) {
177 std::unique_ptr<Item> convertedValue;
178 visitFunc<RawString>(*value, [&](RawString& str) {
179 // This is a raw string, so check if it can be converted to anything.
180 // We can NOT swap value with the converted value in here, since
181 // we called through the original value.
182
183 auto onCreateReference = [&](const ResourceName& name) {
Adam Lesinski24aad162015-04-24 19:19:30 -0700184 // We should never get here. All references would have been
185 // parsed in the parser phase.
186 assert(false);
187 //mTable->addResource(name, ConfigDescription{}, source, util::make_unique<Id>());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800188 };
189
Adam Lesinski24aad162015-04-24 19:19:30 -0700190 convertedValue = ResourceParser::parseItemForAttribute(*str.value, attr,
191 onCreateReference);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800192 if (!convertedValue && attr.typeMask & android::ResTable_map::TYPE_STRING) {
193 // Last effort is to parse as a string.
194 util::StringBuilder builder;
195 builder.append(*str.value);
196 if (builder) {
197 convertedValue = util::make_unique<String>(
198 mTable->getValueStringPool().makeRef(builder.str()));
199 }
200 }
201 });
202
203 if (convertedValue) {
204 value = std::move(convertedValue);
205 }
206
207 // Process this new or old value (it can be a reference!).
208 value->accept(*this, Args{ name, source });
209
210 // Flatten the value to see what resource type it is.
211 android::Res_value resValue;
212 value->flatten(resValue);
213
214 // Always allow references.
215 const uint32_t typeMask = attr.typeMask | android::ResTable_map::TYPE_REFERENCE;
216 if (!(typeMask & ResourceParser::androidTypeToAttributeTypeMask(resValue.dataType))) {
217 Logger::error(source)
218 << *value
219 << " is not compatible with attribute "
220 << attr
221 << "."
222 << std::endl;
223 mError = true;
224 }
225}
226
227void Linker::visit(Style& style, ValueVisitorArgs& a) {
228 Args& args = static_cast<Args&>(a);
229
Adam Lesinski769de982015-04-10 19:43:55 -0700230 if (style.parent.name.isValid() || style.parent.id.isValid()) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800231 visit(style.parent, a);
232 }
233
234 for (Style::Entry& styleEntry : style.entries) {
Adam Lesinski24aad162015-04-24 19:19:30 -0700235 Maybe<IResolver::Entry> result = mResolver->findAttribute(styleEntry.key.name);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800236 if (!result || !result.value().attr) {
237 addUnresolvedSymbol(styleEntry.key.name, args.source);
238 continue;
239 }
240
Adam Lesinski24aad162015-04-24 19:19:30 -0700241 const IResolver::Entry& entry = result.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800242 if (entry.id.isValid()) {
243 styleEntry.key.id = entry.id;
244 } else {
245 // Create a dependency for the style on this attribute.
246 mGraph[styleEntry.key.name].push_back(Node{
247 args.referrer,
248 args.source.path,
249 args.source.line,
250 &styleEntry.key
251 });
252 }
253 processAttributeValue(args.referrer, args.source, *entry.attr, styleEntry.value);
254 }
255}
256
257void Linker::visit(Attribute& attr, ValueVisitorArgs& a) {
258 static constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM |
259 android::ResTable_map::TYPE_FLAGS;
260 if (attr.typeMask & kMask) {
261 for (auto& symbol : attr.symbols) {
262 visit(symbol.symbol, a);
263 }
264 }
265}
266
267void Linker::visit(Styleable& styleable, ValueVisitorArgs& a) {
268 for (auto& attrRef : styleable.entries) {
269 visit(attrRef, a);
270 }
271}
272
273void Linker::visit(Sentinel& sentinel, ValueVisitorArgs& a) {
274 Args& args = static_cast<Args&>(a);
275 addUnresolvedSymbol(args.referrer, args.source);
276}
277
278void Linker::visit(Array& array, ValueVisitorArgs& a) {
279 Args& args = static_cast<Args&>(a);
280
281 for (auto& item : array.items) {
282 item->accept(*this, Args{ args.referrer, args.source });
283 }
284}
285
286void Linker::visit(Plural& plural, ValueVisitorArgs& a) {
287 Args& args = static_cast<Args&>(a);
288
289 for (auto& item : plural.values) {
290 if (item) {
291 item->accept(*this, Args{ args.referrer, args.source });
292 }
293 }
294}
295
296void Linker::addUnresolvedSymbol(const ResourceNameRef& name, const SourceLine& source) {
297 mUnresolvedSymbols[name.toResourceName()].push_back(source);
298}
299
300::std::ostream& operator<<(::std::ostream& out, const Linker::Node& node) {
301 return out << node.name << "(" << node.source << ":" << node.line << ")";
302}
303
304} // namespace aapt