Home | History | Annotate | Download | only in link
      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