diff --git a/src/tools/java/com/google/devtools/build/android/AndroidCompiledDataDeserializer.java b/src/tools/java/com/google/devtools/build/android/AndroidCompiledDataDeserializer.java index a71d7bf17..d602169a5 100644 --- a/src/tools/java/com/google/devtools/build/android/AndroidCompiledDataDeserializer.java +++ b/src/tools/java/com/google/devtools/build/android/AndroidCompiledDataDeserializer.java @@ -549,7 +549,13 @@ private static ImmutableList computeQualifiers(Configuration protoConfig ImmutableList.Builder result = ImmutableList.builderWithExpectedSize(qualifiers.length); for (ResourceQualifier qualifier : qualifiers) { if (qualifier != null) { - result.add(qualifier.getFolderSegment()); + // sdk-common renders the valid zero MNC as an empty folder segment. + if (qualifier instanceof NetworkCodeQualifier + && ((NetworkCodeQualifier) qualifier).getCode() == 0) { + result.add("mnc000"); + } else { + result.add(qualifier.getFolderSegment()); + } } } return result.build(); diff --git a/src/tools/javatests/com/google/devtools/build/android/BUILD b/src/tools/javatests/com/google/devtools/build/android/BUILD index eb0bfddf2..fcd410997 100644 --- a/src/tools/javatests/com/google/devtools/build/android/BUILD +++ b/src/tools/javatests/com/google/devtools/build/android/BUILD @@ -107,6 +107,7 @@ java_test( ":guava", ":test_utils", "//src/tools/java/com/google/devtools/build/android:android_builder_lib", + "@rules_android_maven//:com_android_tools_build_aapt2_proto", "@rules_android_maven//:com_google_jimfs_jimfs", "@rules_android_maven//:com_google_truth_truth", "@rules_android_maven//:junit_junit", diff --git a/src/tools/javatests/com/google/devtools/build/android/dexer/BUILD b/src/tools/javatests/com/google/devtools/build/android/dexer/BUILD index ba4166406..5f1896953 100644 --- a/src/tools/javatests/com/google/devtools/build/android/dexer/BUILD +++ b/src/tools/javatests/com/google/devtools/build/android/dexer/BUILD @@ -29,6 +29,7 @@ java_library( "@androidsdk//:has_androidsdk": [ "DexFileSplitterTest.java", "DexLimitTrackerTest.java", + "ZipEntryComparatorTest.java", ], "//conditions:default": ["NoAndroidSdkStubTest.java"], }), diff --git a/test/tools/android/BUILD b/test/tools/android/BUILD new file mode 100644 index 000000000..afc8cc520 --- /dev/null +++ b/test/tools/android/BUILD @@ -0,0 +1,14 @@ +load("@rules_shell//shell:sh_test.bzl", "sh_test") + +sh_test( + name = "build_java8_legacy_dex_test", + size = "small", + srcs = ["build_java8_legacy_dex_test.sh"], + args = [ + "$(rlocationpath //tools/android:build_java8_legacy_dex.sh)", + ], + data = [ + "//tools/android:build_java8_legacy_dex.sh", + ], + deps = ["@rules_shell//shell/runfiles"], +) diff --git a/test/tools/android/build_java8_legacy_dex_test.sh b/test/tools/android/build_java8_legacy_dex_test.sh new file mode 100755 index 000000000..9c968c2da --- /dev/null +++ b/test/tools/android/build_java8_legacy_dex_test.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# Copyright 2026 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. + +# Verify both Unix and Windows Java launcher names using manifest-only runfiles. +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +set -euo pipefail +script="$(rlocation "$1")" +runfiles_library="$(rlocation bazel_tools/tools/bash/runfiles/runfiles.bash)" +work=$(mktemp -d) +trap 'rm -rf "$work"' EXIT +export TOOL_LOG="$work/tools.log" + +cat > "$work/tool" <<'TOOL' +#!/usr/bin/env bash +set -eu +basename "$0" >> "$TOOL_LOG" +while [[ $# -gt 0 ]]; do + if [[ "$1" == --output ]]; then + echo output > "$2" + break + fi + shift +done +TOOL +chmod +x "$work/tool" +echo '--min-api 21' > "$work/params" +touch "$work/libs.jar" "$work/minify.pgcfg" + +for suffix in '' .exe; do + manifest="$work/MANIFEST" + cat > "$manifest" <> "$manifest" + done + export RUNFILES_DIR='' RUNFILES_MANIFEST_FILE="$manifest" + : > "$TOOL_LOG" + bash "$script" --android_jar "$work/libs.jar" --output "$work/dex.zip" + test -s "$work/dex.zip" + bash "$script" --android_jar "$work/libs.jar" --binary "$work/libs.jar" \ + --output "$work/shrunk.zip" --output_map "$work/map" + test -s "$work/shrunk.zip" + printf 'd8%s\ntracereferences%s\nr8%s\n' "$suffix" "$suffix" "$suffix" > "$work/expected" + diff "$work/expected" "$TOOL_LOG" + rm "$work/dex.zip" "$work/shrunk.zip" +done diff --git a/tools/android/BUILD b/tools/android/BUILD index 467ba3ef7..d01d2dbf5 100644 --- a/tools/android/BUILD +++ b/tools/android/BUILD @@ -9,6 +9,11 @@ package( default_visibility = ["//visibility:public"], ) +exports_files( + ["build_java8_legacy_dex.sh"], + visibility = ["//test/tools/android:__pkg__"], +) + config_setting( name = "minimal_desugaring", values = { diff --git a/tools/android/build_java8_legacy_dex.sh b/tools/android/build_java8_legacy_dex.sh index 6d4bcc264..81c03f037 100755 --- a/tools/android/build_java8_legacy_dex.sh +++ b/tools/android/build_java8_legacy_dex.sh @@ -28,6 +28,16 @@ source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ set -eu +# Java launchers have an .exe suffix on Windows. Match d8_desugar.sh's fallback. +function rlocation_executable() { + local executable + executable="$(rlocation "$1")" + if [[ ! -f "${executable}" ]]; then + executable="$(rlocation "$1.exe")" + fi + printf '%s\n' "${executable}" +} + # Keep rules generated by tracereferences. rules= # android.jar library. @@ -81,7 +91,7 @@ if [[ -n "${binary_jar}" ]]; then if [[ -z "${rules}" ]]; then rules="${tmpdir}/rules.pgcfg" fi - "$(rlocation rules_android/tools/android/tracereferences)" \ + "$(rlocation_executable rules_android/tools/android/tracereferences)" \ --map-diagnostics:MissingDefinitionsDiagnostic error warning \ --keep-rules \ --lib "${android_jar}" \ @@ -98,7 +108,7 @@ if [[ -n "${binary_jar}" ]]; then fi else # Shrink desugared library and convert to DEX. - "$(rlocation rules_android/tools/android/r8)" \ + "$(rlocation_executable rules_android/tools/android/r8)" \ --min-api "${min_api}" \ --no-desugaring \ --lib "${android_jar}" \ @@ -112,5 +122,5 @@ if [[ -n "${binary_jar}" ]]; then rm -rf "${tmpdir}" else # No shrinking just convert to DEX. - "$(rlocation rules_android/tools/android/d8)" --min-api "${min_api}" --no-desugaring --lib "${android_jar}" --output "${dest}" "${todex}" + "$(rlocation_executable rules_android/tools/android/d8)" --min-api "${min_api}" --no-desugaring --lib "${android_jar}" --output "${dest}" "${todex}" fi