Loading tools/aapt2/cmd/Link.cpp +15 −1 Original line number Original line Diff line number Diff line Loading @@ -56,6 +56,7 @@ #include "java/JavaClassGenerator.h" #include "java/JavaClassGenerator.h" #include "java/ManifestClassGenerator.h" #include "java/ManifestClassGenerator.h" #include "java/ProguardRules.h" #include "java/ProguardRules.h" #include "link/FeatureFlagsFilter.h" #include "link/Linkers.h" #include "link/Linkers.h" #include "link/ManifestFixer.h" #include "link/ManifestFixer.h" #include "link/NoDefaultResourceRemover.h" #include "link/NoDefaultResourceRemover.h" Loading Loading @@ -1986,6 +1987,19 @@ class Linker { context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()}); context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()}); context_->SetSplitNameDependencies(app_info_.split_name_dependencies); context_->SetSplitNameDependencies(app_info_.split_name_dependencies); FeatureFlagsFilterOptions flags_filter_options; if (context_->GetMinSdkVersion() > SDK_UPSIDE_DOWN_CAKE) { // For API version > U, PackageManager will dynamically read the flag values and disable // manifest elements accordingly when parsing the manifest. // For API version <= U, we remove disabled elements from the manifest with the filter. flags_filter_options.remove_disabled_elements = false; flags_filter_options.flags_must_have_value = false; } FeatureFlagsFilter flags_filter(options_.feature_flag_values, flags_filter_options); if (!flags_filter.Consume(context_, manifest_xml.get())) { return 1; } // Override the package ID when it is "android". // Override the package ID when it is "android". if (context_->GetCompilationPackage() == "android") { if (context_->GetCompilationPackage() == "android") { context_->SetPackageId(kAndroidPackageId); context_->SetPackageId(kAndroidPackageId); Loading Loading @@ -2530,7 +2544,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) { } } for (const std::string& arg : all_feature_flags_args) { for (const std::string& arg : all_feature_flags_args) { if (ParseFeatureFlagsParameter(arg, context.GetDiagnostics(), &options_.feature_flag_values)) { if (!ParseFeatureFlagsParameter(arg, context.GetDiagnostics(), &options_.feature_flag_values)) { return 1; return 1; } } } } Loading tools/aapt2/cmd/Link.h +5 −1 Original line number Original line Diff line number Diff line Loading @@ -330,7 +330,11 @@ class LinkCommand : public Command { "should only be used together with the --static-lib flag.", "should only be used together with the --static-lib flag.", &options_.merge_only); &options_.merge_only); AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); AddOptionalFlagList("--feature-flags", "Placeholder, to be implemented.", &feature_flags_args_); AddOptionalFlagList("--feature-flags", "Specify the values of feature flags. The pairs in the argument\n" "are separated by ',' and the name is separated from the value by '='.\n" "Example: \"flag1=true,flag2=false,flag3=\" (flag3 has no given value).", &feature_flags_args_); } } int Action(const std::vector<std::string>& args) override; int Action(const std::vector<std::string>& args) override; Loading tools/aapt2/cmd/Link_test.cpp +211 −3 Original line number Original line Diff line number Diff line Loading @@ -16,11 +16,10 @@ #include "Link.h" #include "Link.h" #include <android-base/file.h> #include "AppInfo.h" #include "Diagnostics.h" #include "Diagnostics.h" #include "LoadedApk.h" #include "LoadedApk.h" #include "android-base/file.h" #include "android-base/stringprintf.h" #include "test/Test.h" #include "test/Test.h" using testing::Eq; using testing::Eq; Loading Loading @@ -993,4 +992,213 @@ TEST_F(LinkTest, LocaleConfigWrongLocaleFormat) { ASSERT_FALSE(Link(link_args, &diag)); ASSERT_FALSE(Link(link_args, &diag)); } } static void BuildSDKWithFeatureFlagAttr(const std::string& apk_path, const std::string& java_path, CommandTestFixture* fixture, android::IDiagnostics* diag) { const std::string android_values = R"(<resources> <staging-public-group type="attr" first-id="0x01fe0063"> <public name="featureFlag" /> </staging-public-group> <attr name="featureFlag" format="string" /> </resources>)"; SourceXML source_xml{.res_file_path = "/res/values/values.xml", .file_contents = android_values}; BuildSDK({source_xml}, apk_path, java_path, fixture, diag); } TEST_F(LinkTest, FeatureFlagDisabled_SdkAtMostUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_UPSIDE_DOWN_CAKE); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag=false"); const std::string app_apk = GetTestPath("app.apk"); BuildApk({}, app_apk, std::move(app_link_args), this, &diag); // Permission element should be removed if flag is disabled auto apk = LoadedApk::LoadApkFromPath(app_apk, &diag); ASSERT_THAT(apk, NotNull()); auto apk_manifest = apk->GetManifest(); ASSERT_THAT(apk_manifest, NotNull()); auto root = apk_manifest->root.get(); ASSERT_THAT(root, NotNull()); auto maybe_removed = root->FindChild({}, "permission"); ASSERT_THAT(maybe_removed, IsNull()); } TEST_F(LinkTest, FeatureFlagEnabled_SdkAtMostUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_UPSIDE_DOWN_CAKE); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag=true"); const std::string app_apk = GetTestPath("app.apk"); BuildApk({}, app_apk, std::move(app_link_args), this, &diag); // Permission element should be kept if flag is enabled auto apk = LoadedApk::LoadApkFromPath(app_apk, &diag); ASSERT_THAT(apk, NotNull()); auto apk_manifest = apk->GetManifest(); ASSERT_THAT(apk_manifest, NotNull()); auto root = apk_manifest->root.get(); ASSERT_THAT(root, NotNull()); auto maybe_removed = root->FindChild({}, "permission"); ASSERT_THAT(maybe_removed, NotNull()); } TEST_F(LinkTest, FeatureFlagWithNoValue_SdkAtMostUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_UPSIDE_DOWN_CAKE); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag="); // Flags must have values if <= UDC const std::string app_apk = GetTestPath("app.apk"); ASSERT_FALSE(Link(app_link_args.Build(app_apk), &diag)); } TEST_F(LinkTest, FeatureFlagDisabled_SdkAfterUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_CUR_DEVELOPMENT); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag=false"); const std::string app_apk = GetTestPath("app.apk"); BuildApk({}, app_apk, std::move(app_link_args), this, &diag); // Permission element should be kept if > UDC, regardless of flag value auto apk = LoadedApk::LoadApkFromPath(app_apk, &diag); ASSERT_THAT(apk, NotNull()); auto apk_manifest = apk->GetManifest(); ASSERT_THAT(apk_manifest, NotNull()); auto root = apk_manifest->root.get(); ASSERT_THAT(root, NotNull()); auto maybe_removed = root->FindChild({}, "permission"); ASSERT_THAT(maybe_removed, NotNull()); } TEST_F(LinkTest, FeatureFlagEnabled_SdkAfterUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_CUR_DEVELOPMENT); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag=true"); const std::string app_apk = GetTestPath("app.apk"); BuildApk({}, app_apk, std::move(app_link_args), this, &diag); // Permission element should be kept if > UDC, regardless of flag value auto apk = LoadedApk::LoadApkFromPath(app_apk, &diag); ASSERT_THAT(apk, NotNull()); auto apk_manifest = apk->GetManifest(); ASSERT_THAT(apk_manifest, NotNull()); auto root = apk_manifest->root.get(); ASSERT_THAT(root, NotNull()); auto maybe_removed = root->FindChild({}, "permission"); ASSERT_THAT(maybe_removed, NotNull()); } TEST_F(LinkTest, FeatureFlagWithNoValue_SdkAfterUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_CUR_DEVELOPMENT); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag="); const std::string app_apk = GetTestPath("app.apk"); BuildApk({}, app_apk, std::move(app_link_args), this, &diag); // Permission element should be kept if > UDC, regardless of flag value auto apk = LoadedApk::LoadApkFromPath(app_apk, &diag); ASSERT_THAT(apk, NotNull()); auto apk_manifest = apk->GetManifest(); ASSERT_THAT(apk_manifest, NotNull()); auto root = apk_manifest->root.get(); ASSERT_THAT(root, NotNull()); auto maybe_removed = root->FindChild({}, "permission"); ASSERT_THAT(maybe_removed, NotNull()); } } // namespace aapt } // namespace aapt Loading
tools/aapt2/cmd/Link.cpp +15 −1 Original line number Original line Diff line number Diff line Loading @@ -56,6 +56,7 @@ #include "java/JavaClassGenerator.h" #include "java/JavaClassGenerator.h" #include "java/ManifestClassGenerator.h" #include "java/ManifestClassGenerator.h" #include "java/ProguardRules.h" #include "java/ProguardRules.h" #include "link/FeatureFlagsFilter.h" #include "link/Linkers.h" #include "link/Linkers.h" #include "link/ManifestFixer.h" #include "link/ManifestFixer.h" #include "link/NoDefaultResourceRemover.h" #include "link/NoDefaultResourceRemover.h" Loading Loading @@ -1986,6 +1987,19 @@ class Linker { context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()}); context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()}); context_->SetSplitNameDependencies(app_info_.split_name_dependencies); context_->SetSplitNameDependencies(app_info_.split_name_dependencies); FeatureFlagsFilterOptions flags_filter_options; if (context_->GetMinSdkVersion() > SDK_UPSIDE_DOWN_CAKE) { // For API version > U, PackageManager will dynamically read the flag values and disable // manifest elements accordingly when parsing the manifest. // For API version <= U, we remove disabled elements from the manifest with the filter. flags_filter_options.remove_disabled_elements = false; flags_filter_options.flags_must_have_value = false; } FeatureFlagsFilter flags_filter(options_.feature_flag_values, flags_filter_options); if (!flags_filter.Consume(context_, manifest_xml.get())) { return 1; } // Override the package ID when it is "android". // Override the package ID when it is "android". if (context_->GetCompilationPackage() == "android") { if (context_->GetCompilationPackage() == "android") { context_->SetPackageId(kAndroidPackageId); context_->SetPackageId(kAndroidPackageId); Loading Loading @@ -2530,7 +2544,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) { } } for (const std::string& arg : all_feature_flags_args) { for (const std::string& arg : all_feature_flags_args) { if (ParseFeatureFlagsParameter(arg, context.GetDiagnostics(), &options_.feature_flag_values)) { if (!ParseFeatureFlagsParameter(arg, context.GetDiagnostics(), &options_.feature_flag_values)) { return 1; return 1; } } } } Loading
tools/aapt2/cmd/Link.h +5 −1 Original line number Original line Diff line number Diff line Loading @@ -330,7 +330,11 @@ class LinkCommand : public Command { "should only be used together with the --static-lib flag.", "should only be used together with the --static-lib flag.", &options_.merge_only); &options_.merge_only); AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); AddOptionalFlagList("--feature-flags", "Placeholder, to be implemented.", &feature_flags_args_); AddOptionalFlagList("--feature-flags", "Specify the values of feature flags. The pairs in the argument\n" "are separated by ',' and the name is separated from the value by '='.\n" "Example: \"flag1=true,flag2=false,flag3=\" (flag3 has no given value).", &feature_flags_args_); } } int Action(const std::vector<std::string>& args) override; int Action(const std::vector<std::string>& args) override; Loading
tools/aapt2/cmd/Link_test.cpp +211 −3 Original line number Original line Diff line number Diff line Loading @@ -16,11 +16,10 @@ #include "Link.h" #include "Link.h" #include <android-base/file.h> #include "AppInfo.h" #include "Diagnostics.h" #include "Diagnostics.h" #include "LoadedApk.h" #include "LoadedApk.h" #include "android-base/file.h" #include "android-base/stringprintf.h" #include "test/Test.h" #include "test/Test.h" using testing::Eq; using testing::Eq; Loading Loading @@ -993,4 +992,213 @@ TEST_F(LinkTest, LocaleConfigWrongLocaleFormat) { ASSERT_FALSE(Link(link_args, &diag)); ASSERT_FALSE(Link(link_args, &diag)); } } static void BuildSDKWithFeatureFlagAttr(const std::string& apk_path, const std::string& java_path, CommandTestFixture* fixture, android::IDiagnostics* diag) { const std::string android_values = R"(<resources> <staging-public-group type="attr" first-id="0x01fe0063"> <public name="featureFlag" /> </staging-public-group> <attr name="featureFlag" format="string" /> </resources>)"; SourceXML source_xml{.res_file_path = "/res/values/values.xml", .file_contents = android_values}; BuildSDK({source_xml}, apk_path, java_path, fixture, diag); } TEST_F(LinkTest, FeatureFlagDisabled_SdkAtMostUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_UPSIDE_DOWN_CAKE); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag=false"); const std::string app_apk = GetTestPath("app.apk"); BuildApk({}, app_apk, std::move(app_link_args), this, &diag); // Permission element should be removed if flag is disabled auto apk = LoadedApk::LoadApkFromPath(app_apk, &diag); ASSERT_THAT(apk, NotNull()); auto apk_manifest = apk->GetManifest(); ASSERT_THAT(apk_manifest, NotNull()); auto root = apk_manifest->root.get(); ASSERT_THAT(root, NotNull()); auto maybe_removed = root->FindChild({}, "permission"); ASSERT_THAT(maybe_removed, IsNull()); } TEST_F(LinkTest, FeatureFlagEnabled_SdkAtMostUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_UPSIDE_DOWN_CAKE); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag=true"); const std::string app_apk = GetTestPath("app.apk"); BuildApk({}, app_apk, std::move(app_link_args), this, &diag); // Permission element should be kept if flag is enabled auto apk = LoadedApk::LoadApkFromPath(app_apk, &diag); ASSERT_THAT(apk, NotNull()); auto apk_manifest = apk->GetManifest(); ASSERT_THAT(apk_manifest, NotNull()); auto root = apk_manifest->root.get(); ASSERT_THAT(root, NotNull()); auto maybe_removed = root->FindChild({}, "permission"); ASSERT_THAT(maybe_removed, NotNull()); } TEST_F(LinkTest, FeatureFlagWithNoValue_SdkAtMostUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_UPSIDE_DOWN_CAKE); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag="); // Flags must have values if <= UDC const std::string app_apk = GetTestPath("app.apk"); ASSERT_FALSE(Link(app_link_args.Build(app_apk), &diag)); } TEST_F(LinkTest, FeatureFlagDisabled_SdkAfterUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_CUR_DEVELOPMENT); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag=false"); const std::string app_apk = GetTestPath("app.apk"); BuildApk({}, app_apk, std::move(app_link_args), this, &diag); // Permission element should be kept if > UDC, regardless of flag value auto apk = LoadedApk::LoadApkFromPath(app_apk, &diag); ASSERT_THAT(apk, NotNull()); auto apk_manifest = apk->GetManifest(); ASSERT_THAT(apk_manifest, NotNull()); auto root = apk_manifest->root.get(); ASSERT_THAT(root, NotNull()); auto maybe_removed = root->FindChild({}, "permission"); ASSERT_THAT(maybe_removed, NotNull()); } TEST_F(LinkTest, FeatureFlagEnabled_SdkAfterUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_CUR_DEVELOPMENT); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag=true"); const std::string app_apk = GetTestPath("app.apk"); BuildApk({}, app_apk, std::move(app_link_args), this, &diag); // Permission element should be kept if > UDC, regardless of flag value auto apk = LoadedApk::LoadApkFromPath(app_apk, &diag); ASSERT_THAT(apk, NotNull()); auto apk_manifest = apk->GetManifest(); ASSERT_THAT(apk_manifest, NotNull()); auto root = apk_manifest->root.get(); ASSERT_THAT(root, NotNull()); auto maybe_removed = root->FindChild({}, "permission"); ASSERT_THAT(maybe_removed, NotNull()); } TEST_F(LinkTest, FeatureFlagWithNoValue_SdkAfterUDC) { StdErrDiagnostics diag; const std::string android_apk = GetTestPath("android.apk"); const std::string android_java = GetTestPath("android-java"); BuildSDKWithFeatureFlagAttr(android_apk, android_java, this, &diag); const std::string manifest_contents = android::base::StringPrintf( R"(<uses-sdk android:minSdkVersion="%d" />" <permission android:name="FOO" android:featureFlag="flag" />)", SDK_CUR_DEVELOPMENT); auto app_manifest = ManifestBuilder(this) .SetPackageName("com.example.app") .AddContents(manifest_contents) .Build(); auto app_link_args = LinkCommandBuilder(this) .SetManifestFile(app_manifest) .AddParameter("-I", android_apk) .AddParameter("--feature-flags", "flag="); const std::string app_apk = GetTestPath("app.apk"); BuildApk({}, app_apk, std::move(app_link_args), this, &diag); // Permission element should be kept if > UDC, regardless of flag value auto apk = LoadedApk::LoadApkFromPath(app_apk, &diag); ASSERT_THAT(apk, NotNull()); auto apk_manifest = apk->GetManifest(); ASSERT_THAT(apk_manifest, NotNull()); auto root = apk_manifest->root.get(); ASSERT_THAT(root, NotNull()); auto maybe_removed = root->FindChild({}, "permission"); ASSERT_THAT(maybe_removed, NotNull()); } } // namespace aapt } // namespace aapt