1#!/bin/bash 2# 3# Copyright 2023 The Bazel Authors. All rights reserved. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17# --- begin runfiles.bash initialization v2 --- 18# Copy-pasted from the Bazel Bash runfiles library v2. 19set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash 20source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ 21 source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ 22 source "$0.runfiles/$f" 2>/dev/null || \ 23 source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ 24 source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ 25 { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e 26# --- end runfiles.bash initialization v2 --- 27 28source "$(rlocation rules_android/test/bashunit/unittest.bash)" || \ 29 (echo >&2 "Failed to locate bashunit.sh" && exit 1) 30 31function set_up() { 32 # Clean out the repository. 33 rm -rf * 34 touch WORKSPACE 35 36 # Clean out the test android SDK if any 37 rm -rf "${TEST_TMPDIR}/android_sdk" 38 39 # Make sure the rules exist and seed the WORKSPACE. 40 rm -rf "${TEST_TMPDIR}/android_sdk_repository_src" 41 set_up_rules 42} 43 44function set_up_rules() { 45 local android_revision_rule="$(rlocation rules_android/rules/android_revision.bzl)" 46 47 local repo_rule="$(rlocation rules_android/rules/android_sdk_repository/rule.bzl)" 48 local repo_rule_dir="$(dirname "${repo_rule}")" 49 local dest_dir="${TEST_TMPDIR}/android_sdk_repository_src" 50 mkdir -p "${dest_dir}/rules/android_sdk_repository" 51 cp -r "${repo_rule_dir}"/* "${dest_dir}/rules/android_sdk_repository" 52 cat > "${dest_dir}/WORKSPACE" <<EOF 53workspace(name = "android_sdk_repository_src") 54EOF 55 cat > "${dest_dir}/rules/BUILD" <<EOF 56exports_files(["*.bzl"]) 57EOF 58 cp "${android_revision_rule}" "${dest_dir}/rules/" 59 cat > "${dest_dir}/rules/android_sdk_repository/BUILD" <<EOF 60exports_files(["*.bzl"]) 61EOF 62 63 cat >> WORKSPACE <<EOF 64local_repository( 65 name = "android_sdk_repository_src", 66 path = "${dest_dir}", 67) 68load("@android_sdk_repository_src//rules/android_sdk_repository:rule.bzl", "android_sdk_repository") 69EOF 70} 71 72function create_android_sdk() { 73 # Create a fake Android SDK that will be available for the repository rule. 74 local location="${TEST_TMPDIR}/android_sdk" 75 mkdir -p "${location}" 76 77 mkdir "${location}/platform-tools" 78 touch "${location}/platform-tools/adb" 79 80 echo "${location}" 81} 82 83function add_platforms() { 84 local sdk_path="${1}" 85 shift 86 87 # Add all requested API levels 88 for level in "$@"; do 89 local dir="${sdk_path}/platforms/android-${level}" 90 mkdir -p "${dir}" 91 touch "${dir}/android.jar" 92 touch "${dir}/framework.aidl" 93 94 local system_image_dir="${sdk_path}/system-images/android-${level}" 95 mkdir -p "${system_image_dir}/default/arm64-v8a" 96 mkdir -p "${system_image_dir}/default/x86_64" 97 done 98} 99 100function add_build_tools() { 101 local sdk_path="${1}" 102 shift 103 104 # Add all requested tools 105 for version in "$@"; do 106 local dir="${sdk_path}/build-tools/${version}" 107 mkdir -p "${dir}/lib" 108 touch "${dir}/aapt" 109 touch "${dir}/aidl" 110 touch "${dir}/lib/apksigner.jar" 111 touch "${dir}/lib/d8.jar" 112 touch "${dir}/lib/dx.jar" 113 touch "${dir}/mainDexClasses.rules" 114 touch "${dir}/zipalign" 115 done 116} 117 118function create_android_sdk_basic() { 119 local sdk_path="$(create_android_sdk)" 120 add_platforms "${sdk_path}" 31 121 add_build_tools "${sdk_path}" 30.0.3 122 echo "${sdk_path}" 123} 124 125function create_verify() { 126 mkdir verify 127 cat > verify/BUILD <<EOF 128genrule( 129 name = "check_sdk", 130 outs = ["check_sdk.log"], 131 cmd = select({ 132 "@androidsdk//:has_androidsdk": "echo sdk present > \$@", 133 "//conditions:default": "echo sdk missing > \$@", 134 }), 135) 136EOF 137 138 "${BIT_BAZEL_BINARY}" build //verify:check_sdk >& $TEST_log || fail "Expected success" 139 cat bazel-bin/verify/check_sdk.log >$TEST_log 140} 141 142function verify_no_android_sdk() { 143 create_verify 144 expect_log "sdk missing" 145} 146 147function verify_android_sdk() { 148 create_verify 149 expect_log "sdk present" 150 "${BIT_BAZEL_BINARY}" query @androidsdk//:files >& $TEST_log || fail "Expected to exist" 151} 152 153function write_platforms() { 154 mkdir -p platforms 155 cat > platforms/BUILD <<EOF 156platform( 157 name = "arm64-v8a", 158 constraint_values = [ 159 "@platforms//os:android", 160 "@platforms//cpu:arm64", 161 ], 162) 163EOF 164} 165 166function write_android_sdk_provider() { 167 mkdir -p sdk_check 168 cat > sdk_check/check.bzl <<EOF 169def _find_api_level(android_jar): 170 # expected format: external/androidsdk/platforms/android-LEVEL/android.jar 171 if not android_jar.startswith("external/androidsdk/platforms/android-"): 172 return "unknown" 173 if not android_jar.endswith("/android.jar"): 174 return "unknown" 175 level = android_jar.removeprefix("external/androidsdk/platforms/android-") 176 level = level.removesuffix("/android.jar") 177 return level 178def _show_sdk_info_impl(ctx): 179 print("SDK check results:") 180 provider = ctx.attr._android_sdk[AndroidSdkInfo] 181 print("build_tools_version: %s" % provider.build_tools_version) 182 print("api_level: %s" % _find_api_level(provider.android_jar.path)) 183show_sdk_info = rule( 184 implementation = _show_sdk_info_impl, 185 attrs = { 186 "_android_sdk": attr.label(default = "@androidsdk//:sdk"), 187 }, 188) 189EOF 190} 191 192function write_android_sdk_provider_platforms() { 193 mkdir -p sdk_check 194 cat > sdk_check/check.bzl <<EOF 195def _find_api_level(android_jar): 196 # expected format: external/androidsdk/platforms/android-LEVEL/android.jar 197 if not android_jar.startswith("external/androidsdk/platforms/android-"): 198 return "unknown" 199 if not android_jar.endswith("/android.jar"): 200 return "unknown" 201 level = android_jar.removeprefix("external/androidsdk/platforms/android-") 202 level = level.removesuffix("/android.jar") 203 return level 204def _show_sdk_info_impl(ctx): 205 print("SDK check results:") 206 toolchain = ctx.toolchains["@bazel_tools//tools/android:sdk_toolchain_type"] 207 if not toolchain: 208 print("No SDK found via toolchain") 209 return 210 provider = toolchain.android_sdk_info 211 print("build_tools_version: %s" % provider.build_tools_version) 212 print("api_level: %s" % _find_api_level(provider.android_jar.path)) 213show_sdk_info = rule( 214 implementation = _show_sdk_info_impl, 215 toolchains = [ 216 config_common.toolchain_type( 217 "@bazel_tools//tools/android:sdk_toolchain_type", 218 mandatory = False, 219 ), 220 ], 221) 222EOF 223} 224 225function check_android_sdk_provider() { 226 local extra_args=( 227 # macOS bash doesn't deal well with empty arrays, so make sure this has 228 # contents. 229 "--experimental_google_legacy_api" 230 "$@" 231 ) 232 233 if [[ ${ENABLE_PLATFORMS:-false} == "true" ]]; then 234 write_platforms 235 write_android_sdk_provider_platforms 236 extra_args+=( 237 "--incompatible_enable_android_toolchain_resolution" 238 "--platforms=//platforms:arm64-v8a" 239 ) 240 else 241 write_android_sdk_provider 242 fi 243 244 cat > sdk_check/BUILD <<EOF 245load(":check.bzl", "show_sdk_info") 246show_sdk_info( 247 name = "check", 248) 249EOF 250 251 "${BIT_BAZEL_BINARY}" \ 252 build \ 253 "${extra_args[@]}" \ 254 -- \ 255 //sdk_check:check >& $TEST_log || fail "Expected success" 256 expect_log "SDK check results" 257} 258