Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3edd4726 authored by Shane Farmer's avatar Shane Farmer
Browse files

AAPT2: Set the minSdkVersion when generating multiple APKs.

When generating multiple APKs from a configuration file, check to see if
we have filtered resource by minSdkVersion and update the manifest to
reflect this. We only want to inflate and modify the manifest file if
there is an update to be applied.

Bug: 37944703
Bug: 67005138

Test: Ran unit tests
Test: Manually split an APK and verified the manifest by dumping with
      AAPT (both xmltree and badging).

Change-Id: I64a0e4889d7d9e57373369b044a091287b06cc35
parent 23104030
Loading
Loading
Loading
Loading
+42 −1
Original line number Diff line number Diff line
@@ -20,11 +20,15 @@
#include "ValueVisitor.h"
#include "flatten/Archive.h"
#include "flatten/TableFlattener.h"
#include "flatten/XmlFlattener.h"
#include "io/BigBufferInputStream.h"
#include "io/Util.h"
#include "xml/XmlDom.h"

namespace aapt {

using xml::XmlResource;

std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context,
                                                      const android::StringPiece& path) {
  Source source(path);
@@ -52,6 +56,7 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context,
  if (!parser.Parse()) {
    return {};
  }

  return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
}

@@ -63,7 +68,7 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOption

bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table,
                               const TableFlattenerOptions& options, FilterChain* filters,
                               IArchiveWriter* writer) {
                               IArchiveWriter* writer, XmlResource* manifest) {
  std::set<std::string> referenced_resources;
  // List the files being referenced in the resource table.
  for (auto& pkg : split_table->packages) {
@@ -119,6 +124,20 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
        return false;
      }

    } else if (manifest != nullptr && path == "AndroidManifest.xml") {
      BigBuffer buffer(8192);
      XmlFlattener xml_flattener(&buffer, {});
      if (!xml_flattener.Consume(context, manifest)) {
        context->GetDiagnostics()->Error(DiagMessage(path) << "flattening failed");
        return false;
      }

      uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
      io::BigBufferInputStream manifest_buffer_in(&buffer);
      if (!io::CopyInputStreamToArchive(context, &manifest_buffer_in, path, compression_flags,
                                        writer)) {
        return false;
      }
    } else {
      uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
      if (!io::CopyFileToArchive(context, file, path, compression_flags, writer)) {
@@ -129,4 +148,26 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
  return true;
}

std::unique_ptr<xml::XmlResource> LoadedApk::InflateManifest(IAaptContext* context) {
  IDiagnostics* diag = context->GetDiagnostics();

  io::IFile* manifest_file = GetFileCollection()->FindFile("AndroidManifest.xml");
  if (manifest_file == nullptr) {
    diag->Error(DiagMessage(source_) << "no AndroidManifest.xml found");
    return {};
  }

  std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
  if (manifest_data == nullptr) {
    diag->Error(DiagMessage(manifest_file->GetSource()) << "could not open AndroidManifest.xml");
    return {};
  }

  std::unique_ptr<xml::XmlResource> manifest =
      xml::Inflate(manifest_data->data(), manifest_data->size(), diag, manifest_file->GetSource());
  if (manifest == nullptr) {
    diag->Error(DiagMessage() << "failed to read binary AndroidManifest.xml");
  }
  return manifest;
}
}  // namespace aapt
+16 −9
Original line number Diff line number Diff line
@@ -25,17 +25,17 @@
#include "flatten/TableFlattener.h"
#include "io/ZipArchive.h"
#include "unflatten/BinaryResourceParser.h"
#include "xml/XmlDom.h"

namespace aapt {

/** Info about an APK loaded in memory. */
class LoadedApk {
 public:
  LoadedApk(
      const Source& source,
      std::unique_ptr<io::IFileCollection> apk,
  LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
            std::unique_ptr<ResourceTable> table)
      : source_(source), apk_(std::move(apk)), table_(std::move(table)) {}
      : source_(source), apk_(std::move(apk)), table_(std::move(table)) {
  }

  io::IFileCollection* GetFileCollection() { return apk_.get(); }

@@ -51,13 +51,20 @@ class LoadedApk {
                              IArchiveWriter* writer);

  /**
   * Writes the APK on disk at the given path, while also removing the resource
   * files that are not referenced in the resource table. The provided filter
   * chain is applied to each entry in the APK file.
   * Writes the APK on disk at the given path, while also removing the resource files that are not
   * referenced in the resource table. The provided filter chain is applied to each entry in the APK
   * file.
   *
   * If the manifest is also provided, it will be written to the new APK file, otherwise the
   * original manifest will be written. The manifest is only required if the contents of the new APK
   * have been modified in a way that require the AndroidManifest.xml to also be modified.
   */
  virtual bool WriteToArchive(IAaptContext* context, ResourceTable* split_table,
                              const TableFlattenerOptions& options, FilterChain* filters,
                              IArchiveWriter* writer);
                              IArchiveWriter* writer, xml::XmlResource* manifest = nullptr);

  /** Inflates the AndroidManifest.xml file from the APK. */
  std::unique_ptr<xml::XmlResource> InflateManifest(IAaptContext* context);

  static std::unique_ptr<LoadedApk> LoadApkFromPath(IAaptContext* context,
                                                    const android::StringPiece& path);
+1 −17
Original line number Diff line number Diff line
@@ -283,24 +283,8 @@ class OptimizeCommand {

bool ExtractAppDataFromManifest(OptimizeContext* context, LoadedApk* apk,
                                OptimizeOptions* out_options) {
  io::IFile* manifest_file = apk->GetFileCollection()->FindFile("AndroidManifest.xml");
  if (manifest_file == nullptr) {
    context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
                                     << "missing AndroidManifest.xml");
    return false;
  }

  std::unique_ptr<io::IData> data = manifest_file->OpenAsData();
  if (data == nullptr) {
    context->GetDiagnostics()->Error(DiagMessage(manifest_file->GetSource())
                                     << "failed to open file");
    return false;
  }

  std::unique_ptr<xml::XmlResource> manifest = xml::Inflate(
      data->data(), data->size(), context->GetDiagnostics(), manifest_file->GetSource());
  std::unique_ptr<xml::XmlResource> manifest = apk->InflateManifest(context);
  if (manifest == nullptr) {
    context->GetDiagnostics()->Error(DiagMessage() << "failed to read binary AndroidManifest.xml");
    return false;
  }

+4 −3
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include "ConfigDescription.h"
#include "Diagnostics.h"
#include "ResourceUtils.h"
#include "io/File.h"
#include "io/FileSystem.h"
#include "io/StringInputStream.h"
@@ -499,11 +500,11 @@ ConfigurationParser::ActionHandler ConfigurationParser::android_sdk_group_handle
      AndroidSdk entry;
      for (const auto& attr : child->attributes) {
        if (attr.name == "minSdkVersion") {
          entry.min_sdk_version = {attr.value};
          entry.min_sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
        } else if (attr.name == "targetSdkVersion") {
          entry.target_sdk_version = {attr.value};
          entry.target_sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
        } else if (attr.name == "maxSdkVersion") {
          entry.max_sdk_version = {attr.value};
          entry.max_sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
        } else {
          diag->Warn(DiagMessage() << "Unknown attribute: " << attr.name << " = " << attr.value);
        }
+5 −5
Original line number Diff line number Diff line
@@ -103,14 +103,14 @@ struct AndroidManifest {
};

struct AndroidSdk {
  Maybe<std::string> min_sdk_version;
  Maybe<std::string> target_sdk_version;
  Maybe<std::string> max_sdk_version;
  Maybe<int> min_sdk_version;
  Maybe<int> target_sdk_version;
  Maybe<int> max_sdk_version;
  Maybe<AndroidManifest> manifest;

  static AndroidSdk ForMinSdk(std::string min_sdk) {
  static AndroidSdk ForMinSdk(int min_sdk) {
    AndroidSdk sdk;
    sdk.min_sdk_version = {std::move(min_sdk)};
    sdk.min_sdk_version = min_sdk;
    return sdk;
  }

Loading