XmlReferenceLinker.cpp revision ceb9b2f80f853059233cdd29057f39a5960a74ae
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 "link/Linkers.h" 18 19#include "androidfw/ResourceTypes.h" 20 21#include "Diagnostics.h" 22#include "ResourceUtils.h" 23#include "SdkConstants.h" 24#include "link/ReferenceLinker.h" 25#include "process/IResourceTableConsumer.h" 26#include "process/SymbolTable.h" 27#include "util/Util.h" 28#include "xml/XmlDom.h" 29 30namespace aapt { 31 32namespace { 33 34/** 35 * Visits all references (including parents of styles, references in styles, 36 * arrays, etc) and 37 * links their symbolic name to their Resource ID, performing mangling and 38 * package aliasing 39 * as needed. 40 */ 41class ReferenceVisitor : public ValueVisitor { 42 public: 43 using ValueVisitor::Visit; 44 45 ReferenceVisitor(IAaptContext* context, SymbolTable* symbols, xml::IPackageDeclStack* decls, 46 CallSite* callsite) 47 : context_(context), symbols_(symbols), decls_(decls), callsite_(callsite), error_(false) {} 48 49 void Visit(Reference* ref) override { 50 if (!ReferenceLinker::LinkReference(ref, context_, symbols_, decls_, callsite_)) { 51 error_ = true; 52 } 53 } 54 55 bool HasError() const { return error_; } 56 57 private: 58 DISALLOW_COPY_AND_ASSIGN(ReferenceVisitor); 59 60 IAaptContext* context_; 61 SymbolTable* symbols_; 62 xml::IPackageDeclStack* decls_; 63 CallSite* callsite_; 64 bool error_; 65}; 66 67/** 68 * Visits each xml Element and compiles the attributes within. 69 */ 70class XmlVisitor : public xml::PackageAwareVisitor { 71 public: 72 using xml::PackageAwareVisitor::Visit; 73 74 XmlVisitor(IAaptContext* context, SymbolTable* symbols, const Source& source, 75 std::set<int>* sdk_levels_found, CallSite* callsite) 76 : context_(context), 77 symbols_(symbols), 78 source_(source), 79 sdk_levels_found_(sdk_levels_found), 80 callsite_(callsite), 81 reference_visitor_(context, symbols, this, callsite) {} 82 83 void Visit(xml::Element* el) override { 84 // The default Attribute allows everything except enums or flags. 85 constexpr const static uint32_t kDefaultTypeMask = 86 0xffffffffu & ~(android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS); 87 const static Attribute kDefaultAttribute(true /* weak */, kDefaultTypeMask); 88 89 const Source source = source_.WithLine(el->line_number); 90 for (xml::Attribute& attr : el->attributes) { 91 // If the attribute has no namespace, interpret values as if 92 // they were assigned to the default Attribute. 93 94 const Attribute* attribute = &kDefaultAttribute; 95 std::string attribute_package; 96 97 if (Maybe<xml::ExtractedPackage> maybe_package = 98 xml::ExtractPackageFromNamespace(attr.namespace_uri)) { 99 // There is a valid package name for this attribute. We will look this up. 100 attribute_package = maybe_package.value().package; 101 if (attribute_package.empty()) { 102 // Empty package means the 'current' or 'local' package. 103 attribute_package = context_->GetCompilationPackage(); 104 } 105 106 Reference attr_ref(ResourceNameRef(attribute_package, ResourceType::kAttr, attr.name)); 107 attr_ref.private_reference = maybe_package.value().private_namespace; 108 109 std::string err_str; 110 attr.compiled_attribute = 111 ReferenceLinker::CompileXmlAttribute(attr_ref, symbols_, callsite_, &err_str); 112 113 if (!attr.compiled_attribute) { 114 context_->GetDiagnostics()->Error(DiagMessage(source) << "attribute '" 115 << attribute_package << ":" 116 << attr.name << "' " << err_str); 117 error_ = true; 118 continue; 119 } 120 121 // Find this compiled attribute's SDK level. 122 const xml::AaptAttribute& aapt_attr = attr.compiled_attribute.value(); 123 if (aapt_attr.id) { 124 // Record all SDK levels from which the attributes were defined. 125 const size_t sdk_level = FindAttributeSdkLevel(aapt_attr.id.value()); 126 if (sdk_level > 1) { 127 sdk_levels_found_->insert(sdk_level); 128 } 129 } 130 attribute = &aapt_attr.attribute; 131 } 132 133 attr.compiled_value = ResourceUtils::TryParseItemForAttribute(attr.value, attribute); 134 if (attr.compiled_value) { 135 // With a compiledValue, we must resolve the reference and assign it an 136 // ID. 137 attr.compiled_value->SetSource(source); 138 attr.compiled_value->Accept(&reference_visitor_); 139 } else if ((attribute->type_mask & android::ResTable_map::TYPE_STRING) == 0) { 140 // We won't be able to encode this as a string. 141 DiagMessage msg(source); 142 msg << "'" << attr.value << "' " 143 << "is incompatible with attribute "; 144 if (!attribute_package.empty()) { 145 msg << attribute_package << ":"; 146 } 147 msg << attr.name << " " << *attribute; 148 context_->GetDiagnostics()->Error(msg); 149 error_ = true; 150 } 151 } 152 153 // Call the super implementation. 154 xml::PackageAwareVisitor::Visit(el); 155 } 156 157 bool HasError() { return error_ || reference_visitor_.HasError(); } 158 159 private: 160 DISALLOW_COPY_AND_ASSIGN(XmlVisitor); 161 162 IAaptContext* context_; 163 SymbolTable* symbols_; 164 Source source_; 165 std::set<int>* sdk_levels_found_; 166 CallSite* callsite_; 167 ReferenceVisitor reference_visitor_; 168 bool error_ = false; 169}; 170 171} // namespace 172 173bool XmlReferenceLinker::Consume(IAaptContext* context, xml::XmlResource* resource) { 174 sdk_levels_found_.clear(); 175 CallSite callsite = {resource->file.name}; 176 XmlVisitor visitor(context, context->GetExternalSymbols(), resource->file.source, 177 &sdk_levels_found_, &callsite); 178 if (resource->root) { 179 resource->root->Accept(&visitor); 180 return !visitor.HasError(); 181 } 182 return false; 183} 184 185} // namespace aapt 186