SymbolTable.cpp revision e4bb9eb5af5b0899dc0921d5580220b20e15bd5a
1/* 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" 19#include "ValueVisitor.h" 20#include "process/SymbolTable.h" 21#include "util/Util.h" 22 23#include <androidfw/AssetManager.h> 24#include <androidfw/ResourceTypes.h> 25 26namespace aapt { 27 28const ISymbolTable::Symbol* SymbolTableWrapper::findByName(const ResourceName& name) { 29 if (const std::shared_ptr<Symbol>& s = mCache.get(name)) { 30 return s.get(); 31 } 32 33 Maybe<ResourceTable::SearchResult> result = mTable->findResource(name); 34 if (!result) { 35 if (name.type == ResourceType::kAttr) { 36 // Recurse and try looking up a private attribute. 37 return findByName(ResourceName(name.package, ResourceType::kAttrPrivate, name.entry)); 38 } 39 return {}; 40 } 41 42 ResourceTable::SearchResult sr = result.value(); 43 44 // If no ID exists, we treat the symbol as missing. SymbolTables are used to 45 // find symbols to link. 46 if (!sr.package->id || !sr.type->id || !sr.entry->id) { 47 return {}; 48 } 49 50 std::shared_ptr<Symbol> symbol = std::make_shared<Symbol>(); 51 symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value()); 52 symbol->isPublic = (sr.entry->symbolStatus.state == SymbolState::kPublic); 53 54 if (name.type == ResourceType::kAttr || name.type == ResourceType::kAttrPrivate) { 55 const ConfigDescription kDefaultConfig; 56 ResourceConfigValue* configValue = sr.entry->findValue(kDefaultConfig); 57 if (configValue) { 58 // This resource has an Attribute. 59 if (Attribute* attr = valueCast<Attribute>(configValue->value.get())) { 60 symbol->attribute = util::make_unique<Attribute>(*attr); 61 } else { 62 return {}; 63 } 64 } 65 } 66 67 if (name.type == ResourceType::kAttrPrivate) { 68 // Masquerade this entry as kAttr. 69 mCache.put(ResourceName(name.package, ResourceType::kAttr, name.entry), symbol); 70 } else { 71 mCache.put(name, symbol); 72 } 73 return symbol.get(); 74} 75 76static std::shared_ptr<ISymbolTable::Symbol> lookupAttributeInTable(const android::ResTable& table, 77 ResourceId id) { 78 // Try as a bag. 79 const android::ResTable::bag_entry* entry; 80 ssize_t count = table.lockBag(id.id, &entry); 81 if (count < 0) { 82 table.unlockBag(entry); 83 return nullptr; 84 } 85 86 // We found a resource. 87 std::shared_ptr<ISymbolTable::Symbol> s = std::make_shared<ISymbolTable::Symbol>(); 88 s->id = id; 89 90 // Check to see if it is an attribute. 91 for (size_t i = 0; i < (size_t) count; i++) { 92 if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) { 93 s->attribute = util::make_unique<Attribute>(false); 94 s->attribute->typeMask = entry[i].map.value.data; 95 break; 96 } 97 } 98 99 if (s->attribute) { 100 for (size_t i = 0; i < (size_t) count; i++) { 101 const android::ResTable_map& mapEntry = entry[i].map; 102 if (Res_INTERNALID(mapEntry.name.ident)) { 103 switch (mapEntry.name.ident) { 104 case android::ResTable_map::ATTR_MIN: 105 s->attribute->minInt = static_cast<int32_t>(mapEntry.value.data); 106 break; 107 case android::ResTable_map::ATTR_MAX: 108 s->attribute->maxInt = static_cast<int32_t>(mapEntry.value.data); 109 break; 110 } 111 continue; 112 } 113 114 android::ResTable::resource_name entryName; 115 if (!table.getResourceName(mapEntry.name.ident, false, &entryName)) { 116 table.unlockBag(entry); 117 return nullptr; 118 } 119 120 const ResourceType* parsedType = parseResourceType( 121 StringPiece16(entryName.type, entryName.typeLen)); 122 if (!parsedType) { 123 table.unlockBag(entry); 124 return nullptr; 125 } 126 127 Attribute::Symbol symbol; 128 symbol.symbol.name = ResourceName( 129 StringPiece16(entryName.package, entryName.packageLen), 130 *parsedType, 131 StringPiece16(entryName.name, entryName.nameLen)); 132 symbol.symbol.id = ResourceId(mapEntry.name.ident); 133 symbol.value = mapEntry.value.data; 134 s->attribute->symbols.push_back(std::move(symbol)); 135 } 136 } 137 table.unlockBag(entry); 138 return s; 139} 140 141const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findByName( 142 const ResourceName& name) { 143 if (const std::shared_ptr<Symbol>& s = mCache.get(name)) { 144 return s.get(); 145 } 146 147 for (const auto& asset : mAssets) { 148 const android::ResTable& table = asset->getResources(false); 149 StringPiece16 typeStr = toString(name.type); 150 uint32_t typeSpecFlags = 0; 151 ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(), 152 typeStr.data(), typeStr.size(), 153 name.package.data(), name.package.size(), 154 &typeSpecFlags); 155 if (!resId.isValid()) { 156 continue; 157 } 158 159 std::shared_ptr<Symbol> s; 160 if (name.type == ResourceType::kAttr) { 161 s = lookupAttributeInTable(table, resId); 162 } else { 163 s = std::make_shared<Symbol>(); 164 s->id = resId; 165 } 166 167 if (s) { 168 s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0; 169 mCache.put(name, s); 170 return s.get(); 171 } 172 } 173 return nullptr; 174} 175 176static Maybe<ResourceName> getResourceName(const android::ResTable& table, ResourceId id) { 177 android::ResTable::resource_name resName; 178 if (!table.getResourceName(id.id, true, &resName)) { 179 return {}; 180 } 181 182 ResourceName name; 183 if (resName.package) { 184 name.package = StringPiece16(resName.package, resName.packageLen).toString(); 185 } 186 187 const ResourceType* type; 188 if (resName.type) { 189 type = parseResourceType(StringPiece16(resName.type, resName.typeLen)); 190 191 } else if (resName.type8) { 192 type = parseResourceType(util::utf8ToUtf16(StringPiece(resName.type8, resName.typeLen))); 193 } else { 194 return {}; 195 } 196 197 if (!type) { 198 return {}; 199 } 200 201 name.type = *type; 202 203 if (resName.name) { 204 name.entry = StringPiece16(resName.name, resName.nameLen).toString(); 205 } else if (resName.name8) { 206 name.entry = util::utf8ToUtf16(StringPiece(resName.name8, resName.nameLen)); 207 } else { 208 return {}; 209 } 210 211 return name; 212} 213 214const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findById( 215 ResourceId id) { 216 if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) { 217 return s.get(); 218 } 219 220 for (const auto& asset : mAssets) { 221 const android::ResTable& table = asset->getResources(false); 222 223 Maybe<ResourceName> maybeName = getResourceName(table, id); 224 if (!maybeName) { 225 continue; 226 } 227 228 uint32_t typeSpecFlags = 0; 229 table.getResourceFlags(id.id, &typeSpecFlags); 230 231 std::shared_ptr<Symbol> s; 232 if (maybeName.value().type == ResourceType::kAttr) { 233 s = lookupAttributeInTable(table, id); 234 } else { 235 s = std::make_shared<Symbol>(); 236 s->id = id; 237 } 238 239 if (s) { 240 s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0; 241 mIdCache.put(id, s); 242 return s.get(); 243 } 244 } 245 return nullptr; 246} 247 248const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findByName( 249 const ResourceName& name) { 250 for (auto& symbolTable : mSymbolTables) { 251 if (const Symbol* s = symbolTable->findByName(name)) { 252 return s; 253 } 254 } 255 return {}; 256} 257 258const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findById(ResourceId id) { 259 for (auto& symbolTable : mSymbolTables) { 260 if (const Symbol* s = symbolTable->findById(id)) { 261 return s; 262 } 263 } 264 return {}; 265} 266 267} // namespace aapt 268