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

Commit c6284379 authored by Adam Lesinski's avatar Adam Lesinski
Browse files

AAPT2: Embed version of framework an app was compiled against.

This change injects the 'android:compileSdkVersion' and
'android:compileSdkVersionCodename' into an app's AndroidManifest.xml,
whose values are dervied from the version name and version code of the
framework AndroidManifest.xml that is being linked against.

Bug: 63388434
Test: make aapt2_tests
Change-Id: I7b607192ecb337307c4bcb5770e7f716c6d4c9d2
parent 36f46a87
Loading
Loading
Loading
Loading
+100 −4
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */

#include <sys/stat.h>
#include <cinttypes>

#include <queue>
#include <unordered_map>
@@ -725,6 +726,30 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
  return true;
}

static int32_t FindFrameworkAssetManagerCookie(const android::AssetManager& assets) {
  using namespace android;

  // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so
  // we're looking for the first attribute resource in the system package.
  const ResTable& table = assets.getResources(true);
  Res_value val;
  ssize_t idx = table.getResource(0x01010000, &val, true);
  if (idx != NO_ERROR) {
    // Try as a bag.
    const ResTable::bag_entry* entry;
    ssize_t cnt = table.lockBag(0x01010000, &entry);
    if (cnt >= 0) {
      idx = entry->stringBlock;
    }
    table.unlockBag(entry);
  }

  if (idx < 0) {
    return 0;
  }
  return table.getTableCookie(idx);
}

class LinkCommand {
 public:
  LinkCommand(LinkContext* context, const LinkOptions& options)
@@ -734,7 +759,65 @@ class LinkCommand {
        file_collection_(util::make_unique<io::FileCollection>()) {
  }

  void ExtractCompileSdkVersions(android::AssetManager* assets) {
    using namespace android;

    int32_t cookie = FindFrameworkAssetManagerCookie(*assets);
    if (cookie == 0) {
      // No Framework assets loaded. Not a failure.
      return;
    }

    std::unique_ptr<Asset> manifest(
        assets->openNonAsset(cookie, kAndroidManifestPath, Asset::AccessMode::ACCESS_BUFFER));
    if (manifest == nullptr) {
      // No errors.
      return;
    }

    std::string error;
    std::unique_ptr<xml::XmlResource> manifest_xml =
        xml::Inflate(manifest->getBuffer(true /*wordAligned*/), manifest->getLength(), &error);
    if (manifest_xml == nullptr) {
      // No errors.
      return;
    }

    xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionCode");
    if (attr != nullptr) {
      Maybe<std::string>& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version;
      if (BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get())) {
        switch (prim->value.dataType) {
          case Res_value::TYPE_INT_DEC:
            compile_sdk_version = StringPrintf("%" PRId32, static_cast<int32_t>(prim->value.data));
            break;
          case Res_value::TYPE_INT_HEX:
            compile_sdk_version = StringPrintf("%" PRIx32, prim->value.data);
            break;
          default:
            break;
        }
      } else if (String* str = ValueCast<String>(attr->compiled_value.get())) {
        compile_sdk_version = *str->value;
      } else {
        compile_sdk_version = attr->value;
      }
    }

    attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionName");
    if (attr != nullptr) {
      Maybe<std::string>& compile_sdk_version_codename =
          options_.manifest_fixer_options.compile_sdk_version_codename;
      if (String* str = ValueCast<String>(attr->compiled_value.get())) {
        compile_sdk_version_codename = *str->value;
      } else {
        compile_sdk_version_codename = attr->value;
      }
    }
  }

  // Creates a SymbolTable that loads symbols from the various APKs.
  // Pre-condition: context_->GetCompilationPackage() needs to be set.
  bool LoadSymbolsFromIncludePaths() {
    auto asset_source = util::make_unique<AssetManagerSymbolSource>();
    for (const std::string& path : options_.include_paths) {
@@ -802,6 +885,17 @@ class LinkCommand {
      } else if (entry.first == kAppPackageId) {
        // Capture the included base feature package.
        included_feature_base_ = entry.second;
      } else if (entry.first == kFrameworkPackageId) {
        // Try to embed which version of the framework we're compiling against.
        // First check if we should use compileSdkVersion at all. Otherwise compilation may fail
        // when linking our synthesized 'android:compileSdkVersion' attribute.
        std::unique_ptr<SymbolTable::Symbol> symbol = asset_source->FindByName(
            ResourceName("android", ResourceType::kAttr, "compileSdkVersion"));
        if (symbol != nullptr && symbol->is_public) {
          // The symbol is present and public, extract the android:versionName and
          // android:versionCode from the framework AndroidManifest.xml.
          ExtractCompileSdkVersions(asset_source->GetAssetManager());
        }
      }
    }

@@ -1535,6 +1629,12 @@ class LinkCommand {
      context_->SetCompilationPackage(app_info.package);
    }

    // Now that the compilation package is set, load the dependencies. This will also extract
    // the Android framework's versionCode and versionName, if they exist.
    if (!LoadSymbolsFromIncludePaths()) {
      return 1;
    }

    ManifestFixer manifest_fixer(options_.manifest_fixer_options);
    if (!manifest_fixer.Consume(context_, manifest_xml.get())) {
      return 1;
@@ -1563,10 +1663,6 @@ class LinkCommand {
      }
    }

    if (!LoadSymbolsFromIncludePaths()) {
      return 1;
    }

    TableMergerOptions table_merger_options;
    table_merger_options.auto_add_overlay = options_.auto_add_overlay;
    table_merger_ = util::make_unique<TableMerger>(context_, &final_table_, table_merger_options);
+19 −0
Original line number Diff line number Diff line
@@ -406,6 +406,25 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
    root->InsertChild(0, std::move(uses_sdk));
  }

  if (options_.compile_sdk_version) {
    xml::Attribute* attr = root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersion");

    // Make sure we un-compile the value if it was set to something else.
    attr->compiled_value = {};

    attr->value = options_.compile_sdk_version.value();
  }

  if (options_.compile_sdk_version_codename) {
    xml::Attribute* attr =
        root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");

    // Make sure we un-compile the value if it was set to something else.
    attr->compiled_value = {};

    attr->value = options_.compile_sdk_version_codename.value();
  }

  xml::XmlActionExecutor executor;
  if (!BuildRules(&executor, context->GetDiagnostics())) {
    return false;
+26 −6
Original line number Diff line number Diff line
@@ -29,22 +29,42 @@
namespace aapt {

struct ManifestFixerOptions {
  // The minimum SDK version to set if no 'android:minSdkVersion' is defined in a <uses-sdk> tag.
  Maybe<std::string> min_sdk_version_default;

  // The target SDK version to set if no 'android:targetSdkVersion' is defined in a <uses-sdk> tag.
  Maybe<std::string> target_sdk_version_default;

  // The Android package to use instead of the one defined in 'package' in <manifest>.
  // This also renames all relative package/class names in the manifest to fully qualified
  // Java names.
  Maybe<std::string> rename_manifest_package;

  // The Android package to use instead of the one defined in 'android:targetPackage' in
  // <instrumentation>.
  Maybe<std::string> rename_instrumentation_target_package;

  // The version name to set if 'android:versionName' is not defined in <manifest>.
  Maybe<std::string> version_name_default;

  // The version code to set if 'android:versionCode' is not defined in <manifest>.
  Maybe<std::string> version_code_default;

  // The version of the framework being compiled against to set for 'android:compileSdkVersion' in
  // the <manifest> tag.
  Maybe<std::string> compile_sdk_version;

  // The version codename of the framework being compiled against to set for
  // 'android:compileSdkVersionCodename' in the <manifest> tag.
  Maybe<std::string> compile_sdk_version_codename;
};

/**
 * Verifies that the manifest is correctly formed and inserts defaults
 * where specified with ManifestFixerOptions.
 */
// Verifies that the manifest is correctly formed and inserts defaults where specified with
// ManifestFixerOptions.
class ManifestFixer : public IXmlResourceConsumer {
 public:
  explicit ManifestFixer(const ManifestFixerOptions& options)
      : options_(options) {}
  explicit ManifestFixer(const ManifestFixerOptions& options) : options_(options) {
  }

  bool Consume(IAaptContext* context, xml::XmlResource* doc) override;

+116 −95
Original line number Diff line number Diff line
@@ -19,7 +19,12 @@
#include "test/Test.h"

using ::android::StringPiece;
using ::testing::Eq;
using ::testing::Gt;
using ::testing::IsNull;
using ::testing::Ne;
using ::testing::NotNull;
using ::testing::StrEq;

namespace aapt {

@@ -72,22 +77,20 @@ struct ManifestFixerTest : public ::testing::Test {
};

TEST_F(ManifestFixerTest, EnsureManifestIsRootTag) {
  EXPECT_EQ(nullptr, Verify("<other-tag />"));
  EXPECT_EQ(nullptr, Verify("<ns:manifest xmlns:ns=\"com\" />"));
  EXPECT_NE(nullptr, Verify("<manifest package=\"android\"></manifest>"));
  EXPECT_THAT(Verify("<other-tag />"), IsNull());
  EXPECT_THAT(Verify("<ns:manifest xmlns:ns=\"com\" />"), IsNull());
  EXPECT_THAT(Verify("<manifest package=\"android\"></manifest>"), NotNull());
}

TEST_F(ManifestFixerTest, EnsureManifestHasPackage) {
  EXPECT_NE(nullptr, Verify("<manifest package=\"android\" />"));
  EXPECT_NE(nullptr, Verify("<manifest package=\"com.android\" />"));
  EXPECT_NE(nullptr, Verify("<manifest package=\"com.android.google\" />"));
  EXPECT_EQ(nullptr,
            Verify("<manifest package=\"com.android.google.Class$1\" />"));
  EXPECT_EQ(nullptr, Verify("<manifest "
                            "xmlns:android=\"http://schemas.android.com/apk/"
                            "res/android\" "
                            "android:package=\"com.android\" />"));
  EXPECT_EQ(nullptr, Verify("<manifest package=\"@string/str\" />"));
  EXPECT_THAT(Verify("<manifest package=\"android\" />"), NotNull());
  EXPECT_THAT(Verify("<manifest package=\"com.android\" />"), NotNull());
  EXPECT_THAT(Verify("<manifest package=\"com.android.google\" />"), NotNull());
  EXPECT_THAT(Verify("<manifest package=\"com.android.google.Class$1\" />"), IsNull());
  EXPECT_THAT(Verify("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" "
                     "android:package=\"com.android\" />"),
              IsNull());
  EXPECT_THAT(Verify("<manifest package=\"@string/str\" />"), IsNull());
}

TEST_F(ManifestFixerTest, AllowMetaData) {
@@ -105,7 +108,7 @@ TEST_F(ManifestFixerTest, AllowMetaData) {
          </application>
          <instrumentation android:name=".Go"><meta-data /></instrumentation>
        </manifest>)EOF");
  ASSERT_NE(nullptr, doc);
  ASSERT_THAT(doc, NotNull());
}

TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
@@ -117,21 +120,21 @@ TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
        <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
      </manifest>)EOF",
                                                            options);
  ASSERT_NE(nullptr, doc);
  ASSERT_THAT(doc, NotNull());

  xml::Element* el;
  xml::Attribute* attr;

  el = doc->root.get();
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());
  el = el->FindChild({}, "uses-sdk");
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());
  attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ("7", attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("7"));
  attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ("21", attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("21"));

  doc = VerifyWithOptions(R"EOF(
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -139,18 +142,18 @@ TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
        <uses-sdk android:targetSdkVersion="21" />
      </manifest>)EOF",
                          options);
  ASSERT_NE(nullptr, doc);
  ASSERT_THAT(doc, NotNull());

  el = doc->root.get();
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());
  el = el->FindChild({}, "uses-sdk");
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());
  attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ("8", attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("8"));
  attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ("21", attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("21"));

  doc = VerifyWithOptions(R"EOF(
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -158,35 +161,35 @@ TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
        <uses-sdk />
      </manifest>)EOF",
                          options);
  ASSERT_NE(nullptr, doc);
  ASSERT_THAT(doc, NotNull());

  el = doc->root.get();
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());
  el = el->FindChild({}, "uses-sdk");
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());
  attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ("8", attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("8"));
  attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ("22", attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("22"));

  doc = VerifyWithOptions(R"EOF(
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                package="android" />)EOF",
                          options);
  ASSERT_NE(nullptr, doc);
  ASSERT_THAT(doc, NotNull());

  el = doc->root.get();
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());
  el = el->FindChild({}, "uses-sdk");
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());
  attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ("8", attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("8"));
  attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ("22", attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("22"));
}

TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) {
@@ -197,17 +200,17 @@ TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) {
            <application android:name=".MainApplication" />
          </manifest>)EOF",
                                                            options);
  ASSERT_NE(nullptr, doc);
  ASSERT_THAT(doc, NotNull());

  xml::Element* manifest_el = doc->root.get();
  ASSERT_NE(nullptr, manifest_el);
  ASSERT_THAT(manifest_el, NotNull());
  ASSERT_EQ("manifest", manifest_el->name);

  xml::Element* application_el = manifest_el->FindChild("", "application");
  ASSERT_NE(nullptr, application_el);
  ASSERT_THAT(application_el, NotNull());

  xml::Element* uses_sdk_el = manifest_el->FindChild("", "uses-sdk");
  ASSERT_NE(nullptr, uses_sdk_el);
  ASSERT_THAT(uses_sdk_el, NotNull());

  // Check that the uses_sdk_el comes before application_el in the children
  // vector.
@@ -225,12 +228,12 @@ TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) {
                     return child.get() == application_el;
                   });

  ASSERT_NE(manifest_el->children.end(), uses_sdk_iter);
  ASSERT_NE(manifest_el->children.end(), application_iter);
  ASSERT_THAT(uses_sdk_iter, Ne(manifest_el->children.end()));
  ASSERT_THAT(application_iter, Ne(manifest_el->children.end()));

  // The distance should be positive, meaning uses_sdk_iter comes before
  // application_iter.
  EXPECT_GT(std::distance(uses_sdk_iter, application_iter), 0);
  EXPECT_THAT(std::distance(uses_sdk_iter, application_iter), Gt(0));
}

TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
@@ -247,48 +250,49 @@ TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
        </application>
      </manifest>)EOF",
                                                            options);
  ASSERT_NE(nullptr, doc);
  ASSERT_THAT(doc, NotNull());

  xml::Element* manifest_el = doc->root.get();
  ASSERT_NE(nullptr, manifest_el);
  ASSERT_THAT(manifest_el, NotNull());

  xml::Attribute* attr = nullptr;

  attr = manifest_el->FindAttribute({}, "package");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ(std::string("com.android"), attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("com.android"));

  xml::Element* uses_split_el = manifest_el->FindChild({}, "uses-split");
  ASSERT_NE(nullptr, uses_split_el);
  ASSERT_THAT(uses_split_el, NotNull());
  attr = uses_split_el->FindAttribute(xml::kSchemaAndroid, "name");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ(std::string("feature_a"), attr->value);
  ASSERT_THAT(attr, NotNull());
  // This should NOT have been affected.
  EXPECT_THAT(attr->value, StrEq("feature_a"));

  xml::Element* application_el = manifest_el->FindChild({}, "application");
  ASSERT_NE(nullptr, application_el);
  ASSERT_THAT(application_el, NotNull());

  attr = application_el->FindAttribute(xml::kSchemaAndroid, "name");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ(std::string("android.MainApplication"), attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("android.MainApplication"));

  attr = application_el->FindAttribute({}, "text");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ(std::string("hello"), attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("hello"));

  xml::Element* el;
  el = application_el->FindChild({}, "activity");
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());

  attr = el->FindAttribute(xml::kSchemaAndroid, "name");
  ASSERT_NE(nullptr, el);
  EXPECT_EQ(std::string("android.activity.Start"), attr->value);
  ASSERT_THAT(el, NotNull());
  EXPECT_THAT(attr->value, StrEq("android.activity.Start"));

  el = application_el->FindChild({}, "receiver");
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());

  attr = el->FindAttribute(xml::kSchemaAndroid, "name");
  ASSERT_NE(nullptr, el);
  EXPECT_EQ(std::string("com.google.android.Receiver"), attr->value);
  ASSERT_THAT(el, NotNull());
  EXPECT_THAT(attr->value, StrEq("com.google.android.Receiver"));
}

TEST_F(ManifestFixerTest,
@@ -302,19 +306,19 @@ TEST_F(ManifestFixerTest,
        <instrumentation android:name=".TestRunner" android:targetPackage="android" />
      </manifest>)EOF",
                                                            options);
  ASSERT_NE(nullptr, doc);
  ASSERT_THAT(doc, NotNull());

  xml::Element* manifest_el = doc->root.get();
  ASSERT_NE(nullptr, manifest_el);
  ASSERT_THAT(manifest_el, NotNull());

  xml::Element* instrumentation_el =
      manifest_el->FindChild({}, "instrumentation");
  ASSERT_NE(nullptr, instrumentation_el);
  ASSERT_THAT(instrumentation_el, NotNull());

  xml::Attribute* attr =
      instrumentation_el->FindAttribute(xml::kSchemaAndroid, "targetPackage");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ(std::string("com.android"), attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("com.android"));
}

TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) {
@@ -326,41 +330,39 @@ TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) {
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                package="android" />)EOF",
                                                            options);
  ASSERT_NE(nullptr, doc);
  ASSERT_THAT(doc, NotNull());

  xml::Element* manifest_el = doc->root.get();
  ASSERT_NE(nullptr, manifest_el);
  ASSERT_THAT(manifest_el, NotNull());

  xml::Attribute* attr =
      manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ(std::string("Beta"), attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("Beta"));

  attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
  ASSERT_NE(nullptr, attr);
  EXPECT_EQ(std::string("0x10000000"), attr->value);
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("0x10000000"));
}

TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) {
  EXPECT_EQ(nullptr,
            Verify("<manifest package=\"android\" coreApp=\"hello\" />"));
  EXPECT_EQ(nullptr,
            Verify("<manifest package=\"android\" coreApp=\"1dp\" />"));
  EXPECT_THAT(Verify("<manifest package=\"android\" coreApp=\"hello\" />"), IsNull());
  EXPECT_THAT(Verify("<manifest package=\"android\" coreApp=\"1dp\" />"), IsNull());

  std::unique_ptr<xml::XmlResource> doc =
      Verify("<manifest package=\"android\" coreApp=\"true\" />");
  ASSERT_NE(nullptr, doc);
  ASSERT_THAT(doc, NotNull());

  xml::Element* el = doc->root.get();
  ASSERT_NE(nullptr, el);
  ASSERT_THAT(el, NotNull());

  EXPECT_EQ("manifest", el->name);
  EXPECT_THAT(el->name, StrEq("manifest"));

  xml::Attribute* attr = el->FindAttribute("", "coreApp");
  ASSERT_NE(nullptr, attr);
  ASSERT_THAT(attr, NotNull());

  EXPECT_NE(nullptr, attr->compiled_value);
  EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(attr->compiled_value.get()));
  EXPECT_THAT(attr->compiled_value, NotNull());
  EXPECT_THAT(ValueCast<BinaryPrimitive>(attr->compiled_value.get()), NotNull());
}

TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
@@ -375,21 +377,21 @@ TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
            <uses-feature android:glEsVersion="2" />
          </feature-group>
        </manifest>)EOF";
  EXPECT_NE(nullptr, Verify(input));
  EXPECT_THAT(Verify(input), NotNull());

  input = R"EOF(
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                  package="android">
          <uses-feature android:name="feature" android:glEsVersion="1" />
        </manifest>)EOF";
  EXPECT_EQ(nullptr, Verify(input));
  EXPECT_THAT(Verify(input), IsNull());

  input = R"EOF(
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                  package="android">
          <uses-feature />
        </manifest>)EOF";
  EXPECT_EQ(nullptr, Verify(input));
  EXPECT_THAT(Verify(input), IsNull());

  input = R"EOF(
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -398,7 +400,7 @@ TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
            <uses-feature android:name="feature" android:glEsVersion="1" />
          </feature-group>
        </manifest>)EOF";
  EXPECT_EQ(nullptr, Verify(input));
  EXPECT_THAT(Verify(input), IsNull());

  input = R"EOF(
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -407,7 +409,7 @@ TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
            <uses-feature />
          </feature-group>
        </manifest>)EOF";
  EXPECT_EQ(nullptr, Verify(input));
  EXPECT_THAT(Verify(input), IsNull());
}

TEST_F(ManifestFixerTest, IgnoreNamespacedElements) {
@@ -416,7 +418,7 @@ TEST_F(ManifestFixerTest, IgnoreNamespacedElements) {
                package="android">
        <special:tag whoo="true" xmlns:special="http://google.com" />
      </manifest>)EOF";
  EXPECT_NE(nullptr, Verify(input));
  EXPECT_THAT(Verify(input), NotNull());
}

TEST_F(ManifestFixerTest, DoNotIgnoreNonNamespacedElements) {
@@ -425,7 +427,7 @@ TEST_F(ManifestFixerTest, DoNotIgnoreNonNamespacedElements) {
                package="android">
        <tag whoo="true" />
      </manifest>)EOF";
  EXPECT_EQ(nullptr, Verify(input));
  EXPECT_THAT(Verify(input), IsNull());
}

TEST_F(ManifestFixerTest, SupportKeySets) {
@@ -446,4 +448,23 @@ TEST_F(ManifestFixerTest, SupportKeySets) {
  EXPECT_THAT(Verify(input), NotNull());
}

TEST_F(ManifestFixerTest, InsertCompileSdkVersions) {
  std::string input = R"(
      <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" />)";
  ManifestFixerOptions options;
  options.compile_sdk_version = {"28"};
  options.compile_sdk_version_codename = {"P"};

  std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
  ASSERT_THAT(manifest, NotNull());

  xml::Attribute* attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersion");
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("28"));

  attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
  ASSERT_THAT(attr, NotNull());
  EXPECT_THAT(attr->value, StrEq("P"));
}

}  // namespace aapt
+4 −0
Original line number Diff line number Diff line
@@ -199,6 +199,10 @@ class AssetManagerSymbolSource : public ISymbolSource {
  std::unique_ptr<SymbolTable::Symbol> FindByReference(
      const Reference& ref) override;

  android::AssetManager* GetAssetManager() {
    return &assets_;
  }

 private:
  android::AssetManager assets_;

Loading