Merge changes I2eef812b,I7b607192

* changes:
  AAPT v1 embed compile SDK version and codename into app
  AAPT2: Embed version of framework an app was compiled against.
This commit is contained in:
TreeHugger Robot
2017-12-05 16:03:26 +00:00
committed by Android (Google) Code Review
10 changed files with 350 additions and 110 deletions

View File

@@ -68,6 +68,7 @@ public:
mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
mBuildSharedLibrary(false),
mBuildAppAsSharedLibrary(false),
mCompileSdkVersion(0),
mArgc(0), mArgv(NULL)
{}
~Bundle(void) {}
@@ -123,6 +124,10 @@ public:
void setErrorOnFailedInsert(bool val) { mErrorOnFailedInsert = val; }
bool getErrorOnMissingConfigEntry() { return mErrorOnMissingConfigEntry; }
void setErrorOnMissingConfigEntry(bool val) { mErrorOnMissingConfigEntry = val; }
const android::String8& getCompileSdkVersionCodename() { return mCompileSdkVersionCodename; }
void setCompileSdkVersionCodename(const android::String8& codename) { mCompileSdkVersionCodename = codename; }
int getCompileSdkVersion() { return mCompileSdkVersion; }
void setCompileSdkVersion(int version) { mCompileSdkVersion = version; }
const android::String8& getPlatformBuildVersionCode() { return mPlatformVersionCode; }
void setPlatformBuildVersionCode(const android::String8& code) { mPlatformVersionCode = code; }
const android::String8& getPlatformBuildVersionName() { return mPlatformVersionName; }
@@ -344,6 +349,8 @@ private:
const char* mSingleCrunchOutputFile;
bool mBuildSharedLibrary;
bool mBuildAppAsSharedLibrary;
int mCompileSdkVersion;
android::String8 mCompileSdkVersionCodename;
android::String8 mPlatformVersionCode;
android::String8 mPlatformVersionName;
android::String8 mPrivateSymbolsPackage;

View File

@@ -293,6 +293,8 @@ enum {
ISGAME_ATTR = 0x10103f4,
REQUIRED_FEATURE_ATTR = 0x1010557,
REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
COMPILE_SDK_VERSION_ATTR = 0x01010572, // NOT FINALIZED
COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573, // NOT FINALIZED
};
String8 getComponentName(String8 &pkgName, String8 &componentName) {
@@ -1247,9 +1249,37 @@ int doDump(Bundle* bundle)
splitName.string()).string());
}
String8 platformVersionName = AaptXml::getAttribute(tree, NULL,
String8 platformBuildVersionName = AaptXml::getAttribute(tree, NULL,
"platformBuildVersionName");
printf(" platformBuildVersionName='%s'", platformVersionName.string());
if (platformBuildVersionName != "") {
printf(" platformBuildVersionName='%s'", platformBuildVersionName.string());
}
String8 platformBuildVersionCode = AaptXml::getAttribute(tree, NULL,
"platformBuildVersionCode");
if (platformBuildVersionCode != "") {
printf(" platformBuildVersionCode='%s'", platformBuildVersionCode.string());
}
int32_t compileSdkVersion = AaptXml::getIntegerAttribute(tree,
COMPILE_SDK_VERSION_ATTR, &error);
if (error != "") {
SourcePos(manifestFile, tree.getLineNumber()).error(
"ERROR getting 'android:compileSdkVersion' attribute: %s",
error.string());
goto bail;
}
if (compileSdkVersion > 0) {
printf(" compileSdkVersion='%d'", compileSdkVersion);
}
String8 compileSdkVersionCodename = AaptXml::getResolvedAttribute(res, tree,
COMPILE_SDK_VERSION_CODENAME_ATTR, &error);
if (compileSdkVersionCodename != "") {
printf(" compileSdkVersionCodename='%s'", ResTable::normalizeForOutput(
compileSdkVersionCodename.string()).string());
}
printf("\n");
int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree,

View File

@@ -918,6 +918,22 @@ status_t massageManifest(Bundle* bundle, ResourceTable* table, sp<XMLNode> root)
}
}
if (bundle->getCompileSdkVersion() != 0) {
if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "compileSdkVersion",
String8::format("%d", bundle->getCompileSdkVersion()),
errorOnFailedInsert, true)) {
return UNKNOWN_ERROR;
}
}
if (bundle->getCompileSdkVersionCodename() != "") {
if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "compileSdkVersionCodename",
bundle->getCompileSdkVersionCodename(), errorOnFailedInsert, true)) {
return UNKNOWN_ERROR;
}
}
if (bundle->getPlatformBuildVersionCode() != "") {
if (!addTagAttribute(root, "", "platformBuildVersionCode",
bundle->getPlatformBuildVersionCode(), errorOnFailedInsert, true)) {
@@ -1052,7 +1068,12 @@ enum {
VERSION_NAME_ATTR = 0x0101021c,
};
static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) {
static ssize_t extractPlatformBuildVersion(const ResTable& table, ResXMLTree& tree, Bundle* bundle) {
// First check if we should be recording the compileSdkVersion* attributes.
static const String16 compileSdkVersionName("android:attr/compileSdkVersion");
const bool useCompileSdkVersion = table.identifierForName(compileSdkVersionName.string(),
compileSdkVersionName.size()) != 0u;
size_t len;
ResXMLTree::event_code_t code;
while ((code = tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
@@ -1082,6 +1103,10 @@ static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) {
bundle->setPlatformBuildVersionCode(String8::format("%d", versionCode));
}
if (useCompileSdkVersion && versionCode >= 0 && bundle->getCompileSdkVersion() == 0) {
bundle->setCompileSdkVersion(versionCode);
}
String8 versionName = AaptXml::getAttribute(tree, VERSION_NAME_ATTR, &error);
if (error != "") {
fprintf(stderr, "ERROR: failed to get platform version name\n");
@@ -1091,6 +1116,11 @@ static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) {
if (versionName != "" && bundle->getPlatformBuildVersionName() == "") {
bundle->setPlatformBuildVersionName(versionName);
}
if (useCompileSdkVersion && versionName != ""
&& bundle->getCompileSdkVersionCodename() == "") {
bundle->setCompileSdkVersionCodename(versionName);
}
return NO_ERROR;
}
@@ -1121,7 +1151,7 @@ static ssize_t extractPlatformBuildVersion(AssetManager& assets, Bundle* bundle)
fprintf(stderr, "ERROR: Platform AndroidManifest.xml is corrupt\n");
result = UNKNOWN_ERROR;
} else {
result = extractPlatformBuildVersion(tree, bundle);
result = extractPlatformBuildVersion(assets.getResources(true), tree, bundle);
}
}
@@ -1707,7 +1737,9 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
// extract them from the platform APK.
if (packageType != ResourceTable::System &&
(bundle->getPlatformBuildVersionCode() == "" ||
bundle->getPlatformBuildVersionName() == "")) {
bundle->getPlatformBuildVersionName() == "" ||
bundle->getCompileSdkVersion() == 0 ||
bundle->getCompileSdkVersionCodename() == "")) {
err = extractPlatformBuildVersion(assets->getAssetManager(), bundle);
if (err != NO_ERROR) {
return UNKNOWN_ERROR;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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_;

View File

@@ -418,6 +418,15 @@ const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece
return nullptr;
}
Attribute* Element::FindOrCreateAttribute(const StringPiece& ns, const StringPiece& name) {
Attribute* attr = FindAttribute(ns, name);
if (attr == nullptr) {
attributes.push_back(Attribute{ns.to_string(), name.to_string()});
attr = &attributes.back();
}
return attr;
}
Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
return FindChildWithAttribute(ns, name, {}, {}, {});
}

View File

@@ -100,6 +100,8 @@ class Element : public Node {
Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name);
const Attribute* FindAttribute(const android::StringPiece& ns,
const android::StringPiece& name) const;
Attribute* FindOrCreateAttribute(const android::StringPiece& ns,
const android::StringPiece& name);
Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name);
const Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name) const;