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 "Linker.h" 18 #include "Logger.h" 19 #include "NameMangler.h" 20 #include "Resolver.h" 21 #include "ResourceParser.h" 22 #include "ResourceTable.h" 23 #include "ResourceValues.h" 24 #include "StringPiece.h" 25 #include "Util.h" 26 27 #include <androidfw/AssetManager.h> 28 #include <array> 29 #include <bitset> 30 #include <iostream> 31 #include <map> 32 #include <ostream> 33 #include <set> 34 #include <sstream> 35 #include <tuple> 36 #include <vector> 37 38 namespace aapt { 39 Args(const ResourceNameRef & r,const SourceLine & s)40 Linker::Args::Args(const ResourceNameRef& r, const SourceLine& s) : referrer(r), source(s) { 41 } 42 Linker(const std::shared_ptr<ResourceTable> & table,const std::shared_ptr<IResolver> & resolver,const Options & options)43 Linker::Linker(const std::shared_ptr<ResourceTable>& table, 44 const std::shared_ptr<IResolver>& resolver, const Options& options) : 45 mResolver(resolver), mTable(table), mOptions(options), mError(false) { 46 } 47 linkAndValidate()48 bool Linker::linkAndValidate() { 49 std::bitset<256> usedTypeIds; 50 std::array<std::set<uint16_t>, 256> usedIds; 51 usedTypeIds.set(0); 52 53 // Collect which resource IDs are already taken. 54 for (auto& type : *mTable) { 55 if (type->typeId != ResourceTableType::kUnsetTypeId) { 56 // The ID for this type has already been set. We 57 // mark this ID as taken so we don't re-assign it 58 // later. 59 usedTypeIds.set(type->typeId); 60 } 61 62 for (auto& entry : type->entries) { 63 if (type->typeId != ResourceTableType::kUnsetTypeId && 64 entry->entryId != ResourceEntry::kUnsetEntryId) { 65 // The ID for this entry has already been set. We 66 // mark this ID as taken so we don't re-assign it 67 // later. 68 usedIds[type->typeId].insert(entry->entryId); 69 } 70 } 71 } 72 73 // Assign resource IDs that are available. 74 size_t nextTypeIndex = 0; 75 for (auto& type : *mTable) { 76 if (type->typeId == ResourceTableType::kUnsetTypeId) { 77 while (nextTypeIndex < usedTypeIds.size() && usedTypeIds[nextTypeIndex]) { 78 nextTypeIndex++; 79 } 80 type->typeId = nextTypeIndex++; 81 } 82 83 const auto endEntryIter = std::end(usedIds[type->typeId]); 84 auto nextEntryIter = std::begin(usedIds[type->typeId]); 85 size_t nextIndex = 0; 86 for (auto& entry : type->entries) { 87 if (entry->entryId == ResourceTableType::kUnsetTypeId) { 88 while (nextEntryIter != endEntryIter && 89 nextIndex == *nextEntryIter) { 90 nextIndex++; 91 ++nextEntryIter; 92 } 93 entry->entryId = nextIndex++; 94 } 95 } 96 } 97 98 // Now do reference linking. 99 for (auto& type : *mTable) { 100 for (auto& entry : type->entries) { 101 if (entry->publicStatus.isPublic && entry->values.empty()) { 102 // A public resource has no values. It will not be encoded 103 // properly without a symbol table. This is a unresolved symbol. 104 addUnresolvedSymbol(ResourceNameRef{ 105 mTable->getPackage(), type->type, entry->name }, 106 entry->publicStatus.source); 107 continue; 108 } 109 110 for (auto& valueConfig : entry->values) { 111 // Dispatch to the right method of this linker 112 // based on the value's type. 113 valueConfig.value->accept(*this, Args{ 114 ResourceNameRef{ mTable->getPackage(), type->type, entry->name }, 115 valueConfig.source 116 }); 117 } 118 } 119 } 120 return !mError; 121 } 122 getUnresolvedReferences() const123 const Linker::ResourceNameToSourceMap& Linker::getUnresolvedReferences() const { 124 return mUnresolvedSymbols; 125 } 126 doResolveReference(Reference & reference,const SourceLine & source)127 void Linker::doResolveReference(Reference& reference, const SourceLine& source) { 128 Maybe<ResourceId> result = mResolver->findId(reference.name); 129 if (!result) { 130 addUnresolvedSymbol(reference.name, source); 131 return; 132 } 133 assert(result.value().isValid()); 134 135 if (mOptions.linkResourceIds) { 136 reference.id = result.value(); 137 } else { 138 reference.id = 0; 139 } 140 } 141 doResolveAttribute(Reference & attribute,const SourceLine & source)142 const Attribute* Linker::doResolveAttribute(Reference& attribute, const SourceLine& source) { 143 Maybe<IResolver::Entry> result = mResolver->findAttribute(attribute.name); 144 if (!result || !result.value().attr) { 145 addUnresolvedSymbol(attribute.name, source); 146 return nullptr; 147 } 148 149 const IResolver::Entry& entry = result.value(); 150 assert(entry.id.isValid()); 151 152 if (mOptions.linkResourceIds) { 153 attribute.id = entry.id; 154 } else { 155 attribute.id = 0; 156 } 157 return entry.attr; 158 } 159 visit(Reference & reference,ValueVisitorArgs & a)160 void Linker::visit(Reference& reference, ValueVisitorArgs& a) { 161 Args& args = static_cast<Args&>(a); 162 163 if (reference.name.entry.empty()) { 164 // We can't have a completely bad reference. 165 if (!reference.id.isValid()) { 166 Logger::error() << "srsly? " << args.referrer << std::endl; 167 assert(reference.id.isValid()); 168 } 169 170 // This reference has no name but has an ID. 171 // It is a really bad error to have no name and have the same 172 // package ID. 173 assert(reference.id.packageId() != mTable->getPackageId()); 174 175 // The reference goes outside this package, let it stay as a 176 // resource ID because it will not change. 177 return; 178 } 179 180 doResolveReference(reference, args.source); 181 182 // TODO(adamlesinski): Verify the referencedType is another reference 183 // or a compatible primitive. 184 } 185 processAttributeValue(const ResourceNameRef & name,const SourceLine & source,const Attribute & attr,std::unique_ptr<Item> & value)186 void Linker::processAttributeValue(const ResourceNameRef& name, const SourceLine& source, 187 const Attribute& attr, std::unique_ptr<Item>& value) { 188 std::unique_ptr<Item> convertedValue; 189 visitFunc<RawString>(*value, [&](RawString& str) { 190 // This is a raw string, so check if it can be converted to anything. 191 // We can NOT swap value with the converted value in here, since 192 // we called through the original value. 193 194 auto onCreateReference = [&](const ResourceName& name) { 195 // We should never get here. All references would have been 196 // parsed in the parser phase. 197 assert(false); 198 }; 199 200 convertedValue = ResourceParser::parseItemForAttribute(*str.value, attr, 201 onCreateReference); 202 if (!convertedValue && attr.typeMask & android::ResTable_map::TYPE_STRING) { 203 // Last effort is to parse as a string. 204 util::StringBuilder builder; 205 builder.append(*str.value); 206 if (builder) { 207 convertedValue = util::make_unique<String>( 208 mTable->getValueStringPool().makeRef(builder.str())); 209 } 210 } 211 }); 212 213 if (convertedValue) { 214 value = std::move(convertedValue); 215 } 216 217 // Process this new or old value (it can be a reference!). 218 value->accept(*this, Args{ name, source }); 219 220 // Flatten the value to see what resource type it is. 221 android::Res_value resValue; 222 value->flatten(resValue); 223 224 // Always allow references. 225 const uint32_t typeMask = attr.typeMask | android::ResTable_map::TYPE_REFERENCE; 226 if (!(typeMask & ResourceParser::androidTypeToAttributeTypeMask(resValue.dataType))) { 227 Logger::error(source) 228 << *value 229 << " is not compatible with attribute " 230 << attr 231 << "." 232 << std::endl; 233 mError = true; 234 } 235 } 236 visit(Style & style,ValueVisitorArgs & a)237 void Linker::visit(Style& style, ValueVisitorArgs& a) { 238 Args& args = static_cast<Args&>(a); 239 240 if (style.parent.name.isValid() || style.parent.id.isValid()) { 241 visit(style.parent, a); 242 } 243 244 for (Style::Entry& styleEntry : style.entries) { 245 const Attribute* attr = doResolveAttribute(styleEntry.key, args.source); 246 if (attr) { 247 processAttributeValue(args.referrer, args.source, *attr, styleEntry.value); 248 } 249 } 250 } 251 visit(Attribute & attr,ValueVisitorArgs & a)252 void Linker::visit(Attribute& attr, ValueVisitorArgs& a) { 253 static constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | 254 android::ResTable_map::TYPE_FLAGS; 255 if (attr.typeMask & kMask) { 256 for (auto& symbol : attr.symbols) { 257 visit(symbol.symbol, a); 258 } 259 } 260 } 261 visit(Styleable & styleable,ValueVisitorArgs & a)262 void Linker::visit(Styleable& styleable, ValueVisitorArgs& a) { 263 for (auto& attrRef : styleable.entries) { 264 visit(attrRef, a); 265 } 266 } 267 visit(Array & array,ValueVisitorArgs & a)268 void Linker::visit(Array& array, ValueVisitorArgs& a) { 269 Args& args = static_cast<Args&>(a); 270 271 for (auto& item : array.items) { 272 item->accept(*this, Args{ args.referrer, args.source }); 273 } 274 } 275 visit(Plural & plural,ValueVisitorArgs & a)276 void Linker::visit(Plural& plural, ValueVisitorArgs& a) { 277 Args& args = static_cast<Args&>(a); 278 279 for (auto& item : plural.values) { 280 if (item) { 281 item->accept(*this, Args{ args.referrer, args.source }); 282 } 283 } 284 } 285 addUnresolvedSymbol(const ResourceNameRef & name,const SourceLine & source)286 void Linker::addUnresolvedSymbol(const ResourceNameRef& name, const SourceLine& source) { 287 mUnresolvedSymbols[name.toResourceName()].push_back(source); 288 } 289 290 } // namespace aapt 291