blob: d04181d583bceb64fcdfb5e74916545b03790dd4 [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
17#include "ConfigDescription.h"
18#include "Resource.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070019#include "ValueVisitor.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020
21#include "process/SymbolTable.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070022#include "util/Comparators.h"
23#include "util/Util.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070024
25#include <androidfw/AssetManager.h>
26#include <androidfw/ResourceTypes.h>
27
28namespace aapt {
29
30const ISymbolTable::Symbol* SymbolTableWrapper::findByName(const ResourceName& name) {
31 if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
32 return s.get();
33 }
34
35 Maybe<ResourceTable::SearchResult> result = mTable->findResource(name);
36 if (!result) {
37 if (name.type == ResourceType::kAttr) {
38 // Recurse and try looking up a private attribute.
Adam Lesinskie78fd612015-10-22 12:48:43 -070039 return findByName(ResourceName(name.package, ResourceType::kAttrPrivate, name.entry));
Adam Lesinski1ab598f2015-08-14 14:26:04 -070040 }
41 return {};
42 }
43
44 ResourceTable::SearchResult sr = result.value();
45
46 // If no ID exists, we treat the symbol as missing. SymbolTables are used to
47 // find symbols to link.
48 if (!sr.package->id || !sr.type->id || !sr.entry->id) {
49 return {};
50 }
51
52 std::shared_ptr<Symbol> symbol = std::make_shared<Symbol>();
Adam Lesinskie78fd612015-10-22 12:48:43 -070053 symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value());
Adam Lesinski467f1712015-11-16 17:35:44 -080054 symbol->isPublic = (sr.entry->symbolStatus.state == SymbolState::kPublic);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070055
56 if (name.type == ResourceType::kAttr || name.type == ResourceType::kAttrPrivate) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -070057 const ConfigDescription kDefaultConfig;
58 auto iter = std::lower_bound(sr.entry->values.begin(), sr.entry->values.end(),
Adam Lesinskib274e352015-11-06 15:14:35 -080059 kDefaultConfig, cmp::lessThanConfig);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070060
61 if (iter != sr.entry->values.end() && iter->config == kDefaultConfig) {
62 // This resource has an Attribute.
Adam Lesinskie78fd612015-10-22 12:48:43 -070063 if (Attribute* attr = valueCast<Attribute>(iter->value.get())) {
64 symbol->attribute = std::unique_ptr<Attribute>(attr->clone(nullptr));
65 } else {
66 return {};
67 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070068 }
69 }
70
71 if (name.type == ResourceType::kAttrPrivate) {
72 // Masquerade this entry as kAttr.
Adam Lesinskie78fd612015-10-22 12:48:43 -070073 mCache.put(ResourceName(name.package, ResourceType::kAttr, name.entry), symbol);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070074 } else {
75 mCache.put(name, symbol);
76 }
77 return symbol.get();
78}
79
80
Adam Lesinskie352b992015-11-16 11:59:14 -080081static std::shared_ptr<ISymbolTable::Symbol> lookupAttributeInTable(const android::ResTable& table,
82 ResourceId id) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -070083 // Try as a bag.
84 const android::ResTable::bag_entry* entry;
85 ssize_t count = table.lockBag(id.id, &entry);
86 if (count < 0) {
87 table.unlockBag(entry);
88 return nullptr;
89 }
90
91 // We found a resource.
92 std::shared_ptr<ISymbolTable::Symbol> s = std::make_shared<ISymbolTable::Symbol>();
93 s->id = id;
94
95 // Check to see if it is an attribute.
96 for (size_t i = 0; i < (size_t) count; i++) {
97 if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
98 s->attribute = util::make_unique<Attribute>(false);
99 s->attribute->typeMask = entry[i].map.value.data;
100 break;
101 }
102 }
103
104 if (s->attribute) {
105 for (size_t i = 0; i < (size_t) count; i++) {
106 if (!Res_INTERNALID(entry[i].map.name.ident)) {
107 android::ResTable::resource_name entryName;
108 if (!table.getResourceName(entry[i].map.name.ident, false, &entryName)) {
109 table.unlockBag(entry);
110 return nullptr;
111 }
112
113 const ResourceType* parsedType = parseResourceType(
114 StringPiece16(entryName.type, entryName.typeLen));
115 if (!parsedType) {
116 table.unlockBag(entry);
117 return nullptr;
118 }
119
120 Attribute::Symbol symbol;
121 symbol.symbol.name = ResourceNameRef(
122 StringPiece16(entryName.package, entryName.packageLen),
123 *parsedType,
124 StringPiece16(entryName.name, entryName.nameLen)).toResourceName();
125 symbol.symbol.id = ResourceId(entry[i].map.name.ident);
126 symbol.value = entry[i].map.value.data;
127 s->attribute->symbols.push_back(std::move(symbol));
128 }
129 }
130 }
131 table.unlockBag(entry);
132 return s;
133}
134
135const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findByName(
136 const ResourceName& name) {
137 if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
138 return s.get();
139 }
140
141 for (const auto& asset : mAssets) {
142 const android::ResTable& table = asset->getResources(false);
143 StringPiece16 typeStr = toString(name.type);
Adam Lesinskie352b992015-11-16 11:59:14 -0800144 uint32_t typeSpecFlags = 0;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700145 ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(),
146 typeStr.data(), typeStr.size(),
Adam Lesinskie352b992015-11-16 11:59:14 -0800147 name.package.data(), name.package.size(),
148 &typeSpecFlags);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700149 if (!resId.isValid()) {
150 continue;
151 }
152
Adam Lesinskie352b992015-11-16 11:59:14 -0800153 std::shared_ptr<Symbol> s;
154 if (name.type == ResourceType::kAttr) {
155 s = lookupAttributeInTable(table, resId);
156 } else {
157 s = std::make_shared<Symbol>();
158 s->id = resId;
159 }
160
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700161 if (s) {
Adam Lesinski467f1712015-11-16 17:35:44 -0800162 s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700163 mCache.put(name, s);
164 return s.get();
165 }
166 }
167 return nullptr;
168}
169
Adam Lesinski467f1712015-11-16 17:35:44 -0800170static Maybe<ResourceName> getResourceName(const android::ResTable& table, ResourceId id) {
171 android::ResTable::resource_name resName;
172 if (!table.getResourceName(id.id, true, &resName)) {
173 return {};
174 }
175
176 ResourceName name;
177 if (resName.package) {
178 name.package = StringPiece16(resName.package, resName.packageLen).toString();
179 }
180
181 const ResourceType* type;
182 if (resName.type) {
183 type = parseResourceType(StringPiece16(resName.type, resName.typeLen));
184
185 } else if (resName.type8) {
186 type = parseResourceType(util::utf8ToUtf16(StringPiece(resName.type8, resName.typeLen)));
187 } else {
188 return {};
189 }
190
191 if (!type) {
192 return {};
193 }
194
195 name.type = *type;
196
197 if (resName.name) {
198 name.entry = StringPiece16(resName.name, resName.nameLen).toString();
199 } else if (resName.name8) {
200 name.entry = util::utf8ToUtf16(StringPiece(resName.name8, resName.nameLen));
201 } else {
202 return {};
203 }
204
205 return name;
206}
207
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700208const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findById(
209 ResourceId id) {
210 if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) {
211 return s.get();
212 }
213
214 for (const auto& asset : mAssets) {
215 const android::ResTable& table = asset->getResources(false);
216
Adam Lesinski467f1712015-11-16 17:35:44 -0800217 Maybe<ResourceName> maybeName = getResourceName(table, id);
218 if (!maybeName) {
Adam Lesinskie352b992015-11-16 11:59:14 -0800219 continue;
220 }
221
Adam Lesinski467f1712015-11-16 17:35:44 -0800222 uint32_t typeSpecFlags = 0;
223 table.getResourceFlags(id.id, &typeSpecFlags);
Adam Lesinskie352b992015-11-16 11:59:14 -0800224
225 std::shared_ptr<Symbol> s;
Adam Lesinski467f1712015-11-16 17:35:44 -0800226 if (maybeName.value().type == ResourceType::kAttr) {
Adam Lesinskie352b992015-11-16 11:59:14 -0800227 s = lookupAttributeInTable(table, id);
228 } else {
229 s = std::make_shared<Symbol>();
230 s->id = id;
231 }
232
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700233 if (s) {
Adam Lesinski467f1712015-11-16 17:35:44 -0800234 s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700235 mIdCache.put(id, s);
236 return s.get();
237 }
238 }
239 return nullptr;
240}
241
242const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findByName(
243 const ResourceName& name) {
244 for (auto& symbolTable : mSymbolTables) {
245 if (const Symbol* s = symbolTable->findByName(name)) {
246 return s;
247 }
248 }
249 return {};
250}
251
252const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findById(ResourceId id) {
253 for (auto& symbolTable : mSymbolTables) {
254 if (const Symbol* s = symbolTable->findById(id)) {
255 return s;
256 }
257 }
258 return {};
259}
260
261} // namespace aapt