blob: 767384d8d9562bc7e759a3aee6b0075acadc947d [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 Lesinskice5e56e2016-10-21 17:56:45 -070018
19#include "androidfw/AssetManager.h"
20#include "androidfw/ResourceTypes.h"
21
Adam Lesinski1ab598f2015-08-14 14:26:04 -070022#include "ConfigDescription.h"
23#include "Resource.h"
Adam Lesinskid0f116b2016-07-08 15:00:32 -070024#include "ResourceUtils.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070025#include "ValueVisitor.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070026#include "util/Util.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070027
Adam Lesinski1ab598f2015-08-14 14:26:04 -070028namespace aapt {
29
Adam Lesinskice5e56e2016-10-21 17:56:45 -070030void SymbolTable::AppendSource(std::unique_ptr<ISymbolSource> source) {
31 sources_.push_back(std::move(source));
Adam Lesinski64587af2016-02-18 18:33:06 -080032
Adam Lesinskicacb28f2016-10-19 12:18:14 -070033 // We do not clear the cache, because sources earlier in the list take
34 // precedent.
Adam Lesinski64587af2016-02-18 18:33:06 -080035}
36
Adam Lesinskice5e56e2016-10-21 17:56:45 -070037void SymbolTable::PrependSource(std::unique_ptr<ISymbolSource> source) {
38 sources_.insert(sources_.begin(), std::move(source));
Adam Lesinski64587af2016-02-18 18:33:06 -080039
Adam Lesinskicacb28f2016-10-19 12:18:14 -070040 // We must clear the cache in case we did a lookup before adding this
41 // resource.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070042 cache_.clear();
Adam Lesinski64587af2016-02-18 18:33:06 -080043}
44
Adam Lesinskice5e56e2016-10-21 17:56:45 -070045const SymbolTable::Symbol* SymbolTable::FindByName(const ResourceName& name) {
46 if (const std::shared_ptr<Symbol>& s = cache_.get(name)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070047 return s.get();
48 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070049
Adam Lesinskicacb28f2016-10-19 12:18:14 -070050 // We did not find it in the cache, so look through the sources.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070051 for (auto& symbolSource : sources_) {
52 std::unique_ptr<Symbol> symbol = symbolSource->FindByName(name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070053 if (symbol) {
54 // Take ownership of the symbol into a shared_ptr. We do this because
55 // LruCache
56 // doesn't support unique_ptr.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070057 std::shared_ptr<Symbol> shared_symbol =
Adam Lesinskicacb28f2016-10-19 12:18:14 -070058 std::shared_ptr<Symbol>(symbol.release());
Adam Lesinskice5e56e2016-10-21 17:56:45 -070059 cache_.put(name, shared_symbol);
Adam Lesinski7656554f2016-03-10 21:55:04 -080060
Adam Lesinskice5e56e2016-10-21 17:56:45 -070061 if (shared_symbol->id) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070062 // The symbol has an ID, so we can also cache this!
Adam Lesinskice5e56e2016-10-21 17:56:45 -070063 id_cache_.put(shared_symbol->id.value(), shared_symbol);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070064 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070065 return shared_symbol.get();
Adam Lesinski64587af2016-02-18 18:33:06 -080066 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -070067 }
68 return nullptr;
Adam Lesinski64587af2016-02-18 18:33:06 -080069}
70
Adam Lesinskice5e56e2016-10-21 17:56:45 -070071const SymbolTable::Symbol* SymbolTable::FindById(const ResourceId& id) {
72 if (const std::shared_ptr<Symbol>& s = id_cache_.get(id)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073 return s.get();
74 }
Adam Lesinski64587af2016-02-18 18:33:06 -080075
Adam Lesinskicacb28f2016-10-19 12:18:14 -070076 // We did not find it in the cache, so look through the sources.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070077 for (auto& symbolSource : sources_) {
78 std::unique_ptr<Symbol> symbol = symbolSource->FindById(id);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070079 if (symbol) {
80 // Take ownership of the symbol into a shared_ptr. We do this because
81 // LruCache
82 // doesn't support unique_ptr.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070083 std::shared_ptr<Symbol> shared_symbol =
Adam Lesinskicacb28f2016-10-19 12:18:14 -070084 std::shared_ptr<Symbol>(symbol.release());
Adam Lesinskice5e56e2016-10-21 17:56:45 -070085 id_cache_.put(id, shared_symbol);
86 return shared_symbol.get();
Adam Lesinski64587af2016-02-18 18:33:06 -080087 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -070088 }
89 return nullptr;
Adam Lesinski64587af2016-02-18 18:33:06 -080090}
91
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092const SymbolTable::Symbol* SymbolTable::FindByReference(const Reference& ref) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070093 // First try the ID. This is because when we lookup by ID, we only fill in the
94 // ID cache.
95 // Looking up by name fills in the name and ID cache. So a cache miss will
96 // cause a failed
97 // ID lookup, then a successful name lookup. Subsequent look ups will hit
98 // immediately
99 // because the ID is cached too.
100 //
101 // If we looked up by name first, a cache miss would mean we failed to lookup
102 // by name, then
103 // succeeded to lookup by ID. Subsequent lookups will miss then hit.
104 const SymbolTable::Symbol* symbol = nullptr;
105 if (ref.id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700106 symbol = FindById(ref.id.value());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700107 }
Adam Lesinski7656554f2016-03-10 21:55:04 -0800108
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700109 if (ref.name && !symbol) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700110 symbol = FindByName(ref.name.value());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700111 }
112 return symbol;
Adam Lesinski7656554f2016-03-10 21:55:04 -0800113}
114
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700115std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::FindByName(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700116 const ResourceName& name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700117 Maybe<ResourceTable::SearchResult> result = table_->FindResource(name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700118 if (!result) {
119 if (name.type == ResourceType::kAttr) {
120 // Recurse and try looking up a private attribute.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700121 return FindByName(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700122 ResourceName(name.package, ResourceType::kAttrPrivate, name.entry));
123 }
124 return {};
125 }
126
127 ResourceTable::SearchResult sr = result.value();
128
129 std::unique_ptr<SymbolTable::Symbol> symbol =
130 util::make_unique<SymbolTable::Symbol>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700131 symbol->is_public = (sr.entry->symbol_status.state == SymbolState::kPublic);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700132
133 if (sr.package->id && sr.type->id && sr.entry->id) {
134 symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(),
135 sr.entry->id.value());
136 }
137
138 if (name.type == ResourceType::kAttr ||
139 name.type == ResourceType::kAttrPrivate) {
140 const ConfigDescription kDefaultConfig;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700141 ResourceConfigValue* config_value = sr.entry->FindValue(kDefaultConfig);
142 if (config_value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700143 // This resource has an Attribute.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700144 if (Attribute* attr = ValueCast<Attribute>(config_value->value.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700145 symbol->attribute = std::make_shared<Attribute>(*attr);
146 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700147 return {};
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700148 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700149 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700150 }
151 return symbol;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700152}
153
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700155 int32_t cookie = 0;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156 return assets_.addAssetPath(android::String8(path.data(), path.size()),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700157 &cookie);
Adam Lesinski64587af2016-02-18 18:33:06 -0800158}
159
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700160static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700161 const android::ResTable& table, ResourceId id) {
162 // Try as a bag.
163 const android::ResTable::bag_entry* entry;
164 ssize_t count = table.lockBag(id.id, &entry);
165 if (count < 0) {
166 table.unlockBag(entry);
167 return nullptr;
168 }
169
170 // We found a resource.
171 std::unique_ptr<SymbolTable::Symbol> s =
172 util::make_unique<SymbolTable::Symbol>();
173 s->id = id;
174
175 // Check to see if it is an attribute.
176 for (size_t i = 0; i < (size_t)count; i++) {
177 if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
178 s->attribute = std::make_shared<Attribute>(false);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700179 s->attribute->type_mask = entry[i].map.value.data;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700180 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700181 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700182 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700183
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700184 if (s->attribute) {
185 for (size_t i = 0; i < (size_t)count; i++) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700186 const android::ResTable_map& map_entry = entry[i].map;
187 if (Res_INTERNALID(map_entry.name.ident)) {
188 switch (map_entry.name.ident) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700189 case android::ResTable_map::ATTR_MIN:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700190 s->attribute->min_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700191 break;
192 case android::ResTable_map::ATTR_MAX:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700193 s->attribute->max_int = static_cast<int32_t>(map_entry.value.data);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700194 break;
195 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700196 continue;
197 }
198
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700199 android::ResTable::resource_name entry_name;
200 if (!table.getResourceName(map_entry.name.ident, false, &entry_name)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700201 table.unlockBag(entry);
202 return nullptr;
203 }
204
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700205 Maybe<ResourceName> parsed_name =
206 ResourceUtils::ToResourceName(entry_name);
207 if (!parsed_name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700208 return nullptr;
209 }
210
211 Attribute::Symbol symbol;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700212 symbol.symbol.name = parsed_name.value();
213 symbol.symbol.id = ResourceId(map_entry.name.ident);
214 symbol.value = map_entry.value.data;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700215 s->attribute->symbols.push_back(std::move(symbol));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700216 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700217 }
218 table.unlockBag(entry);
219 return s;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700220}
221
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700222std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700223 const ResourceName& name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700224 const android::ResTable& table = assets_.getResources(false);
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700225
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700226 const std::u16string package16 = util::Utf8ToUtf16(name.package);
227 const std::u16string type16 = util::Utf8ToUtf16(ToString(name.type));
228 const std::u16string entry16 = util::Utf8ToUtf16(name.entry);
Adam Lesinskid0f116b2016-07-08 15:00:32 -0700229
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700230 uint32_t type_spec_flags = 0;
231 ResourceId res_id = table.identifierForName(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700232 entry16.data(), entry16.size(), type16.data(), type16.size(),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700233 package16.data(), package16.size(), &type_spec_flags);
234 if (!res_id.is_valid()) {
Adam Lesinski64587af2016-02-18 18:33:06 -0800235 return {};
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700236 }
237
238 std::unique_ptr<SymbolTable::Symbol> s;
239 if (name.type == ResourceType::kAttr) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700240 s = LookupAttributeInTable(table, res_id);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700241 } else {
242 s = util::make_unique<SymbolTable::Symbol>();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700243 s->id = res_id;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700244 }
245
246 if (s) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700247 s->is_public =
248 (type_spec_flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700249 return s;
250 }
251 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700252}
253
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700254static Maybe<ResourceName> GetResourceName(const android::ResTable& table,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700255 ResourceId id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700256 android::ResTable::resource_name res_name = {};
257 if (!table.getResourceName(id.id, true, &res_name)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700258 return {};
259 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700260 return ResourceUtils::ToResourceName(res_name);
Adam Lesinski467f1712015-11-16 17:35:44 -0800261}
262
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700263std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700264 ResourceId id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700265 const android::ResTable& table = assets_.getResources(false);
266 Maybe<ResourceName> maybe_name = GetResourceName(table, id);
267 if (!maybe_name) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700268 return {};
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700269 }
270
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700271 uint32_t type_spec_flags = 0;
272 table.getResourceFlags(id.id, &type_spec_flags);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700273
274 std::unique_ptr<SymbolTable::Symbol> s;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700275 if (maybe_name.value().type == ResourceType::kAttr) {
276 s = LookupAttributeInTable(table, id);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700277 } else {
278 s = util::make_unique<SymbolTable::Symbol>();
279 s->id = id;
280 }
281
282 if (s) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700283 s->is_public =
284 (type_spec_flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700285 return s;
286 }
287 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700288}
289
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700290std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByReference(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700291 const Reference& ref) {
292 // AssetManager always prefers IDs.
293 if (ref.id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700294 return FindById(ref.id.value());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700295 } else if (ref.name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700296 return FindByName(ref.name.value());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700297 }
298 return {};
Adam Lesinski7656554f2016-03-10 21:55:04 -0800299}
300
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700301} // namespace aapt