16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/* 26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License. 66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at 76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software 116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and 146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License. 156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Maybe.h" 18769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include "NameMangler.h" 196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Resource.h" 206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceTable.h" 2124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski#include "ResourceTableResolver.h" 226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceValues.h" 236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Util.h" 246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <androidfw/AssetManager.h> 266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <androidfw/ResourceTypes.h> 276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <memory> 286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <vector> 296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt { 316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3224aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiResourceTableResolver::ResourceTableResolver( 3324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::shared_ptr<const ResourceTable> table, 34330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski const std::vector<std::shared_ptr<const android::AssetManager>>& sources) : 356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mTable(table), mSources(sources) { 36330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski for (const auto& assetManager : mSources) { 37330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski const android::ResTable& resTable = assetManager->getResources(false); 38330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski const size_t packageCount = resTable.getBasePackageCount(); 39330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski for (size_t i = 0; i < packageCount; i++) { 40330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski std::u16string packageName = resTable.getBasePackageName(i).string(); 41330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski mIncludedPackages.insert(std::move(packageName)); 42330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski } 43769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski } 446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4624aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiMaybe<ResourceId> ResourceTableResolver::findId(const ResourceName& name) { 476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski Maybe<Entry> result = findAttribute(name); 486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (result) { 496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return result.value().id; 506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return {}; 526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 5424aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiMaybe<IResolver::Entry> ResourceTableResolver::findAttribute(const ResourceName& name) { 556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski auto cacheIter = mCache.find(name); 566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (cacheIter != std::end(mCache)) { 576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return Entry{ cacheIter->second.id, cacheIter->second.attr.get() }; 586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 60769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski ResourceName mangledName; 61769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski const ResourceName* nameToSearch = &name; 62769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski if (name.package != mTable->getPackage()) { 63769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski // This may be a reference to an included resource or 64769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski // to a mangled resource. 65769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski if (mIncludedPackages.find(name.package) == mIncludedPackages.end()) { 66769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski // This is not in our included set, so mangle the name and 67769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski // check for that. 68769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski mangledName.entry = name.entry; 69769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski NameMangler::mangle(name.package, &mangledName.entry); 70769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski mangledName.package = mTable->getPackage(); 71769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski mangledName.type = name.type; 72769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski nameToSearch = &mangledName; 73769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski } else { 74769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski const CacheEntry* cacheEntry = buildCacheEntry(name); 75769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski if (cacheEntry) { 76769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski return Entry{ cacheEntry->id, cacheEntry->attr.get() }; 77769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski } 78769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski return {}; 79769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski } 80769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski } 81769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const ResourceTableType* type; 836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const ResourceEntry* entry; 84769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski std::tie(type, entry) = mTable->findResource(*nameToSearch); 856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (type && entry) { 866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski Entry result = {}; 876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (mTable->getPackageId() != ResourceTable::kUnsetPackageId && 886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski type->typeId != ResourceTableType::kUnsetTypeId && 896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski entry->entryId != ResourceEntry::kUnsetEntryId) { 906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski result.id = ResourceId(mTable->getPackageId(), type->typeId, entry->entryId); 916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!entry->values.empty()) { 946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski visitFunc<Attribute>(*entry->values.front().value, [&result](Attribute& attr) { 956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski result.attr = &attr; 966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski }); 976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return result; 996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return {}; 1016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 10324aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiMaybe<ResourceName> ResourceTableResolver::findName(ResourceId resId) { 104330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski for (const auto& assetManager : mSources) { 105330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski const android::ResTable& table = assetManager->getResources(false); 10624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 107330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski android::ResTable::resource_name resourceName; 108330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski if (!table.getResourceName(resId.id, false, &resourceName)) { 109330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski continue; 110330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski } 11124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 112330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski const ResourceType* type = parseResourceType(StringPiece16(resourceName.type, 113330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski resourceName.typeLen)); 114330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski assert(type); 115330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski return ResourceName{ 116330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski { resourceName.package, resourceName.packageLen }, 117330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski *type, 118330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski { resourceName.name, resourceName.nameLen } }; 119330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski } 120330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski return {}; 12124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski} 12224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 1236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/** 1246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * This is called when we need to lookup a resource name in the AssetManager. 1256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Since the values in the AssetManager are not parsed like in a ResourceTable, 1266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * we must create Attribute objects here if we find them. 1276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 12824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinskiconst ResourceTableResolver::CacheEntry* ResourceTableResolver::buildCacheEntry( 12924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski const ResourceName& name) { 130330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski for (const auto& assetManager : mSources) { 131330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski const android::ResTable& table = assetManager->getResources(false); 132330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski 133330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski const StringPiece16 type16 = toString(name.type); 134330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski ResourceId resId { 135330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski table.identifierForName( 136330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski name.entry.data(), name.entry.size(), 137330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski type16.data(), type16.size(), 138330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski name.package.data(), name.package.size()) 139330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski }; 140330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski 141330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski if (!resId.isValid()) { 142330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski continue; 143330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski } 1446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 145330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski CacheEntry& entry = mCache[name]; 146330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski entry.id = resId; 1476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 148330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski // 149330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski // Now check to see if this resource is an Attribute. 150330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski // 1516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 152330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski const android::ResTable::bag_entry* bagBegin; 153330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski ssize_t bags = table.lockBag(resId.id, &bagBegin); 154330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski if (bags < 1) { 155330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski table.unlockBag(bagBegin); 156330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski return &entry; 1576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 159330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski // Look for the ATTR_TYPE key in the bag and check the types it supports. 160330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski uint32_t attrTypeMask = 0; 1616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (ssize_t i = 0; i < bags; i++) { 162330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski if (bagBegin[i].map.name.ident == android::ResTable_map::ATTR_TYPE) { 163330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski attrTypeMask = bagBegin[i].map.value.data; 1646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 165330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski } 1666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 167330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski entry.attr = util::make_unique<Attribute>(false); 168330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski 169330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski if (attrTypeMask & android::ResTable_map::TYPE_ENUM || 170330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski attrTypeMask & android::ResTable_map::TYPE_FLAGS) { 171330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski for (ssize_t i = 0; i < bags; i++) { 172330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski if (Res_INTERNALID(bagBegin[i].map.name.ident)) { 173330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski // Internal IDs are special keys, which are not enum/flag symbols, so skip. 174330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski continue; 175330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski } 176330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski 177330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski android::ResTable::resource_name symbolName; 178330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski bool result = table.getResourceName(bagBegin[i].map.name.ident, false, 179330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski &symbolName); 180330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski assert(result); 181330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski const ResourceType* type = parseResourceType( 182330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski StringPiece16(symbolName.type, symbolName.typeLen)); 183330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski assert(type); 184330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski 185330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski entry.attr->symbols.push_back(Attribute::Symbol{ 186330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski Reference(ResourceNameRef( 187330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski StringPiece16(symbolName.package, symbolName.packageLen), 188330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski *type, 189330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski StringPiece16(symbolName.name, symbolName.nameLen))), 190330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski bagBegin[i].map.value.data 191330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski }); 192330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski } 1936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 195330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski entry.attr->typeMask |= attrTypeMask; 196330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski table.unlockBag(bagBegin); 197330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski return &entry; 198330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski } 199330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski return nullptr; 2006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace aapt 203