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