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
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user