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

Commit 5fa2bb14 authored by Ryan Mitchell's avatar Ryan Mitchell
Browse files

AAPT2: Fix long version code bugs

Refactoring areas in AAPT2 that use android:versionCode to also use
abdroid:versionCodeMajor. Does not add versionCodeMajor command line flag yet.

Bug: 109883459
Test: aapt2_tests
Change-Id: I573fbea37491cf8c5742f9e385c66ee64c4e5166
parent 89c9a128
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -31,9 +31,12 @@ struct AppInfo {
  // The app's minimum SDK version, if it is defined.
  Maybe<int> min_sdk_version;

  // The app's version code, if it is defined.
  // The app's version code (the lower 32 bits of the long version code), if it is defined.
  Maybe<uint32_t> version_code;

  // The app's version code major (the upper 32 bits of the long version code), if it is defined.
  Maybe<uint32_t> version_code_major;

  // The app's revision code, if it is defined.
  Maybe<uint32_t> revision_code;

+12 −0
Original line number Diff line number Diff line
@@ -908,6 +908,18 @@ class Linker {
      app_info.version_code = maybe_code.value();
    }

    if (xml::Attribute* version_code_major_attr =
        manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) {
      Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_major_attr->value);
      if (!maybe_code) {
        diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
                        << "invalid android:versionCodeMajor '"
                        << version_code_major_attr->value << "'");
        return {};
      }
      app_info.version_code_major = maybe_code.value();
    }

    if (xml::Attribute* revision_code_attr =
            manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
      Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(revision_code_attr->value);
+38 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "util/Util.h"

using ::android::StringPiece;
using ::android::base::StringPrintf;

namespace aapt {

@@ -168,6 +169,7 @@ std::string MakePackageSafeName(const std::string &name) {
std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info,
                                                        const SplitConstraints& constraints) {
  const ResourceId kVersionCode(0x0101021b);
  const ResourceId kVersionCodeMajor(0x01010576);
  const ResourceId kRevisionCode(0x010104d5);
  const ResourceId kHasCode(0x0101000c);

@@ -184,6 +186,14 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info,
        util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_DEC, version_code)});
  }

  if (app_info.version_code_major) {
    const uint32_t version_code_major = app_info.version_code_major.value();
    manifest_el->attributes.push_back(xml::Attribute{
        xml::kSchemaAndroid, "versionCodeMajor", std::to_string(version_code_major),
        CreateAttributeWithId(kVersionCodeMajor),
        util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_DEC, version_code_major)});
  }

  if (app_info.revision_code) {
    const uint32_t revision_code = app_info.revision_code.value();
    manifest_el->attributes.push_back(xml::Attribute{
@@ -355,6 +365,17 @@ Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
    app_info.version_code = maybe_code.value();
  }

  if (const xml::Attribute* version_code_major_attr =
      manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) {
    Maybe<uint32_t> maybe_code = ExtractCompiledInt(*version_code_major_attr, &error_msg);
    if (!maybe_code) {
      diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
                      << "invalid android:versionCodeMajor: " << error_msg);
      return {};
    }
    app_info.version_code_major = maybe_code.value();
  }

  if (const xml::Attribute* revision_code_attr =
          manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
    Maybe<uint32_t> maybe_code = ExtractCompiledInt(*revision_code_attr, &error_msg);
@@ -391,4 +412,21 @@ Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
  return app_info;
}

void SetLongVersionCode(xml::Element* manifest, uint64_t version) {
  // Write the low bits of the version code to android:versionCode
  auto version_code = manifest->FindOrCreateAttribute(xml::kSchemaAndroid, "versionCode");
  version_code->value = StringPrintf("0x%08x", (uint32_t) (version & 0xffffffff));
  version_code->compiled_value = ResourceUtils::TryParseInt(version_code->value);

  auto version_high = (uint32_t) (version >> 32);
  if (version_high != 0) {
    // Write the high bits of the version code to android:versionCodeMajor
    auto version_major = manifest->FindOrCreateAttribute(xml::kSchemaAndroid, "versionCodeMajor");
    version_major->value = StringPrintf("0x%08x", version_high);
    version_major->compiled_value = ResourceUtils::TryParseInt(version_major->value);
  } else {
    manifest->RemoveAttribute(xml::kSchemaAndroid, "versionCodeMajor");
  }
}

}  // namespace aapt
+5 −0
Original line number Diff line number Diff line
@@ -67,6 +67,11 @@ Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
// checks this at runtime.
std::string MakePackageSafeName(const std::string &name);

// Sets the versionCode and versionCodeMajor attributes to the version code. Attempts to encode the
// version code using the versionCode attribute only, and encodes using both versionCode and
// versionCodeMajor if the version code requires more than 32 bits.
void SetLongVersionCode(xml::Element* manifest, uint64_t version_code);

}  // namespace aapt

#endif /* AAPT_SPLIT_UTIL_H */
+48 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include "AppInfo.h"
#include "split/TableSplitter.h"
#include "test/Builders.h"
#include "test/Test.h"

namespace aapt {
@@ -36,4 +37,51 @@ TEST(UtilTest, SplitNamesAreSanitized) {
    EXPECT_EQ(root->FindAttribute("", "targetConfig")->value, "b+sr+Latn,en-rUS-land");
}

TEST (UtilTest, LongVersionCodeDefined) {
  auto doc = test::BuildXmlDom(R"(
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.aapt.test" android:versionCode="0x1" android:versionCodeMajor="0x1">
      </manifest>)");
  SetLongVersionCode(doc->root.get(), 42);

  auto version_code = doc->root->FindAttribute(xml::kSchemaAndroid, "versionCode");
  ASSERT_NE(version_code, nullptr);
  EXPECT_EQ(version_code->value, "0x0000002a");

  ASSERT_NE(version_code->compiled_value, nullptr);
  auto compiled_version_code = ValueCast<BinaryPrimitive>(version_code->compiled_value.get());
  ASSERT_NE(compiled_version_code, nullptr);
  EXPECT_EQ(compiled_version_code->value.data, 42U);

  auto version_code_major = doc->root->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor");
  EXPECT_EQ(version_code_major, nullptr);
}

TEST (UtilTest, LongVersionCodeUndefined) {
  auto doc = test::BuildXmlDom(R"(
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.aapt.test">
        </manifest>)");
  SetLongVersionCode(doc->root.get(), 420000000000);

  auto version_code = doc->root->FindAttribute(xml::kSchemaAndroid, "versionCode");
  ASSERT_NE(version_code, nullptr);
  EXPECT_EQ(version_code->value, "0xc9f36800");

  ASSERT_NE(version_code->compiled_value, nullptr);
  auto compiled_version_code = ValueCast<BinaryPrimitive>(version_code->compiled_value.get());
  ASSERT_NE(compiled_version_code, nullptr);
  EXPECT_EQ(compiled_version_code->value.data, 0xc9f36800);

  auto version_code_major = doc->root->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor");
  ASSERT_NE(version_code_major, nullptr);
  EXPECT_EQ(version_code_major->value, "0x00000061");

  ASSERT_NE(version_code_major->compiled_value, nullptr);
  auto compiled_version_code_major = ValueCast<BinaryPrimitive>(
      version_code_major->compiled_value.get());
  ASSERT_NE(compiled_version_code_major, nullptr);
  EXPECT_EQ(compiled_version_code_major->value.data, 0x61);
}

}  // namespace aapt
Loading