Pass custom_package to internal android_binary in android_sandboxed_sdk. This is critical for accessing resources in sandboxed SDKs. PiperOrigin-RevId: 643971020 Change-Id: Ibc41332ab5b54dc61244e06ba9e54cf680d851ae
diff --git a/rules/android_sandboxed_sdk/android_sandboxed_sdk_macro.bzl b/rules/android_sandboxed_sdk/android_sandboxed_sdk_macro.bzl index 61909bf..473ce05 100644 --- a/rules/android_sandboxed_sdk/android_sandboxed_sdk_macro.bzl +++ b/rules/android_sandboxed_sdk/android_sandboxed_sdk_macro.bzl
@@ -33,6 +33,7 @@ visibility(PROJECT_VISIBILITY) _ATTRS = dict( + java_package_name = attr.string(), sdk_modules_config = attr.label( allow_single_file = [".pb.json"], ), @@ -47,6 +48,15 @@ ) def _impl(ctx): + validation = ctx.actions.declare_file(ctx.label.name + "_validation") + _sandboxed_sdk_toolbox.validate_modules_config( + ctx, + output = validation, + sdk_module_config = ctx.file.sdk_modules_config, + java_package_name = ctx.attr.java_package_name, + sandboxed_sdk_toolbox = _get_android_toolchain(ctx).sandboxed_sdk_toolbox.files_to_run, + host_javabase = _common.get_host_javabase(ctx), + ) sdk_api_descriptors = ctx.actions.declare_file(ctx.label.name + "_sdk_api_descriptors.jar") _sandboxed_sdk_toolbox.extract_api_descriptors( ctx, @@ -64,6 +74,7 @@ sdk_module_config = ctx.file.sdk_modules_config, sdk_api_descriptors = sdk_api_descriptors, ), + OutputGroupInfo(_validation = depset([validation])), ] _android_sandboxed_sdk = rule( @@ -99,7 +110,8 @@ visibility: A list of targets allowed to depend on this rule. testonly: Whether this library is only for testing. tags: A list of string tags passed to generated targets. - custom_package: Java package for resources, + custom_package: Java package for resources. This needs to be the same as the package set in + the sdk_modules_config. android_binary: android_binary rule used to create the intermediate SDK APK. """ fully_qualified_name = "//%s:%s" % (native.package_name(), name) @@ -130,11 +142,13 @@ testonly = testonly, tags = tags, use_r_package = True, + custom_package = custom_package, ) sdk_deploy_jar = Label("%s_deploy.jar" % bin_fqn) _android_sandboxed_sdk( name = name, + java_package_name = package, sdk_modules_config = sdk_modules_config, visibility = visibility, testonly = testonly,
diff --git a/rules/sandboxed_sdk_toolbox.bzl b/rules/sandboxed_sdk_toolbox.bzl index 5120def..7801cce 100644 --- a/rules/sandboxed_sdk_toolbox.bzl +++ b/rules/sandboxed_sdk_toolbox.bzl
@@ -302,6 +302,39 @@ progress_message = "Generate SDK split properties %s" % output.short_path, ) +def _validate_modules_config( + ctx, + output = None, + sdk_module_config = None, + java_package_name = None, + sandboxed_sdk_toolbox = None, + host_javabase = None): + """Validates an SDK modules config file and ensures it has a valid package name. + + Args: + ctx: The context. + output: The output file. It will only be created if the validation succeeds. + sdk_module_config: SDK Module config JSON file form an SDK bundle. + java_package_name: The java package name to use for the SDK. + sandboxed_sdk_toolbox: Toolbox executable files. + host_javabase: Javabase used to run the toolbox. + """ + args = ctx.actions.args() + args.add("validate-modules-config") + args.add("--sdk-modules-config", sdk_module_config) + args.add("--java-package-name", java_package_name) + args.add("--output", output) + _java.run( + ctx = ctx, + host_javabase = host_javabase, + executable = sandboxed_sdk_toolbox, + arguments = [args], + inputs = [sdk_module_config], + outputs = [output], + mnemonic = "ValidateModulesConfig", + progress_message = "Validating SDK modules config %s" % output.short_path, + ) + sandboxed_sdk_toolbox = struct( extract_api_descriptors = _extract_api_descriptors, extract_api_descriptors_from_asar = _extract_api_descriptors_from_asar, @@ -310,4 +343,5 @@ generate_runtime_enabled_sdk_table = _generate_runtime_enabled_sdk_table, generate_sdk_dependencies_manifest = _generate_sdk_dependencies_manifest, generate_sdk_split_properties = _generate_sdk_split_properties, + validate_modules_config = _validate_modules_config, )
diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/BUILD b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/BUILD index 0ae13b0..2fbf67c 100644 --- a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/BUILD +++ b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/BUILD
@@ -18,6 +18,7 @@ "//src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/runtimeenabledsdkconfig", "//src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdkdependenciesmanifest", "//src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/sdksplitproperties", + "//src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig", "@rules_android_maven//:info_picocli_picocli", ], )
diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/SandboxedSdkToolbox.java b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/SandboxedSdkToolbox.java index ff0278a..f6447b9 100644 --- a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/SandboxedSdkToolbox.java +++ b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/SandboxedSdkToolbox.java
@@ -22,6 +22,7 @@ import com.google.devtools.build.android.sandboxedsdktoolbox.runtimeenabledsdkconfig.GenerateRuntimeEnabledSdkTableCommand; import com.google.devtools.build.android.sandboxedsdktoolbox.sdkdependenciesmanifest.GenerateSdkDependenciesManifestCommand; import com.google.devtools.build.android.sandboxedsdktoolbox.sdksplitproperties.GenerateSdkSplitPropertiesCommand; +import com.google.devtools.build.android.sandboxedsdktoolbox.validatemodulesconfig.ValidateModulesConfigCommand; import picocli.CommandLine; import picocli.CommandLine.Command; @@ -36,6 +37,7 @@ GenerateRuntimeEnabledSdkTableCommand.class, GenerateSdkDependenciesManifestCommand.class, GenerateSdkSplitPropertiesCommand.class, + ValidateModulesConfigCommand.class, }) public final class SandboxedSdkToolbox {
diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/BUILD b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/BUILD new file mode 100644 index 0000000..9e013f4 --- /dev/null +++ b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/BUILD
@@ -0,0 +1,17 @@ +# Command to validate SDK modules config. + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//:__subpackages__"], +) + +licenses(["notice"]) + +java_library( + name = "validatemodulesconfig", + srcs = glob(["*.java"]), + deps = [ + "//src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/info", + "@rules_android_maven//:info_picocli_picocli", + ], +)
diff --git a/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/ValidateModulesConfigCommand.java b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/ValidateModulesConfigCommand.java new file mode 100644 index 0000000..f12dc88 --- /dev/null +++ b/src/tools/java/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/ValidateModulesConfigCommand.java
@@ -0,0 +1,64 @@ +/* + * Copyright 2024 The Bazel Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.devtools.build.android.sandboxedsdktoolbox.validatemodulesconfig; + +import com.google.devtools.build.android.sandboxedsdktoolbox.info.SdkInfo; +import com.google.devtools.build.android.sandboxedsdktoolbox.info.SdkInfoReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; + +/** Checks if the given modules config is valid and compatible with other build parameters. */ +@Command( + name = "validate-modules-config", + description = + "Checks if the given modules config is valid and compatible with other build" + + " parameters.") +public final class ValidateModulesConfigCommand implements Runnable { + + @Option(names = "--sdk-modules-config", required = true) + Path sdkModuleConfigPath; + + @Option(names = "--java-package-name", required = true) + String javaPackageName; + + @Option(names = "--output", required = true) + Path output; + + @Override + public void run() { + SdkInfo info = SdkInfoReader.readFromSdkModuleJsonFile(sdkModuleConfigPath); + + if (!info.getPackageName().equals(javaPackageName)) { + throw new IllegalArgumentException( + String.format( + "The package name in the modules config (%s) does not match the java package name " + + "(%s). This causes runtime errors when running the SDK as a split APK.", + info.getPackageName(), javaPackageName)); + } + + try { + // Empty file representing a successful validation. + Files.createFile(output); + } catch (IOException e) { + throw new IllegalStateException("Failed to create output file", e); + } + } + + private ValidateModulesConfigCommand() {} +}
diff --git a/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/BUILD b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/BUILD new file mode 100644 index 0000000..38470ea --- /dev/null +++ b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/BUILD
@@ -0,0 +1,22 @@ +# Tests for validate-modules-config command. + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//:__subpackages__"], +) + +licenses(["notice"]) + +java_test( + name = "ValidateModulesConfigCommandTest", + size = "small", + srcs = ["ValidateModulesConfigCommandTest.java"], + data = glob(["testdata/*"]), + deps = [ + "//src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/utils", + "@rules_android_maven//:com_android_tools_build_bundletool", + "@rules_android_maven//:com_google_protobuf_protobuf_java_util", + "@rules_android_maven//:com_google_truth_truth", + "@rules_android_maven//:junit_junit", + ], +)
diff --git a/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/ValidateModulesConfigCommandTest.java b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/ValidateModulesConfigCommandTest.java new file mode 100644 index 0000000..4d5deea --- /dev/null +++ b/src/tools/javatests/com/google/devtools/build/android/sandboxedsdktoolbox/validatemodulesconfig/ValidateModulesConfigCommandTest.java
@@ -0,0 +1,81 @@ +/* + * Copyright 2024 The Bazel Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.devtools.build.android.sandboxedsdktoolbox.validatemodulesconfig; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.android.sandboxedsdktoolbox.utils.Runner.runCommand; + +import com.android.bundle.SdkModulesConfigOuterClass.SdkModulesConfig; +import com.google.devtools.build.android.sandboxedsdktoolbox.utils.CommandResult; +import com.google.protobuf.util.JsonFormat; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class ValidateModulesConfigCommandTest { + + @Rule public final TemporaryFolder testFolder = new TemporaryFolder(); + + @Test + public void modulesConfig_withTheSameJavaPackage_succeeds() throws Exception { + SdkModulesConfig config = + SdkModulesConfig.newBuilder().setSdkPackageName("com.example.package").build(); + String javaPackageName = "com.example.package"; + Path output = testFolder.getRoot().toPath().resolve("output"); + + CommandResult result = runValidateCommand(config, javaPackageName, output); + + assertThat(result.getOutput()).isEmpty(); + assertThat(result.getStatusCode()).isEqualTo(0); + assertThat(Files.exists(output)).isTrue(); + } + + @Test + public void modulesConfig_withMismatchedJavaPackage_failsValidation() throws Exception { + SdkModulesConfig config = + SdkModulesConfig.newBuilder().setSdkPackageName("com.example.package").build(); + String javaPackageName = "com.example.package.different"; + Path output = testFolder.getRoot().toPath().resolve("output"); + + CommandResult result = runValidateCommand(config, javaPackageName, output); + + assertThat(result.getOutput()) + .contains( + "The package name in the modules config (com.example.package) does not match the java" + + " package name (com.example.package.different)"); + assertThat(result.getStatusCode()).isEqualTo(1); + assertThat(Files.exists(output)).isFalse(); + } + + private CommandResult runValidateCommand( + SdkModulesConfig config, String javaPackageName, Path output) throws Exception { + Path sdkModulesConfigPath = testFolder.getRoot().toPath().resolve("sdk-modules-config.pb.json"); + Files.writeString(sdkModulesConfigPath, JsonFormat.printer().print(config)); + return runCommand( + "validate-modules-config", + "--sdk-modules-config", + sdkModulesConfigPath.toString(), + "--java-package-name", + javaPackageName, + "--output", + output.toString()); + } +}