diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 818ad2089d8aa..a3b7664818873 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -2159,7 +2159,11 @@ int Link(const std::vector& args, IDiagnostics* diagnostics) { "Syntax: path/to/output.apk:[,[...]].\n" "On Windows, use a semicolon ';' separator instead.", &split_args) - .OptionalSwitch("-v", "Enables verbose logging.", &verbose); + .OptionalSwitch("-v", "Enables verbose logging.", &verbose) + .OptionalSwitch("--debug-mode", + "Inserts android:debuggable=\"true\" in to the application node of the\n" + "manifest, making the application debuggable even on production devices.", + &options.manifest_fixer_options.debug_mode); if (!flags.Parse("aapt2 link", args, &std::cerr)) { return 1; diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index 713db5b7ed862..165702ca42cd9 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -354,6 +354,14 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, uses_static_library_action.Action(RequiredAndroidAttribute("version")); uses_static_library_action.Action(RequiredAndroidAttribute("certDigest")); + if (options_.debug_mode) { + application_action.Action([&](xml::Element* el) -> bool { + xml::Attribute *attr = el->FindOrCreateAttribute(xml::kSchemaAndroid, "debuggable"); + attr->value = "true"; + return true; + }); + } + application_action["meta-data"] = meta_data_action; application_action["activity"] = component_action; diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h index 0caa52eaf6509..7d6fad2f09187 100644 --- a/tools/aapt2/link/ManifestFixer.h +++ b/tools/aapt2/link/ManifestFixer.h @@ -58,10 +58,13 @@ struct ManifestFixerOptions { // 'android:compileSdkVersionCodename' in the tag. Maybe compile_sdk_version_codename; - // Wether validation errors should be treated only as warnings. If this is 'true', then an + // Whether validation errors should be treated only as warnings. If this is 'true', then an // incorrect node will not result in an error, but only as a warning, and the parsing will // continue. bool warn_validation = false; + + // Whether to inject the android:debuggable="true" flag into the manifest + bool debug_mode = false; }; // Verifies that the manifest is correctly formed and inserts defaults where specified with diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp index ed98d715df58a..8db937439c553 100644 --- a/tools/aapt2/link/ManifestFixer_test.cpp +++ b/tools/aapt2/link/ManifestFixer_test.cpp @@ -416,6 +416,68 @@ TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) { EXPECT_THAT(Verify(input), IsNull()); } +TEST_F(ManifestFixerTest, ApplicationInjectDebuggable) { + ManifestFixerOptions options; + options.debug_mode = true; + + std::string no_d = R"( + + + + )"; + + std::string false_d = R"( + + + + )"; + + std::string true_d = R"( + + + + )"; + + // Inject the debuggable attribute when the attribute is not present and the + // flag is present + std::unique_ptr manifest = VerifyWithOptions(no_d, options); + EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( + {}, "application", xml::kSchemaAndroid, "debuggable", "true"), NotNull()); + + // Set the debuggable flag to true if the attribute is false and the flag is + // present + manifest = VerifyWithOptions(false_d, options); + EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( + {}, "application", xml::kSchemaAndroid, "debuggable", "true"), NotNull()); + + // Keep debuggable flag true if the attribute is true and the flag is present + manifest = VerifyWithOptions(true_d, options); + EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( + {}, "application", xml::kSchemaAndroid, "debuggable", "true"), NotNull()); + + // Do not inject the debuggable attribute when the attribute is not present + // and the flag is not present + manifest = Verify(no_d); + EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( + {}, "application", xml::kSchemaAndroid, "debuggable", "true"), IsNull()); + + // Do not set the debuggable flag to true if the attribute is false and the + // flag is not present + manifest = Verify(false_d); + EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( + {}, "application", xml::kSchemaAndroid, "debuggable", "true"), IsNull()); + + // Keep debuggable flag true if the attribute is true and the flag is not + // present + manifest = Verify(true_d); + EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( + {}, "application", xml::kSchemaAndroid, "debuggable", "true"), NotNull()); +} + + TEST_F(ManifestFixerTest, IgnoreNamespacedElements) { std::string input = R"EOF(