Home | History | Annotate | Download | only in cmd
      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.h"
     18 
     19 #include <sys/stat.h>
     20 #include <cinttypes>
     21 
     22 #include <algorithm>
     23 #include <queue>
     24 #include <unordered_map>
     25 #include <vector>
     26 
     27 #include "android-base/errors.h"
     28 #include "android-base/file.h"
     29 #include "android-base/stringprintf.h"
     30 #include "androidfw/Locale.h"
     31 #include "androidfw/StringPiece.h"
     32 
     33 #include "AppInfo.h"
     34 #include "Debug.h"
     35 #include "LoadedApk.h"
     36 #include "NameMangler.h"
     37 #include "ResourceUtils.h"
     38 #include "ResourceValues.h"
     39 #include "ValueVisitor.h"
     40 #include "cmd/Util.h"
     41 #include "compile/IdAssigner.h"
     42 #include "compile/XmlIdCollector.h"
     43 #include "filter/ConfigFilter.h"
     44 #include "format/Archive.h"
     45 #include "format/Container.h"
     46 #include "format/binary/TableFlattener.h"
     47 #include "format/binary/XmlFlattener.h"
     48 #include "format/proto/ProtoDeserialize.h"
     49 #include "format/proto/ProtoSerialize.h"
     50 #include "io/BigBufferStream.h"
     51 #include "io/FileStream.h"
     52 #include "io/FileSystem.h"
     53 #include "io/Util.h"
     54 #include "io/ZipArchive.h"
     55 #include "java/JavaClassGenerator.h"
     56 #include "java/ManifestClassGenerator.h"
     57 #include "java/ProguardRules.h"
     58 #include "link/Linkers.h"
     59 #include "link/ManifestFixer.h"
     60 #include "link/NoDefaultResourceRemover.h"
     61 #include "link/ReferenceLinker.h"
     62 #include "link/ResourceExcluder.h"
     63 #include "link/TableMerger.h"
     64 #include "link/XmlCompatVersioner.h"
     65 #include "optimize/ResourceDeduper.h"
     66 #include "optimize/VersionCollapser.h"
     67 #include "process/IResourceTableConsumer.h"
     68 #include "process/SymbolTable.h"
     69 #include "split/TableSplitter.h"
     70 #include "trace/TraceBuffer.h"
     71 #include "util/Files.h"
     72 #include "xml/XmlDom.h"
     73 
     74 using ::aapt::io::FileInputStream;
     75 using ::android::ConfigDescription;
     76 using ::android::StringPiece;
     77 using ::android::base::StringPrintf;
     78 
     79 namespace aapt {
     80 
     81 class LinkContext : public IAaptContext {
     82  public:
     83   explicit LinkContext(IDiagnostics* diagnostics)
     84       : diagnostics_(diagnostics), name_mangler_({}), symbols_(&name_mangler_) {
     85   }
     86 
     87   PackageType GetPackageType() override {
     88     return package_type_;
     89   }
     90 
     91   void SetPackageType(PackageType type) {
     92     package_type_ = type;
     93   }
     94 
     95   IDiagnostics* GetDiagnostics() override {
     96     return diagnostics_;
     97   }
     98 
     99   NameMangler* GetNameMangler() override {
    100     return &name_mangler_;
    101   }
    102 
    103   void SetNameManglerPolicy(const NameManglerPolicy& policy) {
    104     name_mangler_ = NameMangler(policy);
    105   }
    106 
    107   const std::string& GetCompilationPackage() override {
    108     return compilation_package_;
    109   }
    110 
    111   void SetCompilationPackage(const StringPiece& package_name) {
    112     compilation_package_ = package_name.to_string();
    113   }
    114 
    115   uint8_t GetPackageId() override {
    116     return package_id_;
    117   }
    118 
    119   void SetPackageId(uint8_t id) {
    120     package_id_ = id;
    121   }
    122 
    123   SymbolTable* GetExternalSymbols() override {
    124     return &symbols_;
    125   }
    126 
    127   bool IsVerbose() override {
    128     return verbose_;
    129   }
    130 
    131   void SetVerbose(bool val) {
    132     verbose_ = val;
    133   }
    134 
    135   int GetMinSdkVersion() override {
    136     return min_sdk_version_;
    137   }
    138 
    139   void SetMinSdkVersion(int minSdk) {
    140     min_sdk_version_ = minSdk;
    141   }
    142 
    143  private:
    144   DISALLOW_COPY_AND_ASSIGN(LinkContext);
    145 
    146   PackageType package_type_ = PackageType::kApp;
    147   IDiagnostics* diagnostics_;
    148   NameMangler name_mangler_;
    149   std::string compilation_package_;
    150   uint8_t package_id_ = 0x0;
    151   SymbolTable symbols_;
    152   bool verbose_ = false;
    153   int min_sdk_version_ = 0;
    154 };
    155 
    156 // A custom delegate that generates compatible pre-O IDs for use with feature splits.
    157 // Feature splits use package IDs > 7f, which in Java (since Java doesn't have unsigned ints)
    158 // is interpreted as a negative number. Some verification was wrongly assuming negative values
    159 // were invalid.
    160 //
    161 // This delegate will attempt to masquerade any '@id/' references with ID 0xPPTTEEEE,
    162 // where PP > 7f, as 0x7fPPEEEE. Any potential overlapping is verified and an error occurs if such
    163 // an overlap exists.
    164 //
    165 // See b/37498913.
    166 class FeatureSplitSymbolTableDelegate : public DefaultSymbolTableDelegate {
    167  public:
    168   explicit FeatureSplitSymbolTableDelegate(IAaptContext* context) : context_(context) {
    169   }
    170 
    171   virtual ~FeatureSplitSymbolTableDelegate() = default;
    172 
    173   virtual std::unique_ptr<SymbolTable::Symbol> FindByName(
    174       const ResourceName& name,
    175       const std::vector<std::unique_ptr<ISymbolSource>>& sources) override {
    176     std::unique_ptr<SymbolTable::Symbol> symbol =
    177         DefaultSymbolTableDelegate::FindByName(name, sources);
    178     if (symbol == nullptr) {
    179       return {};
    180     }
    181 
    182     // Check to see if this is an 'id' with the target package.
    183     if (name.type == ResourceType::kId && symbol->id) {
    184       ResourceId* id = &symbol->id.value();
    185       if (id->package_id() > kAppPackageId) {
    186         // Rewrite the resource ID to be compatible pre-O.
    187         ResourceId rewritten_id(kAppPackageId, id->package_id(), id->entry_id());
    188 
    189         // Check that this doesn't overlap another resource.
    190         if (DefaultSymbolTableDelegate::FindById(rewritten_id, sources) != nullptr) {
    191           // The ID overlaps, so log a message (since this is a weird failure) and fail.
    192           context_->GetDiagnostics()->Error(DiagMessage() << "Failed to rewrite " << name
    193                                                           << " for pre-O feature split support");
    194           return {};
    195         }
    196 
    197         if (context_->IsVerbose()) {
    198           context_->GetDiagnostics()->Note(DiagMessage() << "rewriting " << name << " (" << *id
    199                                                          << ") -> (" << rewritten_id << ")");
    200         }
    201 
    202         *id = rewritten_id;
    203       }
    204     }
    205     return symbol;
    206   }
    207 
    208  private:
    209   DISALLOW_COPY_AND_ASSIGN(FeatureSplitSymbolTableDelegate);
    210 
    211   IAaptContext* context_;
    212 };
    213 
    214 static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res,
    215                        const StringPiece& path, bool keep_raw_values, bool utf16,
    216                        OutputFormat format, IArchiveWriter* writer) {
    217   TRACE_CALL();
    218   if (context->IsVerbose()) {
    219     context->GetDiagnostics()->Note(DiagMessage(path) << "writing to archive (keep_raw_values="
    220                                                       << (keep_raw_values ? "true" : "false")
    221                                                       << ")");
    222   }
    223 
    224   switch (format) {
    225     case OutputFormat::kApk: {
    226       BigBuffer buffer(1024);
    227       XmlFlattenerOptions options = {};
    228       options.keep_raw_values = keep_raw_values;
    229       options.use_utf16 = utf16;
    230       XmlFlattener flattener(&buffer, options);
    231       if (!flattener.Consume(context, &xml_res)) {
    232         return false;
    233       }
    234 
    235       io::BigBufferInputStream input_stream(&buffer);
    236       return io::CopyInputStreamToArchive(context, &input_stream, path.to_string(),
    237                                           ArchiveEntry::kCompress, writer);
    238     } break;
    239 
    240     case OutputFormat::kProto: {
    241       pb::XmlNode pb_node;
    242       // Strip whitespace text nodes from tha AndroidManifest.xml
    243       SerializeXmlOptions options;
    244       options.remove_empty_text_nodes = (path == kAndroidManifestPath);
    245       SerializeXmlResourceToPb(xml_res, &pb_node);
    246       return io::CopyProtoToArchive(context, &pb_node, path.to_string(), ArchiveEntry::kCompress,
    247                                     writer);
    248     } break;
    249   }
    250   return false;
    251 }
    252 
    253 // Inflates an XML file from the source path.
    254 static std::unique_ptr<xml::XmlResource> LoadXml(const std::string& path, IDiagnostics* diag) {
    255   TRACE_CALL();
    256   FileInputStream fin(path);
    257   if (fin.HadError()) {
    258     diag->Error(DiagMessage(path) << "failed to load XML file: " << fin.GetError());
    259     return {};
    260   }
    261   return xml::Inflate(&fin, diag, Source(path));
    262 }
    263 
    264 struct ResourceFileFlattenerOptions {
    265   bool no_auto_version = false;
    266   bool no_version_vectors = false;
    267   bool no_version_transitions = false;
    268   bool no_xml_namespaces = false;
    269   bool keep_raw_values = false;
    270   bool do_not_compress_anything = false;
    271   bool update_proguard_spec = false;
    272   OutputFormat output_format = OutputFormat::kApk;
    273   std::unordered_set<std::string> extensions_to_not_compress;
    274   Maybe<std::regex> regex_to_not_compress;
    275 };
    276 
    277 // A sampling of public framework resource IDs.
    278 struct R {
    279   struct attr {
    280     enum : uint32_t {
    281       paddingLeft = 0x010100d6u,
    282       paddingRight = 0x010100d8u,
    283       paddingHorizontal = 0x0101053du,
    284 
    285       paddingTop = 0x010100d7u,
    286       paddingBottom = 0x010100d9u,
    287       paddingVertical = 0x0101053eu,
    288 
    289       layout_marginLeft = 0x010100f7u,
    290       layout_marginRight = 0x010100f9u,
    291       layout_marginHorizontal = 0x0101053bu,
    292 
    293       layout_marginTop = 0x010100f8u,
    294       layout_marginBottom = 0x010100fau,
    295       layout_marginVertical = 0x0101053cu,
    296     };
    297   };
    298 };
    299 
    300 class ResourceFileFlattener {
    301  public:
    302   ResourceFileFlattener(const ResourceFileFlattenerOptions& options, IAaptContext* context,
    303                         proguard::KeepSet* keep_set);
    304 
    305   bool Flatten(ResourceTable* table, IArchiveWriter* archive_writer);
    306 
    307  private:
    308   struct FileOperation {
    309     ConfigDescription config;
    310 
    311     // The entry this file came from.
    312     ResourceEntry* entry;
    313 
    314     // The file to copy as-is.
    315     io::IFile* file_to_copy;
    316 
    317     // The XML to process and flatten.
    318     std::unique_ptr<xml::XmlResource> xml_to_flatten;
    319 
    320     // The destination to write this file to.
    321     std::string dst_path;
    322   };
    323 
    324   uint32_t GetCompressionFlags(const StringPiece& str);
    325 
    326   std::vector<std::unique_ptr<xml::XmlResource>> LinkAndVersionXmlFile(ResourceTable* table,
    327                                                                        FileOperation* file_op);
    328 
    329   ResourceFileFlattenerOptions options_;
    330   IAaptContext* context_;
    331   proguard::KeepSet* keep_set_;
    332   XmlCompatVersioner::Rules rules_;
    333 };
    334 
    335 ResourceFileFlattener::ResourceFileFlattener(const ResourceFileFlattenerOptions& options,
    336                                              IAaptContext* context, proguard::KeepSet* keep_set)
    337     : options_(options), context_(context), keep_set_(keep_set) {
    338   SymbolTable* symm = context_->GetExternalSymbols();
    339 
    340   // Build up the rules for degrading newer attributes to older ones.
    341   // NOTE(adamlesinski): These rules are hardcoded right now, but they should be
    342   // generated from the attribute definitions themselves (b/62028956).
    343   if (const SymbolTable::Symbol* s = symm->FindById(R::attr::paddingHorizontal)) {
    344     std::vector<ReplacementAttr> replacements{
    345         {"paddingLeft", R::attr::paddingLeft, Attribute(android::ResTable_map::TYPE_DIMENSION)},
    346         {"paddingRight", R::attr::paddingRight, Attribute(android::ResTable_map::TYPE_DIMENSION)},
    347     };
    348     rules_[R::attr::paddingHorizontal] =
    349         util::make_unique<DegradeToManyRule>(std::move(replacements));
    350   }
    351 
    352   if (const SymbolTable::Symbol* s = symm->FindById(R::attr::paddingVertical)) {
    353     std::vector<ReplacementAttr> replacements{
    354         {"paddingTop", R::attr::paddingTop, Attribute(android::ResTable_map::TYPE_DIMENSION)},
    355         {"paddingBottom", R::attr::paddingBottom, Attribute(android::ResTable_map::TYPE_DIMENSION)},
    356     };
    357     rules_[R::attr::paddingVertical] =
    358         util::make_unique<DegradeToManyRule>(std::move(replacements));
    359   }
    360 
    361   if (const SymbolTable::Symbol* s = symm->FindById(R::attr::layout_marginHorizontal)) {
    362     std::vector<ReplacementAttr> replacements{
    363         {"layout_marginLeft", R::attr::layout_marginLeft,
    364          Attribute(android::ResTable_map::TYPE_DIMENSION)},
    365         {"layout_marginRight", R::attr::layout_marginRight,
    366          Attribute(android::ResTable_map::TYPE_DIMENSION)},
    367     };
    368     rules_[R::attr::layout_marginHorizontal] =
    369         util::make_unique<DegradeToManyRule>(std::move(replacements));
    370   }
    371 
    372   if (const SymbolTable::Symbol* s = symm->FindById(R::attr::layout_marginVertical)) {
    373     std::vector<ReplacementAttr> replacements{
    374         {"layout_marginTop", R::attr::layout_marginTop,
    375          Attribute(android::ResTable_map::TYPE_DIMENSION)},
    376         {"layout_marginBottom", R::attr::layout_marginBottom,
    377          Attribute(android::ResTable_map::TYPE_DIMENSION)},
    378     };
    379     rules_[R::attr::layout_marginVertical] =
    380         util::make_unique<DegradeToManyRule>(std::move(replacements));
    381   }
    382 }
    383 
    384 // TODO(rtmitchell): turn this function into a variable that points to a method that retrieves the
    385 // compression flag
    386 uint32_t ResourceFileFlattener::GetCompressionFlags(const StringPiece& str) {
    387   if (options_.do_not_compress_anything) {
    388     return 0;
    389   }
    390 
    391   if (options_.regex_to_not_compress
    392       && std::regex_search(str.to_string(), options_.regex_to_not_compress.value())) {
    393     return 0;
    394   }
    395 
    396   for (const std::string& extension : options_.extensions_to_not_compress) {
    397     if (util::EndsWith(str, extension)) {
    398       return 0;
    399     }
    400   }
    401   return ArchiveEntry::kCompress;
    402 }
    403 
    404 static bool IsTransitionElement(const std::string& name) {
    405   return name == "fade" || name == "changeBounds" || name == "slide" || name == "explode" ||
    406          name == "changeImageTransform" || name == "changeTransform" ||
    407          name == "changeClipBounds" || name == "autoTransition" || name == "recolor" ||
    408          name == "changeScroll" || name == "transitionSet" || name == "transition" ||
    409          name == "transitionManager";
    410 }
    411 
    412 static bool IsVectorElement(const std::string& name) {
    413   return name == "vector" || name == "animated-vector" || name == "pathInterpolator" ||
    414          name == "objectAnimator" || name == "gradient" || name == "animated-selector" ||
    415          name == "set";
    416 }
    417 
    418 template <typename T>
    419 std::vector<T> make_singleton_vec(T&& val) {
    420   std::vector<T> vec;
    421   vec.emplace_back(std::forward<T>(val));
    422   return vec;
    423 }
    424 
    425 std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVersionXmlFile(
    426     ResourceTable* table, FileOperation* file_op) {
    427   TRACE_CALL();
    428   xml::XmlResource* doc = file_op->xml_to_flatten.get();
    429   const Source& src = doc->file.source;
    430 
    431   if (context_->IsVerbose()) {
    432     context_->GetDiagnostics()->Note(DiagMessage()
    433                                      << "linking " << src.path << " (" << doc->file.name << ")");
    434   }
    435 
    436   // First, strip out any tools namespace attributes. AAPT stripped them out early, which means
    437   // that existing projects have out-of-date references which pass compilation.
    438   xml::StripAndroidStudioAttributes(doc->root.get());
    439 
    440   XmlReferenceLinker xml_linker;
    441   if (!xml_linker.Consume(context_, doc)) {
    442     return {};
    443   }
    444 
    445   if (options_.update_proguard_spec && !proguard::CollectProguardRules(context_, doc, keep_set_)) {
    446     return {};
    447   }
    448 
    449   if (options_.no_xml_namespaces) {
    450     XmlNamespaceRemover namespace_remover;
    451     if (!namespace_remover.Consume(context_, doc)) {
    452       return {};
    453     }
    454   }
    455 
    456   if (options_.no_auto_version) {
    457     return make_singleton_vec(std::move(file_op->xml_to_flatten));
    458   }
    459 
    460   if (options_.no_version_vectors || options_.no_version_transitions) {
    461     // Skip this if it is a vector or animated-vector.
    462     xml::Element* el = doc->root.get();
    463     if (el && el->namespace_uri.empty()) {
    464       if ((options_.no_version_vectors && IsVectorElement(el->name)) ||
    465           (options_.no_version_transitions && IsTransitionElement(el->name))) {
    466         return make_singleton_vec(std::move(file_op->xml_to_flatten));
    467       }
    468     }
    469   }
    470 
    471   const ConfigDescription& config = file_op->config;
    472   ResourceEntry* entry = file_op->entry;
    473 
    474   XmlCompatVersioner xml_compat_versioner(&rules_);
    475   const util::Range<ApiVersion> api_range{config.sdkVersion,
    476                                           FindNextApiVersionForConfig(entry, config)};
    477   return xml_compat_versioner.Process(context_, doc, api_range);
    478 }
    479 
    480 ResourceFile::Type XmlFileTypeForOutputFormat(OutputFormat format) {
    481   switch (format) {
    482     case OutputFormat::kApk:
    483       return ResourceFile::Type::kBinaryXml;
    484     case OutputFormat::kProto:
    485       return ResourceFile::Type::kProtoXml;
    486   }
    487   LOG_ALWAYS_FATAL("unreachable");
    488   return ResourceFile::Type::kUnknown;
    489 }
    490 
    491 static auto kDrawableVersions = std::map<std::string, ApiVersion>{
    492     { "adaptive-icon" , SDK_O },
    493 };
    494 
    495 bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archive_writer) {
    496   TRACE_CALL();
    497   bool error = false;
    498   std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> config_sorted_files;
    499 
    500   proguard::CollectResourceReferences(context_, table, keep_set_);
    501 
    502   for (auto& pkg : table->packages) {
    503     CHECK(!pkg->name.empty()) << "Packages must have names when being linked";
    504 
    505     for (auto& type : pkg->types) {
    506       // Sort by config and name, so that we get better locality in the zip file.
    507       config_sorted_files.clear();
    508       std::queue<FileOperation> file_operations;
    509 
    510       // Populate the queue with all files in the ResourceTable.
    511       for (auto& entry : type->entries) {
    512         for (auto& config_value : entry->values) {
    513           // WARNING! Do not insert or remove any resources while executing in this scope. It will
    514           // corrupt the iteration order.
    515 
    516           FileReference* file_ref = ValueCast<FileReference>(config_value->value.get());
    517           if (!file_ref) {
    518             continue;
    519           }
    520 
    521           io::IFile* file = file_ref->file;
    522           if (!file) {
    523             context_->GetDiagnostics()->Error(DiagMessage(file_ref->GetSource())
    524                                               << "file not found");
    525             return false;
    526           }
    527 
    528           FileOperation file_op;
    529           file_op.entry = entry.get();
    530           file_op.dst_path = *file_ref->path;
    531           file_op.config = config_value->config;
    532           file_op.file_to_copy = file;
    533 
    534           if (type->type != ResourceType::kRaw &&
    535               (file_ref->type == ResourceFile::Type::kBinaryXml ||
    536                file_ref->type == ResourceFile::Type::kProtoXml)) {
    537             std::unique_ptr<io::IData> data = file->OpenAsData();
    538             if (!data) {
    539               context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
    540                                                 << "failed to open file");
    541               return false;
    542             }
    543 
    544             if (file_ref->type == ResourceFile::Type::kProtoXml) {
    545               pb::XmlNode pb_xml_node;
    546               if (!pb_xml_node.ParseFromArray(data->data(), static_cast<int>(data->size()))) {
    547                 context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
    548                                                   << "failed to parse proto XML");
    549                 return false;
    550               }
    551 
    552               std::string error;
    553               file_op.xml_to_flatten = DeserializeXmlResourceFromPb(pb_xml_node, &error);
    554               if (file_op.xml_to_flatten == nullptr) {
    555                 context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
    556                                                   << "failed to deserialize proto XML: " << error);
    557                 return false;
    558               }
    559             } else {
    560               std::string error_str;
    561               file_op.xml_to_flatten = xml::Inflate(data->data(), data->size(), &error_str);
    562               if (file_op.xml_to_flatten == nullptr) {
    563                 context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
    564                                                   << "failed to parse binary XML: " << error_str);
    565                 return false;
    566               }
    567             }
    568 
    569             // Update the type that this file will be written as.
    570             file_ref->type = XmlFileTypeForOutputFormat(options_.output_format);
    571 
    572             file_op.xml_to_flatten->file.config = config_value->config;
    573             file_op.xml_to_flatten->file.source = file_ref->GetSource();
    574             file_op.xml_to_flatten->file.name = ResourceName(pkg->name, type->type, entry->name);
    575           }
    576 
    577           // NOTE(adamlesinski): Explicitly construct a StringPiece here, or
    578           // else we end up copying the string in the std::make_pair() method,
    579           // then creating a StringPiece from the copy, which would cause us
    580           // to end up referencing garbage in the map.
    581           const StringPiece entry_name(entry->name);
    582           config_sorted_files[std::make_pair(config_value->config, entry_name)] =
    583               std::move(file_op);
    584         }
    585       }
    586 
    587       // Now flatten the sorted values.
    588       for (auto& map_entry : config_sorted_files) {
    589         const ConfigDescription& config = map_entry.first.first;
    590         FileOperation& file_op = map_entry.second;
    591 
    592         if (file_op.xml_to_flatten) {
    593           // Check minimum sdk versions supported for drawables
    594           auto drawable_entry = kDrawableVersions.find(file_op.xml_to_flatten->root->name);
    595           if (drawable_entry != kDrawableVersions.end()) {
    596             if (drawable_entry->second > context_->GetMinSdkVersion()
    597                 && drawable_entry->second > config.sdkVersion) {
    598               context_->GetDiagnostics()->Error(DiagMessage(file_op.xml_to_flatten->file.source)
    599                                                     << "<" << drawable_entry->first << "> elements "
    600                                                     << "require a sdk version of at least "
    601                                                     << (int16_t) drawable_entry->second);
    602               error = true;
    603               continue;
    604             }
    605           }
    606 
    607           std::vector<std::unique_ptr<xml::XmlResource>> versioned_docs =
    608               LinkAndVersionXmlFile(table, &file_op);
    609           if (versioned_docs.empty()) {
    610             error = true;
    611             continue;
    612           }
    613 
    614           for (std::unique_ptr<xml::XmlResource>& doc : versioned_docs) {
    615             std::string dst_path = file_op.dst_path;
    616             if (doc->file.config != file_op.config) {
    617               // Only add the new versioned configurations.
    618               if (context_->IsVerbose()) {
    619                 context_->GetDiagnostics()->Note(DiagMessage(doc->file.source)
    620                                                  << "auto-versioning resource from config '"
    621                                                  << config << "' -> '" << doc->file.config << "'");
    622               }
    623 
    624               const ResourceFile& file = doc->file;
    625               dst_path = ResourceUtils::BuildResourceFileName(file, context_->GetNameMangler());
    626 
    627               std::unique_ptr<FileReference> file_ref =
    628                   util::make_unique<FileReference>(table->string_pool.MakeRef(dst_path));
    629               file_ref->SetSource(doc->file.source);
    630               // Update the output format of this XML file.
    631               file_ref->type = XmlFileTypeForOutputFormat(options_.output_format);
    632               if (!table->AddResourceMangled(file.name, file.config, {}, std::move(file_ref),
    633                                              context_->GetDiagnostics())) {
    634                 return false;
    635               }
    636             }
    637 
    638             error |= !FlattenXml(context_, *doc, dst_path, options_.keep_raw_values,
    639                                  false /*utf16*/, options_.output_format, archive_writer);
    640           }
    641         } else {
    642           error |= !io::CopyFileToArchive(context_, file_op.file_to_copy, file_op.dst_path,
    643                                           GetCompressionFlags(file_op.dst_path), archive_writer);
    644         }
    645       }
    646     }
    647   }
    648   return !error;
    649 }
    650 
    651 static bool WriteStableIdMapToPath(IDiagnostics* diag,
    652                                    const std::unordered_map<ResourceName, ResourceId>& id_map,
    653                                    const std::string& id_map_path) {
    654   io::FileOutputStream fout(id_map_path);
    655   if (fout.HadError()) {
    656     diag->Error(DiagMessage(id_map_path) << "failed to open: " << fout.GetError());
    657     return false;
    658   }
    659 
    660   text::Printer printer(&fout);
    661   for (const auto& entry : id_map) {
    662     const ResourceName& name = entry.first;
    663     const ResourceId& id = entry.second;
    664     printer.Print(name.to_string());
    665     printer.Print(" = ");
    666     printer.Println(id.to_string());
    667   }
    668   fout.Flush();
    669 
    670   if (fout.HadError()) {
    671     diag->Error(DiagMessage(id_map_path) << "failed writing to file: " << fout.GetError());
    672     return false;
    673   }
    674   return true;
    675 }
    676 
    677 static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
    678                             std::unordered_map<ResourceName, ResourceId>* out_id_map) {
    679   std::string content;
    680   if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
    681     diag->Error(DiagMessage(path) << "failed reading stable ID file");
    682     return false;
    683   }
    684 
    685   out_id_map->clear();
    686   size_t line_no = 0;
    687   for (StringPiece line : util::Tokenize(content, '\n')) {
    688     line_no++;
    689     line = util::TrimWhitespace(line);
    690     if (line.empty()) {
    691       continue;
    692     }
    693 
    694     auto iter = std::find(line.begin(), line.end(), '=');
    695     if (iter == line.end()) {
    696       diag->Error(DiagMessage(Source(path, line_no)) << "missing '='");
    697       return false;
    698     }
    699 
    700     ResourceNameRef name;
    701     StringPiece res_name_str =
    702         util::TrimWhitespace(line.substr(0, std::distance(line.begin(), iter)));
    703     if (!ResourceUtils::ParseResourceName(res_name_str, &name)) {
    704       diag->Error(DiagMessage(Source(path, line_no)) << "invalid resource name '" << res_name_str
    705                                                      << "'");
    706       return false;
    707     }
    708 
    709     const size_t res_id_start_idx = std::distance(line.begin(), iter) + 1;
    710     const size_t res_id_str_len = line.size() - res_id_start_idx;
    711     StringPiece res_id_str = util::TrimWhitespace(line.substr(res_id_start_idx, res_id_str_len));
    712 
    713     Maybe<ResourceId> maybe_id = ResourceUtils::ParseResourceId(res_id_str);
    714     if (!maybe_id) {
    715       diag->Error(DiagMessage(Source(path, line_no)) << "invalid resource ID '" << res_id_str
    716                                                      << "'");
    717       return false;
    718     }
    719 
    720     (*out_id_map)[name.ToResourceName()] = maybe_id.value();
    721   }
    722   return true;
    723 }
    724 
    725 static android::ApkAssetsCookie FindFrameworkAssetManagerCookie(
    726     const android::AssetManager2& assets) {
    727   using namespace android;
    728 
    729   // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so
    730   // we're looking for the first attribute resource in the system package.
    731   Res_value val{};
    732   ResTable_config config{};
    733   uint32_t type_spec_flags;
    734   ApkAssetsCookie idx = assets.GetResource(0x01010000, true /** may_be_bag */,
    735                                            0 /** density_override */, &val, &config,
    736                                            &type_spec_flags);
    737 
    738   return idx;
    739 }
    740 
    741 class Linker {
    742  public:
    743   Linker(LinkContext* context, const LinkOptions& options)
    744       : options_(options),
    745         context_(context),
    746         final_table_(),
    747         file_collection_(util::make_unique<io::FileCollection>()) {
    748   }
    749 
    750   void ExtractCompileSdkVersions(android::AssetManager2* assets) {
    751     using namespace android;
    752 
    753     android::ApkAssetsCookie cookie = FindFrameworkAssetManagerCookie(*assets);
    754     if (cookie == android::kInvalidCookie) {
    755       // No Framework assets loaded. Not a failure.
    756       return;
    757     }
    758 
    759     std::unique_ptr<Asset> manifest(
    760         assets->OpenNonAsset(kAndroidManifestPath, cookie, Asset::AccessMode::ACCESS_BUFFER));
    761     if (manifest == nullptr) {
    762       // No errors.
    763       return;
    764     }
    765 
    766     std::string error;
    767     std::unique_ptr<xml::XmlResource> manifest_xml =
    768         xml::Inflate(manifest->getBuffer(true /*wordAligned*/), manifest->getLength(), &error);
    769     if (manifest_xml == nullptr) {
    770       // No errors.
    771       return;
    772     }
    773 
    774     if (!options_.manifest_fixer_options.compile_sdk_version) {
    775       xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionCode");
    776       if (attr != nullptr) {
    777         Maybe<std::string>& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version;
    778         if (BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get())) {
    779           switch (prim->value.dataType) {
    780             case Res_value::TYPE_INT_DEC:
    781               compile_sdk_version = StringPrintf("%" PRId32, static_cast<int32_t>(prim->value.data));
    782               break;
    783             case Res_value::TYPE_INT_HEX:
    784               compile_sdk_version = StringPrintf("%" PRIx32, prim->value.data);
    785               break;
    786             default:
    787               break;
    788           }
    789         } else if (String* str = ValueCast<String>(attr->compiled_value.get())) {
    790           compile_sdk_version = *str->value;
    791         } else {
    792           compile_sdk_version = attr->value;
    793         }
    794       }
    795     }
    796 
    797     if (!options_.manifest_fixer_options.compile_sdk_version_codename) {
    798       xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionName");
    799       if (attr != nullptr) {
    800         Maybe<std::string>& compile_sdk_version_codename =
    801             options_.manifest_fixer_options.compile_sdk_version_codename;
    802         if (String* str = ValueCast<String>(attr->compiled_value.get())) {
    803           compile_sdk_version_codename = *str->value;
    804         } else {
    805           compile_sdk_version_codename = attr->value;
    806         }
    807       }
    808     }
    809   }
    810 
    811   // Creates a SymbolTable that loads symbols from the various APKs.
    812   // Pre-condition: context_->GetCompilationPackage() needs to be set.
    813   bool LoadSymbolsFromIncludePaths() {
    814     TRACE_NAME("LoadSymbolsFromIncludePaths: #" + std::to_string(options_.include_paths.size()));
    815     auto asset_source = util::make_unique<AssetManagerSymbolSource>();
    816     for (const std::string& path : options_.include_paths) {
    817       if (context_->IsVerbose()) {
    818         context_->GetDiagnostics()->Note(DiagMessage() << "including " << path);
    819       }
    820 
    821       std::string error;
    822       auto zip_collection = io::ZipFileCollection::Create(path, &error);
    823       if (zip_collection == nullptr) {
    824         context_->GetDiagnostics()->Error(DiagMessage() << "failed to open APK: " << error);
    825         return false;
    826       }
    827 
    828       if (zip_collection->FindFile(kProtoResourceTablePath) != nullptr) {
    829         // Load this as a static library include.
    830         std::unique_ptr<LoadedApk> static_apk = LoadedApk::LoadProtoApkFromFileCollection(
    831             Source(path), std::move(zip_collection), context_->GetDiagnostics());
    832         if (static_apk == nullptr) {
    833           return false;
    834         }
    835 
    836         if (context_->GetPackageType() != PackageType::kStaticLib) {
    837           // Can't include static libraries when not building a static library (they have no IDs
    838           // assigned).
    839           context_->GetDiagnostics()->Error(
    840               DiagMessage(path) << "can't include static library when not building a static lib");
    841           return false;
    842         }
    843 
    844         ResourceTable* table = static_apk->GetResourceTable();
    845 
    846         // If we are using --no-static-lib-packages, we need to rename the package of this table to
    847         // our compilation package.
    848         if (options_.no_static_lib_packages) {
    849           // Since package names can differ, and multiple packages can exist in a ResourceTable,
    850           // we place the requirement that all static libraries are built with the package
    851           // ID 0x7f. So if one is not found, this is an error.
    852           if (ResourceTablePackage* pkg = table->FindPackageById(kAppPackageId)) {
    853             pkg->name = context_->GetCompilationPackage();
    854           } else {
    855             context_->GetDiagnostics()->Error(DiagMessage(path)
    856                                               << "no package with ID 0x7f found in static library");
    857             return false;
    858           }
    859         }
    860 
    861         context_->GetExternalSymbols()->AppendSource(
    862             util::make_unique<ResourceTableSymbolSource>(table));
    863         static_library_includes_.push_back(std::move(static_apk));
    864       } else {
    865         if (!asset_source->AddAssetPath(path)) {
    866           context_->GetDiagnostics()->Error(DiagMessage()
    867                                             << "failed to load include path " << path);
    868           return false;
    869         }
    870       }
    871     }
    872 
    873     // Capture the shared libraries so that the final resource table can be properly flattened
    874     // with support for shared libraries.
    875     for (auto& entry : asset_source->GetAssignedPackageIds()) {
    876       if (entry.first == kAppPackageId) {
    877         // Capture the included base feature package.
    878         included_feature_base_ = entry.second;
    879       } else if (entry.first == kFrameworkPackageId) {
    880         // Try to embed which version of the framework we're compiling against.
    881         // First check if we should use compileSdkVersion at all. Otherwise compilation may fail
    882         // when linking our synthesized 'android:compileSdkVersion' attribute.
    883         std::unique_ptr<SymbolTable::Symbol> symbol = asset_source->FindByName(
    884             ResourceName("android", ResourceType::kAttr, "compileSdkVersion"));
    885         if (symbol != nullptr && symbol->is_public) {
    886           // The symbol is present and public, extract the android:versionName and
    887           // android:versionCode from the framework AndroidManifest.xml.
    888           ExtractCompileSdkVersions(asset_source->GetAssetManager());
    889         }
    890       } else if (asset_source->IsPackageDynamic(entry.first)) {
    891         final_table_.included_packages_[entry.first] = entry.second;
    892       }
    893     }
    894 
    895     context_->GetExternalSymbols()->AppendSource(std::move(asset_source));
    896     return true;
    897   }
    898 
    899   Maybe<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res, IDiagnostics* diag) {
    900     TRACE_CALL();
    901     // Make sure the first element is <manifest> with package attribute.
    902     xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get());
    903     if (manifest_el == nullptr) {
    904       return {};
    905     }
    906 
    907     AppInfo app_info;
    908 
    909     if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
    910       diag->Error(DiagMessage(xml_res->file.source) << "root tag must be <manifest>");
    911       return {};
    912     }
    913 
    914     xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
    915     if (!package_attr) {
    916       diag->Error(DiagMessage(xml_res->file.source)
    917                   << "<manifest> must have a 'package' attribute");
    918       return {};
    919     }
    920     app_info.package = package_attr->value;
    921 
    922     if (xml::Attribute* version_code_attr =
    923             manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
    924       Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_attr->value);
    925       if (!maybe_code) {
    926         diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
    927                     << "invalid android:versionCode '" << version_code_attr->value << "'");
    928         return {};
    929       }
    930       app_info.version_code = maybe_code.value();
    931     }
    932 
    933     if (xml::Attribute* version_code_major_attr =
    934         manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) {
    935       Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_major_attr->value);
    936       if (!maybe_code) {
    937         diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
    938                         << "invalid android:versionCodeMajor '"
    939                         << version_code_major_attr->value << "'");
    940         return {};
    941       }
    942       app_info.version_code_major = maybe_code.value();
    943     }
    944 
    945     if (xml::Attribute* revision_code_attr =
    946             manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
    947       Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(revision_code_attr->value);
    948       if (!maybe_code) {
    949         diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
    950                     << "invalid android:revisionCode '" << revision_code_attr->value << "'");
    951         return {};
    952       }
    953       app_info.revision_code = maybe_code.value();
    954     }
    955 
    956     if (xml::Attribute* split_name_attr = manifest_el->FindAttribute({}, "split")) {
    957       if (!split_name_attr->value.empty()) {
    958         app_info.split_name = split_name_attr->value;
    959       }
    960     }
    961 
    962     if (xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) {
    963       if (xml::Attribute* min_sdk =
    964               uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) {
    965         app_info.min_sdk_version = ResourceUtils::ParseSdkVersion(min_sdk->value);
    966       }
    967     }
    968     return app_info;
    969   }
    970 
    971   // Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked.
    972   // Postcondition: ResourceTable has only one package left. All others are
    973   // stripped, or there is an error and false is returned.
    974   bool VerifyNoExternalPackages() {
    975     auto is_ext_package_func = [&](const std::unique_ptr<ResourceTablePackage>& pkg) -> bool {
    976       return context_->GetCompilationPackage() != pkg->name || !pkg->id ||
    977              pkg->id.value() != context_->GetPackageId();
    978     };
    979 
    980     bool error = false;
    981     for (const auto& package : final_table_.packages) {
    982       if (is_ext_package_func(package)) {
    983         // We have a package that is not related to the one we're building!
    984         for (const auto& type : package->types) {
    985           for (const auto& entry : type->entries) {
    986             ResourceNameRef res_name(package->name, type->type, entry->name);
    987 
    988             for (const auto& config_value : entry->values) {
    989               // Special case the occurrence of an ID that is being generated
    990               // for the 'android' package. This is due to legacy reasons.
    991               if (ValueCast<Id>(config_value->value.get()) && package->name == "android") {
    992                 context_->GetDiagnostics()->Warn(DiagMessage(config_value->value->GetSource())
    993                                                  << "generated id '" << res_name
    994                                                  << "' for external package '" << package->name
    995                                                  << "'");
    996               } else {
    997                 context_->GetDiagnostics()->Error(DiagMessage(config_value->value->GetSource())
    998                                                   << "defined resource '" << res_name
    999                                                   << "' for external package '" << package->name
   1000                                                   << "'");
   1001                 error = true;
   1002               }
   1003             }
   1004           }
   1005         }
   1006       }
   1007     }
   1008 
   1009     auto new_end_iter = std::remove_if(final_table_.packages.begin(), final_table_.packages.end(),
   1010                                        is_ext_package_func);
   1011     final_table_.packages.erase(new_end_iter, final_table_.packages.end());
   1012     return !error;
   1013   }
   1014 
   1015   /**
   1016    * Returns true if no IDs have been set, false otherwise.
   1017    */
   1018   bool VerifyNoIdsSet() {
   1019     for (const auto& package : final_table_.packages) {
   1020       for (const auto& type : package->types) {
   1021         if (type->id) {
   1022           context_->GetDiagnostics()->Error(DiagMessage() << "type " << type->type << " has ID "
   1023                                                           << StringPrintf("%02x", type->id.value())
   1024                                                           << " assigned");
   1025           return false;
   1026         }
   1027 
   1028         for (const auto& entry : type->entries) {
   1029           if (entry->id) {
   1030             ResourceNameRef res_name(package->name, type->type, entry->name);
   1031             context_->GetDiagnostics()->Error(
   1032                 DiagMessage() << "entry " << res_name << " has ID "
   1033                               << StringPrintf("%02x", entry->id.value()) << " assigned");
   1034             return false;
   1035           }
   1036         }
   1037       }
   1038     }
   1039     return true;
   1040   }
   1041 
   1042   std::unique_ptr<IArchiveWriter> MakeArchiveWriter(const StringPiece& out) {
   1043     if (options_.output_to_directory) {
   1044       return CreateDirectoryArchiveWriter(context_->GetDiagnostics(), out);
   1045     } else {
   1046       return CreateZipFileArchiveWriter(context_->GetDiagnostics(), out);
   1047     }
   1048   }
   1049 
   1050   bool FlattenTable(ResourceTable* table, OutputFormat format, IArchiveWriter* writer) {
   1051     TRACE_CALL();
   1052     switch (format) {
   1053       case OutputFormat::kApk: {
   1054         BigBuffer buffer(1024);
   1055         TableFlattener flattener(options_.table_flattener_options, &buffer);
   1056         if (!flattener.Consume(context_, table)) {
   1057           context_->GetDiagnostics()->Error(DiagMessage() << "failed to flatten resource table");
   1058           return false;
   1059         }
   1060 
   1061         io::BigBufferInputStream input_stream(&buffer);
   1062         return io::CopyInputStreamToArchive(context_, &input_stream, kApkResourceTablePath,
   1063                                             ArchiveEntry::kAlign, writer);
   1064       } break;
   1065 
   1066       case OutputFormat::kProto: {
   1067         pb::ResourceTable pb_table;
   1068         SerializeTableToPb(*table, &pb_table, context_->GetDiagnostics());
   1069         return io::CopyProtoToArchive(context_, &pb_table, kProtoResourceTablePath,
   1070                                       ArchiveEntry::kCompress, writer);
   1071       } break;
   1072     }
   1073     return false;
   1074   }
   1075 
   1076   bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate,
   1077                      const StringPiece& out_package, const JavaClassGeneratorOptions& java_options,
   1078                      const Maybe<std::string>& out_text_symbols_path = {}) {
   1079     if (!options_.generate_java_class_path && !out_text_symbols_path) {
   1080       return true;
   1081     }
   1082 
   1083     std::string out_path;
   1084     std::unique_ptr<io::FileOutputStream> fout;
   1085     if (options_.generate_java_class_path) {
   1086       out_path = options_.generate_java_class_path.value();
   1087       file::AppendPath(&out_path, file::PackageToPath(out_package));
   1088       if (!file::mkdirs(out_path)) {
   1089         context_->GetDiagnostics()->Error(DiagMessage()
   1090                                           << "failed to create directory '" << out_path << "'");
   1091         return false;
   1092       }
   1093 
   1094       file::AppendPath(&out_path, "R.java");
   1095 
   1096       fout = util::make_unique<io::FileOutputStream>(out_path);
   1097       if (fout->HadError()) {
   1098         context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
   1099                                                         << "': " << fout->GetError());
   1100         return false;
   1101       }
   1102     }
   1103 
   1104     std::unique_ptr<io::FileOutputStream> fout_text;
   1105     if (out_text_symbols_path) {
   1106       fout_text = util::make_unique<io::FileOutputStream>(out_text_symbols_path.value());
   1107       if (fout_text->HadError()) {
   1108         context_->GetDiagnostics()->Error(DiagMessage()
   1109                                           << "failed writing to '" << out_text_symbols_path.value()
   1110                                           << "': " << fout_text->GetError());
   1111         return false;
   1112       }
   1113     }
   1114 
   1115     JavaClassGenerator generator(context_, table, java_options);
   1116     if (!generator.Generate(package_name_to_generate, out_package, fout.get(), fout_text.get())) {
   1117       context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.GetError());
   1118       return false;
   1119     }
   1120 
   1121     return true;
   1122   }
   1123 
   1124   bool GenerateJavaClasses() {
   1125     TRACE_CALL();
   1126     // The set of packages whose R class to call in the main classes onResourcesLoaded callback.
   1127     std::vector<std::string> packages_to_callback;
   1128 
   1129     JavaClassGeneratorOptions template_options;
   1130     template_options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
   1131     template_options.javadoc_annotations = options_.javadoc_annotations;
   1132 
   1133     if (context_->GetPackageType() == PackageType::kStaticLib || options_.generate_non_final_ids) {
   1134       template_options.use_final = false;
   1135     }
   1136 
   1137     if (context_->GetPackageType() == PackageType::kSharedLib) {
   1138       template_options.use_final = false;
   1139       template_options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{};
   1140     }
   1141 
   1142     const StringPiece actual_package = context_->GetCompilationPackage();
   1143     StringPiece output_package = context_->GetCompilationPackage();
   1144     if (options_.custom_java_package) {
   1145       // Override the output java package to the custom one.
   1146       output_package = options_.custom_java_package.value();
   1147     }
   1148 
   1149     // Generate the private symbols if required.
   1150     if (options_.private_symbols) {
   1151       packages_to_callback.push_back(options_.private_symbols.value());
   1152 
   1153       // If we defined a private symbols package, we only emit Public symbols
   1154       // to the original package, and private and public symbols to the private package.
   1155       JavaClassGeneratorOptions options = template_options;
   1156       options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
   1157       if (!WriteJavaFile(&final_table_, actual_package, options_.private_symbols.value(),
   1158                          options)) {
   1159         return false;
   1160       }
   1161     }
   1162 
   1163     // Generate copies of the original package R class but with different package names.
   1164     // This is to support non-namespaced builds.
   1165     for (const std::string& extra_package : options_.extra_java_packages) {
   1166       packages_to_callback.push_back(extra_package);
   1167 
   1168       JavaClassGeneratorOptions options = template_options;
   1169       options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
   1170       if (!WriteJavaFile(&final_table_, actual_package, extra_package, options)) {
   1171         return false;
   1172       }
   1173     }
   1174 
   1175     // Generate R classes for each package that was merged (static library).
   1176     // Use the actual package's resources only.
   1177     for (const std::string& package : table_merger_->merged_packages()) {
   1178       packages_to_callback.push_back(package);
   1179 
   1180       JavaClassGeneratorOptions options = template_options;
   1181       options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
   1182       if (!WriteJavaFile(&final_table_, package, package, options)) {
   1183         return false;
   1184       }
   1185     }
   1186 
   1187     // Generate the main public R class.
   1188     JavaClassGeneratorOptions options = template_options;
   1189 
   1190     // Only generate public symbols if we have a private package.
   1191     if (options_.private_symbols) {
   1192       options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
   1193     }
   1194 
   1195     if (options.rewrite_callback_options) {
   1196       options.rewrite_callback_options.value().packages_to_callback =
   1197           std::move(packages_to_callback);
   1198     }
   1199 
   1200     if (!WriteJavaFile(&final_table_, actual_package, output_package, options,
   1201                        options_.generate_text_symbols_path)) {
   1202       return false;
   1203     }
   1204 
   1205     return true;
   1206   }
   1207 
   1208   bool WriteManifestJavaFile(xml::XmlResource* manifest_xml) {
   1209     TRACE_CALL();
   1210     if (!options_.generate_java_class_path) {
   1211       return true;
   1212     }
   1213 
   1214     std::unique_ptr<ClassDefinition> manifest_class =
   1215         GenerateManifestClass(context_->GetDiagnostics(), manifest_xml);
   1216 
   1217     if (!manifest_class) {
   1218       // Something bad happened, but we already logged it, so exit.
   1219       return false;
   1220     }
   1221 
   1222     if (manifest_class->empty()) {
   1223       // Empty Manifest class, no need to generate it.
   1224       return true;
   1225     }
   1226 
   1227     // Add any JavaDoc annotations to the generated class.
   1228     for (const std::string& annotation : options_.javadoc_annotations) {
   1229       std::string proper_annotation = "@";
   1230       proper_annotation += annotation;
   1231       manifest_class->GetCommentBuilder()->AppendComment(proper_annotation);
   1232     }
   1233 
   1234     const std::string package_utf8 =
   1235         options_.custom_java_package.value_or_default(context_->GetCompilationPackage());
   1236 
   1237     std::string out_path = options_.generate_java_class_path.value();
   1238     file::AppendPath(&out_path, file::PackageToPath(package_utf8));
   1239 
   1240     if (!file::mkdirs(out_path)) {
   1241       context_->GetDiagnostics()->Error(DiagMessage() << "failed to create directory '" << out_path
   1242                                                       << "'");
   1243       return false;
   1244     }
   1245 
   1246     file::AppendPath(&out_path, "Manifest.java");
   1247 
   1248     io::FileOutputStream fout(out_path);
   1249     if (fout.HadError()) {
   1250       context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
   1251                                                       << "': " << fout.GetError());
   1252       return false;
   1253     }
   1254 
   1255     ClassDefinition::WriteJavaFile(manifest_class.get(), package_utf8, true, &fout);
   1256     fout.Flush();
   1257 
   1258     if (fout.HadError()) {
   1259       context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
   1260                                                       << "': " << fout.GetError());
   1261       return false;
   1262     }
   1263     return true;
   1264   }
   1265 
   1266   bool WriteProguardFile(const Maybe<std::string>& out, const proguard::KeepSet& keep_set) {
   1267     TRACE_CALL();
   1268     if (!out) {
   1269       return true;
   1270     }
   1271 
   1272     const std::string& out_path = out.value();
   1273     io::FileOutputStream fout(out_path);
   1274     if (fout.HadError()) {
   1275       context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
   1276                                                       << "': " << fout.GetError());
   1277       return false;
   1278     }
   1279 
   1280     proguard::WriteKeepSet(keep_set, &fout, options_.generate_minimal_proguard_rules);
   1281     fout.Flush();
   1282 
   1283     if (fout.HadError()) {
   1284       context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
   1285                                                       << "': " << fout.GetError());
   1286       return false;
   1287     }
   1288     return true;
   1289   }
   1290 
   1291   bool MergeStaticLibrary(const std::string& input, bool override) {
   1292     TRACE_CALL();
   1293     if (context_->IsVerbose()) {
   1294       context_->GetDiagnostics()->Note(DiagMessage() << "merging static library " << input);
   1295     }
   1296 
   1297     std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(input, context_->GetDiagnostics());
   1298     if (apk == nullptr) {
   1299       context_->GetDiagnostics()->Error(DiagMessage(input) << "invalid static library");
   1300       return false;
   1301     }
   1302 
   1303     ResourceTable* table = apk->GetResourceTable();
   1304     ResourceTablePackage* pkg = table->FindPackageById(kAppPackageId);
   1305     if (!pkg) {
   1306       context_->GetDiagnostics()->Error(DiagMessage(input) << "static library has no package");
   1307       return false;
   1308     }
   1309 
   1310     bool result;
   1311     if (options_.no_static_lib_packages) {
   1312       // Merge all resources as if they were in the compilation package. This is the old behavior
   1313       // of aapt.
   1314 
   1315       // Add the package to the set of --extra-packages so we emit an R.java for each library
   1316       // package.
   1317       if (!pkg->name.empty()) {
   1318         options_.extra_java_packages.insert(pkg->name);
   1319       }
   1320 
   1321       // Clear the package name, so as to make the resources look like they are coming from the
   1322       // local package.
   1323       pkg->name = "";
   1324       result = table_merger_->Merge(Source(input), table, override);
   1325 
   1326     } else {
   1327       // This is the proper way to merge libraries, where the package name is
   1328       // preserved and resource names are mangled.
   1329       result = table_merger_->MergeAndMangle(Source(input), pkg->name, table);
   1330     }
   1331 
   1332     if (!result) {
   1333       return false;
   1334     }
   1335 
   1336     // Make sure to move the collection into the set of IFileCollections.
   1337     merged_apks_.push_back(std::move(apk));
   1338     return true;
   1339   }
   1340 
   1341   bool MergeExportedSymbols(const Source& source,
   1342                             const std::vector<SourcedResourceName>& exported_symbols) {
   1343     TRACE_CALL();
   1344     // Add the exports of this file to the table.
   1345     for (const SourcedResourceName& exported_symbol : exported_symbols) {
   1346       ResourceName res_name = exported_symbol.name;
   1347       if (res_name.package.empty()) {
   1348         res_name.package = context_->GetCompilationPackage();
   1349       }
   1350 
   1351       Maybe<ResourceName> mangled_name = context_->GetNameMangler()->MangleName(res_name);
   1352       if (mangled_name) {
   1353         res_name = mangled_name.value();
   1354       }
   1355 
   1356       std::unique_ptr<Id> id = util::make_unique<Id>();
   1357       id->SetSource(source.WithLine(exported_symbol.line));
   1358       bool result =
   1359           final_table_.AddResourceMangled(res_name, ConfigDescription::DefaultConfig(),
   1360                                           std::string(), std::move(id), context_->GetDiagnostics());
   1361       if (!result) {
   1362         return false;
   1363       }
   1364     }
   1365     return true;
   1366   }
   1367 
   1368   bool MergeCompiledFile(const ResourceFile& compiled_file, io::IFile* file, bool override) {
   1369     TRACE_CALL();
   1370     if (context_->IsVerbose()) {
   1371       context_->GetDiagnostics()->Note(DiagMessage()
   1372                                        << "merging '" << compiled_file.name
   1373                                        << "' from compiled file " << compiled_file.source);
   1374     }
   1375 
   1376     if (!table_merger_->MergeFile(compiled_file, override, file)) {
   1377       return false;
   1378     }
   1379     return MergeExportedSymbols(compiled_file.source, compiled_file.exported_symbols);
   1380   }
   1381 
   1382   // Takes a path to load as a ZIP file and merges the files within into the master ResourceTable.
   1383   // If override is true, conflicting resources are allowed to override each other, in order of last
   1384   // seen.
   1385   // An io::IFileCollection is created from the ZIP file and added to the set of
   1386   // io::IFileCollections that are open.
   1387   bool MergeArchive(const std::string& input, bool override) {
   1388     TRACE_CALL();
   1389     if (context_->IsVerbose()) {
   1390       context_->GetDiagnostics()->Note(DiagMessage() << "merging archive " << input);
   1391     }
   1392 
   1393     std::string error_str;
   1394     std::unique_ptr<io::ZipFileCollection> collection =
   1395         io::ZipFileCollection::Create(input, &error_str);
   1396     if (!collection) {
   1397       context_->GetDiagnostics()->Error(DiagMessage(input) << error_str);
   1398       return false;
   1399     }
   1400 
   1401     bool error = false;
   1402     for (auto iter = collection->Iterator(); iter->HasNext();) {
   1403       if (!MergeFile(iter->Next(), override)) {
   1404         error = true;
   1405       }
   1406     }
   1407 
   1408     // Make sure to move the collection into the set of IFileCollections.
   1409     collections_.push_back(std::move(collection));
   1410     return !error;
   1411   }
   1412 
   1413   // Takes a path to load and merge into the master ResourceTable. If override is true,
   1414   // conflicting resources are allowed to override each other, in order of last seen.
   1415   // If the file path ends with .flata, .jar, .jack, or .zip the file is treated
   1416   // as ZIP archive and the files within are merged individually.
   1417   // Otherwise the file is processed on its own.
   1418   bool MergePath(const std::string& path, bool override) {
   1419     if (util::EndsWith(path, ".flata") || util::EndsWith(path, ".jar") ||
   1420         util::EndsWith(path, ".jack") || util::EndsWith(path, ".zip")) {
   1421       return MergeArchive(path, override);
   1422     } else if (util::EndsWith(path, ".apk")) {
   1423       return MergeStaticLibrary(path, override);
   1424     }
   1425 
   1426     io::IFile* file = file_collection_->InsertFile(path);
   1427     return MergeFile(file, override);
   1428   }
   1429 
   1430   // Takes an AAPT Container file (.apc/.flat) to load and merge into the master ResourceTable.
   1431   // If override is true, conflicting resources are allowed to override each other, in order of last
   1432   // seen.
   1433   // All other file types are ignored. This is because these files could be coming from a zip,
   1434   // where we could have other files like classes.dex.
   1435   bool MergeFile(io::IFile* file, bool override) {
   1436     TRACE_CALL();
   1437     const Source& src = file->GetSource();
   1438 
   1439     if (util::EndsWith(src.path, ".xml") || util::EndsWith(src.path, ".png")) {
   1440       // Since AAPT compiles these file types and appends .flat to them, seeing
   1441       // their raw extensions is a sign that they weren't compiled.
   1442       const StringPiece file_type = util::EndsWith(src.path, ".xml") ? "XML" : "PNG";
   1443       context_->GetDiagnostics()->Error(DiagMessage(src) << "uncompiled " << file_type
   1444                                                          << " file passed as argument. Must be "
   1445                                                             "compiled first into .flat file.");
   1446       return false;
   1447     } else if (!util::EndsWith(src.path, ".apc") && !util::EndsWith(src.path, ".flat")) {
   1448       if (context_->IsVerbose()) {
   1449         context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring unrecognized file");
   1450         return true;
   1451       }
   1452     }
   1453 
   1454     std::unique_ptr<io::InputStream> input_stream = file->OpenInputStream();
   1455     if (input_stream == nullptr) {
   1456       context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to open file");
   1457       return false;
   1458     }
   1459 
   1460     if (input_stream->HadError()) {
   1461       context_->GetDiagnostics()->Error(DiagMessage(src)
   1462                                         << "failed to open file: " << input_stream->GetError());
   1463       return false;
   1464     }
   1465 
   1466     ContainerReaderEntry* entry;
   1467     ContainerReader reader(input_stream.get());
   1468 
   1469     if (reader.HadError()) {
   1470       context_->GetDiagnostics()->Error(DiagMessage(src)
   1471                                         << "failed to read file: " << reader.GetError());
   1472       return false;
   1473     }
   1474 
   1475     while ((entry = reader.Next()) != nullptr) {
   1476       if (entry->Type() == ContainerEntryType::kResTable) {
   1477         TRACE_NAME(std::string("Process ResTable:") + file->GetSource().path);
   1478         pb::ResourceTable pb_table;
   1479         if (!entry->GetResTable(&pb_table)) {
   1480           context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to read resource table: "
   1481                                                              << entry->GetError());
   1482           return false;
   1483         }
   1484 
   1485         ResourceTable table;
   1486         std::string error;
   1487         if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) {
   1488           context_->GetDiagnostics()->Error(DiagMessage(src)
   1489                                             << "failed to deserialize resource table: " << error);
   1490           return false;
   1491         }
   1492 
   1493         if (!table_merger_->Merge(src, &table, override)) {
   1494           context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to merge resource table");
   1495           return false;
   1496         }
   1497       } else if (entry->Type() == ContainerEntryType::kResFile) {
   1498         TRACE_NAME(std::string("Process ResFile") + file->GetSource().path);
   1499         pb::internal::CompiledFile pb_compiled_file;
   1500         off64_t offset;
   1501         size_t len;
   1502         if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &len)) {
   1503           context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to get resource file: "
   1504                                                              << entry->GetError());
   1505           return false;
   1506         }
   1507 
   1508         ResourceFile resource_file;
   1509         std::string error;
   1510         if (!DeserializeCompiledFileFromPb(pb_compiled_file, &resource_file, &error)) {
   1511           context_->GetDiagnostics()->Error(DiagMessage(src)
   1512                                             << "failed to read compiled header: " << error);
   1513           return false;
   1514         }
   1515 
   1516         if (!MergeCompiledFile(resource_file, file->CreateFileSegment(offset, len), override)) {
   1517           return false;
   1518         }
   1519       }
   1520     }
   1521     return true;
   1522   }
   1523 
   1524   bool CopyAssetsDirsToApk(IArchiveWriter* writer) {
   1525     std::map<std::string, std::unique_ptr<io::RegularFile>> merged_assets;
   1526     for (const std::string& assets_dir : options_.assets_dirs) {
   1527       Maybe<std::vector<std::string>> files =
   1528           file::FindFiles(assets_dir, context_->GetDiagnostics(), nullptr);
   1529       if (!files) {
   1530         return false;
   1531       }
   1532 
   1533       for (const std::string& file : files.value()) {
   1534         std::string full_key = "assets/" + file;
   1535         std::string full_path = assets_dir;
   1536         file::AppendPath(&full_path, file);
   1537 
   1538         auto iter = merged_assets.find(full_key);
   1539         if (iter == merged_assets.end()) {
   1540           merged_assets.emplace(std::move(full_key),
   1541                                 util::make_unique<io::RegularFile>(Source(std::move(full_path))));
   1542         } else if (context_->IsVerbose()) {
   1543           context_->GetDiagnostics()->Warn(DiagMessage(iter->second->GetSource())
   1544                                            << "asset file overrides '" << full_path << "'");
   1545         }
   1546       }
   1547     }
   1548 
   1549     for (auto& entry : merged_assets) {
   1550       uint32_t compression_flags = ArchiveEntry::kCompress;
   1551       std::string extension = file::GetExtension(entry.first).to_string();
   1552 
   1553       if (options_.do_not_compress_anything
   1554           || options_.extensions_to_not_compress.count(extension) > 0
   1555           || (options_.regex_to_not_compress
   1556               && std::regex_search(extension, options_.regex_to_not_compress.value()))) {
   1557         compression_flags = 0u;
   1558       }
   1559 
   1560       if (!io::CopyFileToArchive(context_, entry.second.get(), entry.first, compression_flags,
   1561                                  writer)) {
   1562         return false;
   1563       }
   1564     }
   1565     return true;
   1566   }
   1567 
   1568   // Writes the AndroidManifest, ResourceTable, and all XML files referenced by the ResourceTable
   1569   // to the IArchiveWriter.
   1570   bool WriteApk(IArchiveWriter* writer, proguard::KeepSet* keep_set, xml::XmlResource* manifest,
   1571                 ResourceTable* table) {
   1572     TRACE_CALL();
   1573     const bool keep_raw_values = (context_->GetPackageType() == PackageType::kStaticLib)
   1574                                  || options_.keep_raw_values;
   1575     bool result = FlattenXml(context_, *manifest, kAndroidManifestPath, keep_raw_values,
   1576                              true /*utf16*/, options_.output_format, writer);
   1577     if (!result) {
   1578       return false;
   1579     }
   1580 
   1581     ResourceFileFlattenerOptions file_flattener_options;
   1582     file_flattener_options.keep_raw_values = keep_raw_values;
   1583     file_flattener_options.do_not_compress_anything = options_.do_not_compress_anything;
   1584     file_flattener_options.extensions_to_not_compress = options_.extensions_to_not_compress;
   1585     file_flattener_options.regex_to_not_compress = options_.regex_to_not_compress;
   1586     file_flattener_options.no_auto_version = options_.no_auto_version;
   1587     file_flattener_options.no_version_vectors = options_.no_version_vectors;
   1588     file_flattener_options.no_version_transitions = options_.no_version_transitions;
   1589     file_flattener_options.no_xml_namespaces = options_.no_xml_namespaces;
   1590     file_flattener_options.update_proguard_spec =
   1591         static_cast<bool>(options_.generate_proguard_rules_path);
   1592     file_flattener_options.output_format = options_.output_format;
   1593 
   1594     ResourceFileFlattener file_flattener(file_flattener_options, context_, keep_set);
   1595 
   1596     if (!file_flattener.Flatten(table, writer)) {
   1597       context_->GetDiagnostics()->Error(DiagMessage() << "failed linking file resources");
   1598       return false;
   1599     }
   1600 
   1601     // Hack to fix b/68820737.
   1602     // We need to modify the ResourceTable's package name, but that should NOT affect
   1603     // anything else being generated, which includes the Java classes.
   1604     // If required, the package name is modifed before flattening, and then modified back
   1605     // to its original name.
   1606     ResourceTablePackage* package_to_rewrite = nullptr;
   1607     // Pre-O, the platform treats negative resource IDs [those with a package ID of 0x80
   1608     // or higher] as invalid. In order to work around this limitation, we allow the use
   1609     // of traditionally reserved resource IDs [those between 0x02 and 0x7E]. Allow the
   1610     // definition of what a valid "split" package ID is to account for this.
   1611     const bool isSplitPackage = (options_.allow_reserved_package_id &&
   1612           context_->GetPackageId() != kAppPackageId &&
   1613           context_->GetPackageId() != kFrameworkPackageId)
   1614         || (!options_.allow_reserved_package_id && context_->GetPackageId() > kAppPackageId);
   1615     if (isSplitPackage &&
   1616         included_feature_base_ == make_value(context_->GetCompilationPackage())) {
   1617       // The base APK is included, and this is a feature split. If the base package is
   1618       // the same as this package, then we are building an old style Android Instant Apps feature
   1619       // split and must apply this workaround to avoid requiring namespaces support.
   1620       package_to_rewrite = table->FindPackage(context_->GetCompilationPackage());
   1621       if (package_to_rewrite != nullptr) {
   1622         CHECK_EQ(1u, table->packages.size()) << "can't change name of package when > 1 package";
   1623 
   1624         std::string new_package_name =
   1625             StringPrintf("%s.%s", package_to_rewrite->name.c_str(),
   1626                          app_info_.split_name.value_or_default("feature").c_str());
   1627 
   1628         if (context_->IsVerbose()) {
   1629           context_->GetDiagnostics()->Note(
   1630               DiagMessage() << "rewriting resource package name for feature split to '"
   1631                             << new_package_name << "'");
   1632         }
   1633         package_to_rewrite->name = new_package_name;
   1634       }
   1635     }
   1636 
   1637     bool success = FlattenTable(table, options_.output_format, writer);
   1638 
   1639     if (package_to_rewrite != nullptr) {
   1640       // Change the name back.
   1641       package_to_rewrite->name = context_->GetCompilationPackage();
   1642       if (package_to_rewrite->id) {
   1643         table->included_packages_.erase(package_to_rewrite->id.value());
   1644       }
   1645     }
   1646 
   1647     if (!success) {
   1648       context_->GetDiagnostics()->Error(DiagMessage() << "failed to write resource table");
   1649     }
   1650     return success;
   1651   }
   1652 
   1653   int Run(const std::vector<std::string>& input_files) {
   1654     TRACE_CALL();
   1655     // Load the AndroidManifest.xml
   1656     std::unique_ptr<xml::XmlResource> manifest_xml =
   1657         LoadXml(options_.manifest_path, context_->GetDiagnostics());
   1658     if (!manifest_xml) {
   1659       return 1;
   1660     }
   1661 
   1662     // First extract the Package name without modifying it (via --rename-manifest-package).
   1663     if (Maybe<AppInfo> maybe_app_info =
   1664             ExtractAppInfoFromManifest(manifest_xml.get(), context_->GetDiagnostics())) {
   1665       const AppInfo& app_info = maybe_app_info.value();
   1666       context_->SetCompilationPackage(app_info.package);
   1667     }
   1668 
   1669     // Now that the compilation package is set, load the dependencies. This will also extract
   1670     // the Android framework's versionCode and versionName, if they exist.
   1671     if (!LoadSymbolsFromIncludePaths()) {
   1672       return 1;
   1673     }
   1674 
   1675     ManifestFixer manifest_fixer(options_.manifest_fixer_options);
   1676     if (!manifest_fixer.Consume(context_, manifest_xml.get())) {
   1677       return 1;
   1678     }
   1679 
   1680     Maybe<AppInfo> maybe_app_info =
   1681         ExtractAppInfoFromManifest(manifest_xml.get(), context_->GetDiagnostics());
   1682     if (!maybe_app_info) {
   1683       return 1;
   1684     }
   1685 
   1686     app_info_ = maybe_app_info.value();
   1687     context_->SetMinSdkVersion(app_info_.min_sdk_version.value_or_default(0));
   1688 
   1689     context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()});
   1690 
   1691     // Override the package ID when it is "android".
   1692     if (context_->GetCompilationPackage() == "android") {
   1693       context_->SetPackageId(0x01);
   1694 
   1695       // Verify we're building a regular app.
   1696       if (context_->GetPackageType() != PackageType::kApp) {
   1697         context_->GetDiagnostics()->Error(
   1698             DiagMessage() << "package 'android' can only be built as a regular app");
   1699         return 1;
   1700       }
   1701     }
   1702 
   1703     TableMergerOptions table_merger_options;
   1704     table_merger_options.auto_add_overlay = options_.auto_add_overlay;
   1705     table_merger_options.strict_visibility = options_.strict_visibility;
   1706     table_merger_ = util::make_unique<TableMerger>(context_, &final_table_, table_merger_options);
   1707 
   1708     if (context_->IsVerbose()) {
   1709       context_->GetDiagnostics()->Note(DiagMessage()
   1710                                        << StringPrintf("linking package '%s' using package ID %02x",
   1711                                                        context_->GetCompilationPackage().data(),
   1712                                                        context_->GetPackageId()));
   1713     }
   1714 
   1715     // Extract symbols from AndroidManifest.xml, since this isn't merged like the other XML files
   1716     // in res/**/*.
   1717     {
   1718       XmlIdCollector collector;
   1719       if (!collector.Consume(context_, manifest_xml.get())) {
   1720         return false;
   1721       }
   1722 
   1723       if (!MergeExportedSymbols(manifest_xml->file.source, manifest_xml->file.exported_symbols)) {
   1724         return false;
   1725       }
   1726     }
   1727 
   1728     for (const std::string& input : input_files) {
   1729       if (!MergePath(input, false)) {
   1730         context_->GetDiagnostics()->Error(DiagMessage() << "failed parsing input");
   1731         return 1;
   1732       }
   1733     }
   1734 
   1735     for (const std::string& input : options_.overlay_files) {
   1736       if (!MergePath(input, true)) {
   1737         context_->GetDiagnostics()->Error(DiagMessage() << "failed parsing overlays");
   1738         return 1;
   1739       }
   1740     }
   1741 
   1742     if (!VerifyNoExternalPackages()) {
   1743       return 1;
   1744     }
   1745 
   1746     if (context_->GetPackageType() != PackageType::kStaticLib) {
   1747       PrivateAttributeMover mover;
   1748       if (!mover.Consume(context_, &final_table_)) {
   1749         context_->GetDiagnostics()->Error(DiagMessage() << "failed moving private attributes");
   1750         return 1;
   1751       }
   1752 
   1753       // Assign IDs if we are building a regular app.
   1754       IdAssigner id_assigner(&options_.stable_id_map);
   1755       if (!id_assigner.Consume(context_, &final_table_)) {
   1756         context_->GetDiagnostics()->Error(DiagMessage() << "failed assigning IDs");
   1757         return 1;
   1758       }
   1759 
   1760       // Now grab each ID and emit it as a file.
   1761       if (options_.resource_id_map_path) {
   1762         for (auto& package : final_table_.packages) {
   1763           for (auto& type : package->types) {
   1764             for (auto& entry : type->entries) {
   1765               ResourceName name(package->name, type->type, entry->name);
   1766               // The IDs are guaranteed to exist.
   1767               options_.stable_id_map[std::move(name)] =
   1768                   ResourceId(package->id.value(), type->id.value(), entry->id.value());
   1769             }
   1770           }
   1771         }
   1772 
   1773         if (!WriteStableIdMapToPath(context_->GetDiagnostics(), options_.stable_id_map,
   1774                                     options_.resource_id_map_path.value())) {
   1775           return 1;
   1776         }
   1777       }
   1778     } else {
   1779       // Static libs are merged with other apps, and ID collisions are bad, so
   1780       // verify that
   1781       // no IDs have been set.
   1782       if (!VerifyNoIdsSet()) {
   1783         return 1;
   1784       }
   1785     }
   1786 
   1787     // Add the names to mangle based on our source merge earlier.
   1788     context_->SetNameManglerPolicy(
   1789         NameManglerPolicy{context_->GetCompilationPackage(), table_merger_->merged_packages()});
   1790 
   1791     // Add our table to the symbol table.
   1792     context_->GetExternalSymbols()->PrependSource(
   1793         util::make_unique<ResourceTableSymbolSource>(&final_table_));
   1794 
   1795     // Workaround for pre-O runtime that would treat negative resource IDs
   1796     // (any ID with a package ID > 7f) as invalid. Intercept any ID (PPTTEEEE) with PP > 0x7f
   1797     // and type == 'id', and return the ID 0x7fPPEEEE. IDs don't need to be real resources, they
   1798     // are just identifiers.
   1799     if (context_->GetMinSdkVersion() < SDK_O && context_->GetPackageType() == PackageType::kApp) {
   1800       if (context_->IsVerbose()) {
   1801         context_->GetDiagnostics()->Note(DiagMessage()
   1802                                          << "enabling pre-O feature split ID rewriting");
   1803       }
   1804       context_->GetExternalSymbols()->SetDelegate(
   1805           util::make_unique<FeatureSplitSymbolTableDelegate>(context_));
   1806     }
   1807 
   1808     // Before we process anything, remove the resources whose default values don't exist.
   1809     // We want to force any references to these to fail the build.
   1810     if (!options_.no_resource_removal) {
   1811       if (!NoDefaultResourceRemover{}.Consume(context_, &final_table_)) {
   1812         context_->GetDiagnostics()->Error(DiagMessage()
   1813                                           << "failed removing resources with no defaults");
   1814         return 1;
   1815       }
   1816     }
   1817 
   1818     ReferenceLinker linker;
   1819     if (!linker.Consume(context_, &final_table_)) {
   1820       context_->GetDiagnostics()->Error(DiagMessage() << "failed linking references");
   1821       return 1;
   1822     }
   1823 
   1824     if (context_->GetPackageType() == PackageType::kStaticLib) {
   1825       if (!options_.products.empty()) {
   1826         context_->GetDiagnostics()->Warn(DiagMessage()
   1827                                          << "can't select products when building static library");
   1828       }
   1829     } else {
   1830       ProductFilter product_filter(options_.products);
   1831       if (!product_filter.Consume(context_, &final_table_)) {
   1832         context_->GetDiagnostics()->Error(DiagMessage() << "failed stripping products");
   1833         return 1;
   1834       }
   1835     }
   1836 
   1837     if (!options_.no_auto_version) {
   1838       AutoVersioner versioner;
   1839       if (!versioner.Consume(context_, &final_table_)) {
   1840         context_->GetDiagnostics()->Error(DiagMessage() << "failed versioning styles");
   1841         return 1;
   1842       }
   1843     }
   1844 
   1845     if (context_->GetPackageType() != PackageType::kStaticLib && context_->GetMinSdkVersion() > 0) {
   1846       if (context_->IsVerbose()) {
   1847         context_->GetDiagnostics()->Note(DiagMessage()
   1848                                          << "collapsing resource versions for minimum SDK "
   1849                                          << context_->GetMinSdkVersion());
   1850       }
   1851 
   1852       VersionCollapser collapser;
   1853       if (!collapser.Consume(context_, &final_table_)) {
   1854         return 1;
   1855       }
   1856     }
   1857 
   1858     if (!options_.exclude_configs_.empty()) {
   1859       std::vector<ConfigDescription> excluded_configs;
   1860 
   1861       for (auto& config_string : options_.exclude_configs_) {
   1862         TRACE_NAME("ConfigDescription::Parse");
   1863         ConfigDescription config_description;
   1864 
   1865         if (!ConfigDescription::Parse(config_string, &config_description)) {
   1866           context_->GetDiagnostics()->Error(DiagMessage()
   1867                                                 << "failed to parse --excluded-configs "
   1868                                                 << config_string);
   1869           return 1;
   1870         }
   1871 
   1872         excluded_configs.push_back(config_description);
   1873       }
   1874 
   1875       ResourceExcluder excluder(excluded_configs);
   1876       if (!excluder.Consume(context_, &final_table_)) {
   1877         context_->GetDiagnostics()->Error(DiagMessage() << "failed excluding configurations");
   1878         return 1;
   1879       }
   1880     }
   1881 
   1882     if (!options_.no_resource_deduping) {
   1883       ResourceDeduper deduper;
   1884       if (!deduper.Consume(context_, &final_table_)) {
   1885         context_->GetDiagnostics()->Error(DiagMessage() << "failed deduping resources");
   1886         return 1;
   1887       }
   1888     }
   1889 
   1890     proguard::KeepSet proguard_keep_set =
   1891         proguard::KeepSet(options_.generate_conditional_proguard_rules);
   1892     proguard::KeepSet proguard_main_dex_keep_set;
   1893 
   1894     if (context_->GetPackageType() == PackageType::kStaticLib) {
   1895       if (options_.table_splitter_options.config_filter != nullptr ||
   1896           !options_.table_splitter_options.preferred_densities.empty()) {
   1897         context_->GetDiagnostics()->Warn(DiagMessage()
   1898                                          << "can't strip resources when building static library");
   1899       }
   1900     } else {
   1901       // Adjust the SplitConstraints so that their SDK version is stripped if it is less than or
   1902       // equal to the minSdk.
   1903       const size_t origConstraintSize = options_.split_constraints.size();
   1904       options_.split_constraints =
   1905           AdjustSplitConstraintsForMinSdk(context_->GetMinSdkVersion(), options_.split_constraints);
   1906 
   1907       if (origConstraintSize != options_.split_constraints.size()) {
   1908         context_->GetDiagnostics()->Warn(DiagMessage()
   1909                                          << "requested to split resources prior to min sdk of "
   1910                                          << context_->GetMinSdkVersion());
   1911       }
   1912       TableSplitter table_splitter(options_.split_constraints, options_.table_splitter_options);
   1913       if (!table_splitter.VerifySplitConstraints(context_)) {
   1914         return 1;
   1915       }
   1916       table_splitter.SplitTable(&final_table_);
   1917 
   1918       // Now we need to write out the Split APKs.
   1919       auto path_iter = options_.split_paths.begin();
   1920       auto split_constraints_iter = options_.split_constraints.begin();
   1921       for (std::unique_ptr<ResourceTable>& split_table : table_splitter.splits()) {
   1922         if (context_->IsVerbose()) {
   1923           context_->GetDiagnostics()->Note(DiagMessage(*path_iter)
   1924                                            << "generating split with configurations '"
   1925                                            << util::Joiner(split_constraints_iter->configs, ", ")
   1926                                            << "'");
   1927         }
   1928 
   1929         std::unique_ptr<IArchiveWriter> archive_writer = MakeArchiveWriter(*path_iter);
   1930         if (!archive_writer) {
   1931           context_->GetDiagnostics()->Error(DiagMessage() << "failed to create archive");
   1932           return 1;
   1933         }
   1934 
   1935         // Generate an AndroidManifest.xml for each split.
   1936         std::unique_ptr<xml::XmlResource> split_manifest =
   1937             GenerateSplitManifest(app_info_, *split_constraints_iter);
   1938 
   1939         XmlReferenceLinker linker;
   1940         if (!linker.Consume(context_, split_manifest.get())) {
   1941           context_->GetDiagnostics()->Error(DiagMessage()
   1942                                             << "failed to create Split AndroidManifest.xml");
   1943           return 1;
   1944         }
   1945 
   1946         if (!WriteApk(archive_writer.get(), &proguard_keep_set, split_manifest.get(),
   1947                       split_table.get())) {
   1948           return 1;
   1949         }
   1950 
   1951         ++path_iter;
   1952         ++split_constraints_iter;
   1953       }
   1954     }
   1955 
   1956     // Start writing the base APK.
   1957     std::unique_ptr<IArchiveWriter> archive_writer = MakeArchiveWriter(options_.output_path);
   1958     if (!archive_writer) {
   1959       context_->GetDiagnostics()->Error(DiagMessage() << "failed to create archive");
   1960       return 1;
   1961     }
   1962 
   1963     bool error = false;
   1964     {
   1965       // AndroidManifest.xml has no resource name, but the CallSite is built from the name
   1966       // (aka, which package the AndroidManifest.xml is coming from).
   1967       // So we give it a package name so it can see local resources.
   1968       manifest_xml->file.name.package = context_->GetCompilationPackage();
   1969 
   1970       XmlReferenceLinker manifest_linker;
   1971       if (manifest_linker.Consume(context_, manifest_xml.get())) {
   1972         if (options_.generate_proguard_rules_path &&
   1973             !proguard::CollectProguardRulesForManifest(manifest_xml.get(), &proguard_keep_set)) {
   1974           error = true;
   1975         }
   1976 
   1977         if (options_.generate_main_dex_proguard_rules_path &&
   1978             !proguard::CollectProguardRulesForManifest(manifest_xml.get(),
   1979                                                        &proguard_main_dex_keep_set, true)) {
   1980           error = true;
   1981         }
   1982 
   1983         if (options_.generate_java_class_path) {
   1984           if (!WriteManifestJavaFile(manifest_xml.get())) {
   1985             error = true;
   1986           }
   1987         }
   1988 
   1989         if (options_.no_xml_namespaces) {
   1990           // PackageParser will fail if URIs are removed from
   1991           // AndroidManifest.xml.
   1992           XmlNamespaceRemover namespace_remover(true /* keepUris */);
   1993           if (!namespace_remover.Consume(context_, manifest_xml.get())) {
   1994             error = true;
   1995           }
   1996         }
   1997       } else {
   1998         error = true;
   1999       }
   2000     }
   2001 
   2002     if (error) {
   2003       context_->GetDiagnostics()->Error(DiagMessage() << "failed processing manifest");
   2004       return 1;
   2005     }
   2006 
   2007     if (!WriteApk(archive_writer.get(), &proguard_keep_set, manifest_xml.get(), &final_table_)) {
   2008       return 1;
   2009     }
   2010 
   2011     if (!CopyAssetsDirsToApk(archive_writer.get())) {
   2012       return 1;
   2013     }
   2014 
   2015     if (options_.generate_java_class_path || options_.generate_text_symbols_path) {
   2016       if (!GenerateJavaClasses()) {
   2017         return 1;
   2018       }
   2019     }
   2020 
   2021     if (!WriteProguardFile(options_.generate_proguard_rules_path, proguard_keep_set)) {
   2022       return 1;
   2023     }
   2024 
   2025     if (!WriteProguardFile(options_.generate_main_dex_proguard_rules_path,
   2026                            proguard_main_dex_keep_set)) {
   2027       return 1;
   2028     }
   2029     return 0;
   2030   }
   2031 
   2032  private:
   2033   LinkOptions options_;
   2034   LinkContext* context_;
   2035   ResourceTable final_table_;
   2036 
   2037   AppInfo app_info_;
   2038 
   2039   std::unique_ptr<TableMerger> table_merger_;
   2040 
   2041   // A pointer to the FileCollection representing the filesystem (not archives).
   2042   std::unique_ptr<io::FileCollection> file_collection_;
   2043 
   2044   // A vector of IFileCollections. This is mainly here to retain ownership of the
   2045   // collections.
   2046   std::vector<std::unique_ptr<io::IFileCollection>> collections_;
   2047 
   2048   // The set of merged APKs. This is mainly here to retain ownership of the APKs.
   2049   std::vector<std::unique_ptr<LoadedApk>> merged_apks_;
   2050 
   2051   // The set of included APKs (not merged). This is mainly here to retain ownership of the APKs.
   2052   std::vector<std::unique_ptr<LoadedApk>> static_library_includes_;
   2053 
   2054   // The set of shared libraries being used, mapping their assigned package ID to package name.
   2055   std::map<size_t, std::string> shared_libs_;
   2056 
   2057   // The package name of the base application, if it is included.
   2058   Maybe<std::string> included_feature_base_;
   2059 };
   2060 
   2061 int LinkCommand::Action(const std::vector<std::string>& args) {
   2062   TRACE_FLUSH(trace_folder_ ? trace_folder_.value() : "", "LinkCommand::Action");
   2063   LinkContext context(diag_);
   2064 
   2065   // Expand all argument-files passed into the command line. These start with '@'.
   2066   std::vector<std::string> arg_list;
   2067   for (const std::string& arg : args) {
   2068     if (util::StartsWith(arg, "@")) {
   2069       const std::string path = arg.substr(1, arg.size() - 1);
   2070       std::string error;
   2071       if (!file::AppendArgsFromFile(path, &arg_list, &error)) {
   2072         context.GetDiagnostics()->Error(DiagMessage(path) << error);
   2073         return 1;
   2074       }
   2075     } else {
   2076       arg_list.push_back(arg);
   2077     }
   2078   }
   2079 
   2080   // Expand all argument-files passed to -R.
   2081   for (const std::string& arg : overlay_arg_list_) {
   2082     if (util::StartsWith(arg, "@")) {
   2083       const std::string path = arg.substr(1, arg.size() - 1);
   2084       std::string error;
   2085       if (!file::AppendArgsFromFile(path, &options_.overlay_files, &error)) {
   2086         context.GetDiagnostics()->Error(DiagMessage(path) << error);
   2087         return 1;
   2088       }
   2089     } else {
   2090       options_.overlay_files.push_back(arg);
   2091     }
   2092   }
   2093 
   2094   if (verbose_) {
   2095     context.SetVerbose(verbose_);
   2096   }
   2097 
   2098   if (int{shared_lib_} + int{static_lib_} + int{proto_format_} > 1) {
   2099     context.GetDiagnostics()->Error(
   2100         DiagMessage()
   2101             << "only one of --shared-lib, --static-lib, or --proto_format can be defined");
   2102     return 1;
   2103   }
   2104 
   2105   // The default build type.
   2106   context.SetPackageType(PackageType::kApp);
   2107   context.SetPackageId(kAppPackageId);
   2108 
   2109   if (shared_lib_) {
   2110     context.SetPackageType(PackageType::kSharedLib);
   2111     context.SetPackageId(0x00);
   2112   } else if (static_lib_) {
   2113     context.SetPackageType(PackageType::kStaticLib);
   2114     options_.output_format = OutputFormat::kProto;
   2115   } else if (proto_format_) {
   2116     options_.output_format = OutputFormat::kProto;
   2117   }
   2118 
   2119   if (package_id_) {
   2120     if (context.GetPackageType() != PackageType::kApp) {
   2121       context.GetDiagnostics()->Error(
   2122           DiagMessage() << "can't specify --package-id when not building a regular app");
   2123       return 1;
   2124     }
   2125 
   2126     const Maybe<uint32_t> maybe_package_id_int = ResourceUtils::ParseInt(package_id_.value());
   2127     if (!maybe_package_id_int) {
   2128       context.GetDiagnostics()->Error(DiagMessage() << "package ID '" << package_id_.value()
   2129                                                     << "' is not a valid integer");
   2130       return 1;
   2131     }
   2132 
   2133     const uint32_t package_id_int = maybe_package_id_int.value();
   2134     if (package_id_int > std::numeric_limits<uint8_t>::max()
   2135         || package_id_int == kFrameworkPackageId
   2136         || (!options_.allow_reserved_package_id && package_id_int < kAppPackageId)) {
   2137       context.GetDiagnostics()->Error(
   2138           DiagMessage() << StringPrintf(
   2139               "invalid package ID 0x%02x. Must be in the range 0x7f-0xff.", package_id_int));
   2140       return 1;
   2141     }
   2142     context.SetPackageId(static_cast<uint8_t>(package_id_int));
   2143   }
   2144 
   2145   // Populate the set of extra packages for which to generate R.java.
   2146   for (std::string& extra_package : extra_java_packages_) {
   2147     // A given package can actually be a colon separated list of packages.
   2148     for (StringPiece package : util::Split(extra_package, ':')) {
   2149       options_.extra_java_packages.insert(package.to_string());
   2150     }
   2151   }
   2152 
   2153   if (product_list_) {
   2154     for (StringPiece product : util::Tokenize(product_list_.value(), ',')) {
   2155       if (product != "" && product != "default") {
   2156         options_.products.insert(product.to_string());
   2157       }
   2158     }
   2159   }
   2160 
   2161   std::unique_ptr<IConfigFilter> filter;
   2162   if (!configs_.empty()) {
   2163     filter = ParseConfigFilterParameters(configs_, context.GetDiagnostics());
   2164     if (filter == nullptr) {
   2165       return 1;
   2166     }
   2167     options_.table_splitter_options.config_filter = filter.get();
   2168   }
   2169 
   2170   if (preferred_density_) {
   2171     Maybe<uint16_t> density =
   2172         ParseTargetDensityParameter(preferred_density_.value(), context.GetDiagnostics());
   2173     if (!density) {
   2174       return 1;
   2175     }
   2176     options_.table_splitter_options.preferred_densities.push_back(density.value());
   2177   }
   2178 
   2179   // Parse the split parameters.
   2180   for (const std::string& split_arg : split_args_) {
   2181     options_.split_paths.push_back({});
   2182     options_.split_constraints.push_back({});
   2183     if (!ParseSplitParameter(split_arg, context.GetDiagnostics(), &options_.split_paths.back(),
   2184         &options_.split_constraints.back())) {
   2185       return 1;
   2186     }
   2187   }
   2188 
   2189   if (context.GetPackageType() != PackageType::kStaticLib && stable_id_file_path_) {
   2190     if (!LoadStableIdMap(context.GetDiagnostics(), stable_id_file_path_.value(),
   2191         &options_.stable_id_map)) {
   2192       return 1;
   2193     }
   2194   }
   2195 
   2196   if (no_compress_regex) {
   2197     std::string regex = no_compress_regex.value();
   2198     if (util::StartsWith(regex, "@")) {
   2199       const std::string path = regex.substr(1, regex.size() -1);
   2200       std::string error;
   2201       if (!file::AppendSetArgsFromFile(path, &options_.extensions_to_not_compress, &error)) {
   2202         context.GetDiagnostics()->Error(DiagMessage(path) << error);
   2203         return 1;
   2204       }
   2205     } else {
   2206       options_.regex_to_not_compress = GetRegularExpression(no_compress_regex.value());
   2207     }
   2208   }
   2209 
   2210   // Populate some default no-compress extensions that are already compressed.
   2211   options_.extensions_to_not_compress.insert(
   2212       {".jpg",   ".jpeg", ".png",  ".gif", ".wav",  ".mp2",  ".mp3",  ".ogg",
   2213           ".aac",   ".mpg",  ".mpeg", ".mid", ".midi", ".smf",  ".jet",  ".rtttl",
   2214           ".imy",   ".xmf",  ".mp4",  ".m4a", ".m4v",  ".3gp",  ".3gpp", ".3g2",
   2215           ".3gpp2", ".amr",  ".awb",  ".wma", ".wmv",  ".webm", ".mkv"});
   2216 
   2217   // Turn off auto versioning for static-libs.
   2218   if (context.GetPackageType() == PackageType::kStaticLib) {
   2219     options_.no_auto_version = true;
   2220     options_.no_version_vectors = true;
   2221     options_.no_version_transitions = true;
   2222   }
   2223 
   2224   Linker cmd(&context, options_);
   2225   return cmd.Run(arg_list);
   2226 }
   2227 
   2228 }  // namespace aapt
   2229