diff options
author | 2018-07-12 11:24:51 -0700 | |
---|---|---|
committer | 2018-07-13 23:41:46 +0000 | |
commit | 5fa2bb14ec6e2a824559909f25e6ea82a2842f5a (patch) | |
tree | 0544bf2e6da16b978251407e581a0ad7502c4cb5 | |
parent | 89c9a12826b5d0c52edb97c17ee55c317425d5b8 (diff) |
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
-rw-r--r-- | tools/aapt2/AppInfo.h | 5 | ||||
-rw-r--r-- | tools/aapt2/cmd/Link.cpp | 12 | ||||
-rw-r--r-- | tools/aapt2/cmd/Util.cpp | 38 | ||||
-rw-r--r-- | tools/aapt2/cmd/Util.h | 5 | ||||
-rw-r--r-- | tools/aapt2/cmd/Util_test.cpp | 48 | ||||
-rw-r--r-- | tools/aapt2/optimize/MultiApkGenerator.cpp | 31 |
6 files changed, 130 insertions, 9 deletions
diff --git a/tools/aapt2/AppInfo.h b/tools/aapt2/AppInfo.h index d6f599520d71..75123537116f 100644 --- a/tools/aapt2/AppInfo.h +++ b/tools/aapt2/AppInfo.h @@ -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; diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 26770d1f281c..1d508d91f0fa 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -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); diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp index 4e77e9ae9a45..c6c82b04ff2e 100644 --- a/tools/aapt2/cmd/Util.cpp +++ b/tools/aapt2/cmd/Util.cpp @@ -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 diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h index fb8753ed2286..cf1443e30e1f 100644 --- a/tools/aapt2/cmd/Util.h +++ b/tools/aapt2/cmd/Util.h @@ -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 */ diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp index 0c527f6a90dc..b9fb5b2868a7 100644 --- a/tools/aapt2/cmd/Util_test.cpp +++ b/tools/aapt2/cmd/Util_test.cpp @@ -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 diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp index 9cfd7300df3d..a931343281bc 100644 --- a/tools/aapt2/optimize/MultiApkGenerator.cpp +++ b/tools/aapt2/optimize/MultiApkGenerator.cpp @@ -26,6 +26,7 @@ #include "ResourceUtils.h" #include "ValueVisitor.h" #include "configuration/ConfigurationParser.h" +#include "cmd/Util.h" #include "filter/AbiFilter.h" #include "filter/Filter.h" #include "format/Archive.h" @@ -269,7 +270,7 @@ bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact, // Make sure the first element is <manifest> with package attribute. xml::Element* manifest_el = manifest->root.get(); - if (manifest_el == nullptr) { + if (!manifest_el) { return false; } @@ -278,21 +279,35 @@ bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact, return false; } - // Update the versionCode attribute. - xml::Attribute* versionCode = manifest_el->FindAttribute(kSchemaAndroid, "versionCode"); - if (versionCode == nullptr) { + // Retrieve the versionCode attribute. + auto version_code = manifest_el->FindAttribute(kSchemaAndroid, "versionCode"); + if (!version_code) { diag->Error(DiagMessage(manifest->file.source) << "manifest must have a versionCode attribute"); return false; } - auto* compiled_version = ValueCast<BinaryPrimitive>(versionCode->compiled_value.get()); - if (compiled_version == nullptr) { + auto version_code_value = ValueCast<BinaryPrimitive>(version_code->compiled_value.get()); + if (!version_code_value) { diag->Error(DiagMessage(manifest->file.source) << "versionCode is invalid"); return false; } - int new_version = compiled_version->value.data + artifact.version; - versionCode->compiled_value = ResourceUtils::TryParseInt(std::to_string(new_version)); + // Retrieve the versionCodeMajor attribute. + auto version_code_major = manifest_el->FindAttribute(kSchemaAndroid, "versionCodeMajor"); + BinaryPrimitive* version_code_major_value = nullptr; + if (version_code_major) { + version_code_major_value = ValueCast<BinaryPrimitive>(version_code_major->compiled_value.get()); + if (!version_code_major_value) { + diag->Error(DiagMessage(manifest->file.source) << "versionCodeMajor is invalid"); + return false; + } + } + + // Calculate and set the updated version code + uint64_t major = (version_code_major_value) + ? ((uint64_t) version_code_major_value->value.data) << 32 : 0; + uint64_t new_version = (major | version_code_value->value.data) + artifact.version; + SetLongVersionCode(manifest_el, new_version); // Check to see if the minSdkVersion needs to be updated. if (artifact.android_sdk) { |