blob: 00ffeb25c3e168dac9d8666b1ea486d6e2361c07 [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
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
Adam Lesinskicacb28f2016-10-19 12:18:14 -070017#include "process/SymbolTable.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070018#include "ConfigDescription.h"
19#include "Resource.h"
Adam Lesinskid0f116b2016-07-08 15:00:32 -070020#include "ResourceUtils.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070021#include "ValueVisitor.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070022#include "util/Util.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070023
24#include <androidfw/AssetManager.h>
25#include <androidfw/ResourceTypes.h>
26
27namespace aapt {
28
Adam Lesinski64587af2016-02-18 18:33:06 -080029void SymbolTable::appendSource(std::unique_ptr<ISymbolSource> source) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070030 mSources.push_back(std::move(source));
Adam Lesinski64587af2016-02-18 18:33:06 -080031
Adam Lesinskicacb28f2016-10-19 12:18:14 -070032 // We do not clear the cache, because sources earlier in the list take
33 // precedent.
Adam Lesinski64587af2016-02-18 18:33:06 -080034}
35
36void SymbolTable::prependSource(std::unique_ptr<ISymbolSource> source) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070037 mSources.insert(mSources.begin(), std::move(source));
Adam Lesinski64587af2016-02-18 18:33:06 -080038
Adam Lesinskicacb28f2016-10-19 12:18:14 -070039 // We must clear the cache in case we did a lookup before adding this
40 // resource.
41 mCache.clear();
Adam Lesinski64587af2016-02-18 18:33:06 -080042}
43
44const SymbolTable::Symbol* SymbolTable::findByName(const ResourceName& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070045 if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
46 return s.get();
47 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070048
Adam Lesinskicacb28f2016-10-19 12:18:14 -070049 // We did not find it in the cache, so look through the sources.
50 for (auto& symbolSource : mSources) {
51 std::unique_ptr<Symbol> symbol = symbolSource->findByName(name);
52 if (symbol) {
53 // Take ownership of the symbol into a shared_ptr. We do this because
54 // LruCache
55 // doesn't support unique_ptr.
56 std::shared_ptr<Symbol> sharedSymbol =
57 std::shared_ptr<Symbol>(symbol.release());
58 mCache.put(name, sharedSymbol);
Adam Lesinski7656554f2016-03-10 21:55:04 -080059
Adam Lesinskicacb28f2016-10-19 12:18:14 -070060 if (sharedSymbol->id) {
61 // The symbol has an ID, so we can also cache this!
62 mIdCache.put(sharedSymbol->id.value(), sharedSymbol);
63 }
64 return sharedSymbol.get();
Adam Lesinski64587af2016-02-18 18:33:06 -080065 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -070066 }
67 return nullptr;
Adam Lesinski64587af2016-02-18 18:33:06 -080068}
69
Chih-Hung Hsieh9b8528f2016-08-10 14:15:30 -070070const SymbolTable::Symbol* SymbolTable::findById(const ResourceId& id) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070071 if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) {
72 return s.get();
73 }
Adam Lesinski64587af2016-02-18 18:33:06 -080074
Adam Lesinskicacb28f2016-10-19 12:18:14 -070075 // We did not find it in the cache, so look through the sources.
76 for (auto& symbolSource : mSources) {
77 std::unique_ptr<Symbol> symbol = symbolSource->findById(id);
78 if (symbol) {
79 // Take ownership of the symbol into a shared_ptr. We do this because
80 // LruCache
81 // doesn't support unique_ptr.
82 std::shared_ptr<Symbol> sharedSymbol =
83 std::shared_ptr<Symbol>(symbol.release());
84 mIdCache.put(id, sharedSymbol);
85 return sharedSymbol.get();
Adam Lesinski64587af2016-02-18 18:33:06 -080086 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -070087 }
88 return nullptr;
Adam Lesinski64587af2016-02-18 18:33:06 -080089}
90
Adam Lesinski7656554f2016-03-10 21:55:04 -080091const SymbolTable::Symbol* SymbolTable::findByReference(const Reference& ref) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070092 // First try the ID. This is because when we lookup by ID, we only fill in the
93 // ID cache.
94 // Looking up by name fills in the name and ID cache. So a cache miss will
95 // cause a failed
96 // ID lookup, then a successful name lookup. Subsequent look ups will hit
97 // immediately
98 // because the ID is cached too.
99 //
100 // If we looked up by name first, a cache miss would mean we failed to lookup
101 // by name, then
102 // succeeded to lookup by ID. Subsequent lookups will miss then hit.
103 const SymbolTable::Symbol* symbol = nullptr;
104 if (ref.id) {
105 symbol = findById(ref.id.value());
106 }
Adam Lesinski7656554f2016-03-10 21:55:04 -0800107
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700108 if (ref.name && !symbol) {
109 symbol = findByName(ref.name.value());
110 }
111 return symbol;
Adam Lesinski7656554f2016-03-10 21:55:04 -0800112}
113
Adam Lesinski64587af2016-02-18 18:33:06 -0800114std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::findByName(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700115 const ResourceName& name) {
116 Maybe<ResourceTable::SearchResult> result = mTable->findResource(name);
117 if (!result) {
118 if (name.type == ResourceType::kAttr) {
119 // Recurse and try looking up a private attribute.
120 return findByName(
121 ResourceName(name.package, ResourceType::kAttrPrivate, name.entry));
122 }
123 return {};
124 }
125
126 ResourceTable::SearchResult sr = result.value();
127
128 std::unique_ptr<SymbolTable::Symbol> symbol =
129 util::make_unique<SymbolTable::Symbol>();
130 symbol->isPublic = (sr.entry->symbolStatus.state == SymbolState::kPublic);
131
132 if (sr.package->id && sr.type->id && sr.entry->id) {
133 symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(),
134 sr.entry->id.value());
135 }
136
137 if (name.type == ResourceType::kAttr ||
138 name.type == ResourceType::kAttrPrivate) {
139 const ConfigDescription kDefaultConfig;
140 ResourceConfigValue* configValue = sr.entry->findValue(kDefaultConfig);
141 if (configValue) {
142 // This resource has an Attribute.
143 if (Attribute* attr = valueCast<Attribute>(configValue->value.get())) {
144 symbol->attribute = std::make_shared<Attribute>(*attr);
145 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700146 return {};
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700147 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700148 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700149 }
150 return symbol;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700151}
152
Adam Lesinski64587af2016-02-18 18:33:06 -0800153bool AssetManagerSymbolSource::addAssetPath(const StringPiece& path) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700154 int32_t cookie = 0;
155 return mAssets.addAssetPath(android::String8(path.data(), path.size()),
156 &cookie);
Adam Lesinski64587af2016-02-18 18:33:06 -0800157}
158
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700159static std::unique_ptr<SymbolTable::Symbol> lookupAttributeInTable(
160 const android::ResTable& table, ResourceId id) {
161 // Try as a bag.
162 const android::ResTable::bag_entry* entry;
163 ssize_t count = table.lockBag(id.id, &entry);
164 if (count < 0) {
165 table.unlockBag(entry);
166 return nullptr;
167 }
168
169 // We found a resource.
170 std::unique_ptr<SymbolTable::Symbol> s =
171 util::make_unique<SymbolTable::Symbol>();
172 s->id = id;
173
174 // Check to see if it is an attribute.
175 for (size_t i = 0; i < (size_t)count; i++) {
176 if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
177 s->attribute = std::make_shared<Attribute>(false);
178 s->attribute->typeMask = entry[i].map.value.data;
179 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700180 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700181 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700182
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183 if (s->attribute) {
184 for (size_t i = 0; i < (size_t)count; i++) {
185 const android::ResTable_map& mapEntry = entry[i].map;
186 if (Res_INTERNALID(mapEntry.name.ident)) {
187 switch (mapEntry.name.ident) {
188 case android::ResTable_map::ATTR_MIN:
189 s->attribute->minInt = static_cast<int32_t>(mapEntry.value.data);
190 break;
191 case android::ResTable_map::ATTR_MAX:
192 s->attribute->maxInt = static_cast<int32_t>(mapEntry.value.data);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700193 break;
194 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700195 continue;
196 }
197
198 android::ResTable::resource_name entryName;
199 if (!table.getResourceName(mapEntry.name.ident, false, &entryName)) {
200 table.unlockBag(entry);
201 return nullptr;
202 }
203
204 Maybe<ResourceName> parsedName = ResourceUtils::toResourceName(entryName);
205 if (!parsedName) {
206 return nullptr;
207 }
208
209 Attribute::Symbol symbol;
210 symbol.symbol.name = parsedName.value();
211 symbol.symbol.id = ResourceId(mapEntry.name.ident);
212 symbol.value = mapEntry.value.data;
213 s->attribute->symbols.push_back(std::move(symbol));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700214 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700215 }
216 table.unlockBag(entry);
217 return s;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700218}
219
Adam Lesinski64587af2016-02-18 18:33:06 -0800220std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findByName(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 const ResourceName& name) {
222 const android::ResTable& table = mAssets.getResources(false);
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700223
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700224 const std::u16string package16 = util::utf8ToUtf16(name.package);
225 const std::u16string type16 = util::utf8ToUtf16(toString(name.type));
226 const std::u16string entry16 = util::utf8ToUtf16(name.entry);
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700227
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700228 uint32_t typeSpecFlags = 0;
229 ResourceId resId = table.identifierForName(
230 entry16.data(), entry16.size(), type16.data(), type16.size(),
231 package16.data(), package16.size(), &typeSpecFlags);
232 if (!resId.isValid()) {
Adam Lesinski64587af2016-02-18 18:33:06 -0800233 return {};
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700234 }
235
236 std::unique_ptr<SymbolTable::Symbol> s;
237 if (name.type == ResourceType::kAttr) {
238 s = lookupAttributeInTable(table, resId);
239 } else {
240 s = util::make_unique<SymbolTable::Symbol>();
241 s->id = resId;
242 }
243
244 if (s) {
245 s->isPublic =
246 (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
247 return s;
248 }
249 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700250}
251
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700252static Maybe<ResourceName> getResourceName(const android::ResTable& table,
253 ResourceId id) {
254 android::ResTable::resource_name resName = {};
255 if (!table.getResourceName(id.id, true, &resName)) {
256 return {};
257 }
258 return ResourceUtils::toResourceName(resName);
Adam Lesinski467f1712015-11-16 17:35:44 -0800259}
260
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700261std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findById(
262 ResourceId id) {
263 const android::ResTable& table = mAssets.getResources(false);
264 Maybe<ResourceName> maybeName = getResourceName(table, id);
265 if (!maybeName) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700266 return {};
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700267 }
268
269 uint32_t typeSpecFlags = 0;
270 table.getResourceFlags(id.id, &typeSpecFlags);
271
272 std::unique_ptr<SymbolTable::Symbol> s;
273 if (maybeName.value().type == ResourceType::kAttr) {
274 s = lookupAttributeInTable(table, id);
275 } else {
276 s = util::make_unique<SymbolTable::Symbol>();
277 s->id = id;
278 }
279
280 if (s) {
281 s->isPublic =
282 (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
283 return s;
284 }
285 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700286}
287
Adam Lesinski7656554f2016-03-10 21:55:04 -0800288std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findByReference(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700289 const Reference& ref) {
290 // AssetManager always prefers IDs.
291 if (ref.id) {
292 return findById(ref.id.value());
293 } else if (ref.name) {
294 return findByName(ref.name.value());
295 }
296 return {};
Adam Lesinski7656554f2016-03-10 21:55:04 -0800297}
298
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700299} // namespace aapt