android 13 from xiaosuan
This commit is contained in:
commit
e6bbafb4ff
|
@ -0,0 +1 @@
|
|||
make/CleanSpec.mk
|
|
@ -0,0 +1 @@
|
|||
include platform/build/soong:/OWNERS
|
|
@ -0,0 +1,5 @@
|
|||
# Bazel
|
||||
|
||||
The code in this directory is experimental. Bazel support for Android Platform
|
||||
is undergoing active development and workflow stability is currently not
|
||||
guaranteed.
|
|
@ -0,0 +1,14 @@
|
|||
# This filegroup is necessary because Bazel requires that every file in the .d
|
||||
# file of a compilation action is in a subdirectory of one of the transitive
|
||||
# dependencies of the rule being compiled.
|
||||
#
|
||||
# (this is not an intentional feature but accidentally results from the fact
|
||||
# that lines in the .d files must be turned into Artifact instances and thus
|
||||
# need a source root. See ArtifactFactory.findSourceRoot() for the pertinent
|
||||
# logic)
|
||||
#
|
||||
# The easiest way to ensure this is to add this filegroup to one of the
|
||||
# dependencies of the cc_toolchain. Then the root directory of the repository
|
||||
# becomes part of said transitive dependencies and thus every file is in a
|
||||
# subdirectory of it.
|
||||
filegroup(name="empty", visibility=["//visibility:public"])
|
|
@ -0,0 +1,91 @@
|
|||
load("//build/bazel/rules:soong_injection.bzl", "soong_injection_repository")
|
||||
load("//build/bazel/rules:make_injection.bzl", "make_injection_repository")
|
||||
|
||||
register_toolchains(
|
||||
"//prebuilts/build-tools:py_toolchain",
|
||||
"//prebuilts/clang/host/linux-x86:all",
|
||||
)
|
||||
|
||||
# This repository provides files that Soong emits during bp2build (other than
|
||||
# converted BUILD files), mostly .bzl files containing constants to support the
|
||||
# converted BUILD files.
|
||||
soong_injection_repository(name="soong_injection")
|
||||
|
||||
# This is a repository rule to allow Bazel builds to depend on Soong-built
|
||||
# prebuilts for migration purposes.
|
||||
make_injection_repository(
|
||||
name = "make_injection",
|
||||
binaries = [
|
||||
# APEX tools
|
||||
"apex_compression_tool",
|
||||
"apexer",
|
||||
"conv_apex_manifest",
|
||||
"deapexer",
|
||||
"sefcontext_compile",
|
||||
],
|
||||
target_module_files = {
|
||||
# For APEX comparisons
|
||||
"com.android.tzdata": ["system/apex/com.android.tzdata.apex"],
|
||||
"com.android.runtime": ["system/apex/com.android.runtime.apex"],
|
||||
"com.android.adbd": ["system/apex/com.android.adbd.capex"],
|
||||
"build.bazel.examples.apex.minimal": ["system/product/apex/build.bazel.examples.apex.minimal.apex"],
|
||||
},
|
||||
watch_android_bp_files = [
|
||||
"//:build/bazel/examples/apex/minimal/Android.bp", # for build.bazel.examples.apex.minimal
|
||||
"//:packages/modules/adbd/apex/Android.bp", # for com.android.adbd
|
||||
# TODO(b/210399979) - add the other .bp files to watch for the other modules built in these rule
|
||||
],
|
||||
)
|
||||
|
||||
local_repository(
|
||||
name = "rules_cc",
|
||||
path = "build/bazel/rules_cc",
|
||||
)
|
||||
|
||||
local_repository(
|
||||
name = "bazel_skylib",
|
||||
path = "external/bazel-skylib",
|
||||
)
|
||||
|
||||
local_repository(
|
||||
name = "rules_android",
|
||||
path = "external/bazelbuild-rules_android",
|
||||
)
|
||||
|
||||
register_toolchains(
|
||||
# For Starlark Android rules
|
||||
"//prebuilts/sdk:android_default_toolchain",
|
||||
"//prebuilts/sdk:android_sdk_tools",
|
||||
|
||||
# For native android_binary
|
||||
"//prebuilts/sdk:android_sdk_tools_for_native_android_binary",
|
||||
|
||||
# For APEX rules
|
||||
"//build/bazel/rules/apex:all"
|
||||
)
|
||||
|
||||
bind(
|
||||
name = "databinding_annotation_processor",
|
||||
actual = "//prebuilts/sdk:compiler_annotation_processor",
|
||||
)
|
||||
|
||||
bind(
|
||||
name = "android/dx_jar_import",
|
||||
actual = "//prebuilts/sdk:dx_jar_import",
|
||||
)
|
||||
|
||||
# The r8.jar in prebuilts/r8 happens to have the d8 classes needed
|
||||
# for Android app building, whereas the d8.jar in prebuilts/sdk/tools doesn't.
|
||||
bind(
|
||||
name = "android/d8_jar_import",
|
||||
actual = "//prebuilts/r8:r8_jar_import",
|
||||
)
|
||||
|
||||
# TODO(b/201242197): Avoid downloading remote_coverage_tools (on CI) by creating
|
||||
# a stub workspace. Test rules (e.g. sh_test) depend on this external dep, but
|
||||
# we don't support coverage yet. Either vendor the external dep into AOSP, or
|
||||
# cut the dependency from test rules to the external repo.
|
||||
local_repository(
|
||||
name = "remote_coverage_tools",
|
||||
path = "build/bazel/rules/coverage/remote_coverage_tools",
|
||||
)
|
|
@ -0,0 +1,198 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
# TODO: Refactor build/make/envsetup.sh to make gettop() available elsewhere
|
||||
function gettop
|
||||
{
|
||||
local TOPFILE=build/bazel/bazel.sh
|
||||
if [ -n "$TOP" -a -f "$TOP/$TOPFILE" ] ; then
|
||||
# The following circumlocution ensures we remove symlinks from TOP.
|
||||
(cd "$TOP"; PWD= /bin/pwd)
|
||||
else
|
||||
if [ -f $TOPFILE ] ; then
|
||||
# The following circumlocution (repeated below as well) ensures
|
||||
# that we record the true directory name and not one that is
|
||||
# faked up with symlink names.
|
||||
PWD= /bin/pwd
|
||||
else
|
||||
local HERE=$PWD
|
||||
local T=
|
||||
while [ \( ! \( -f $TOPFILE \) \) -a \( "$PWD" != "/" \) ]; do
|
||||
\cd ..
|
||||
T=`PWD= /bin/pwd -P`
|
||||
done
|
||||
\cd "$HERE"
|
||||
if [ -f "$T/$TOPFILE" ]; then
|
||||
echo "$T"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# TODO: Refactor build/soong/scripts/microfactory.bash to make getoutdir() available elsewhere
|
||||
function getoutdir
|
||||
{
|
||||
local out_dir="${OUT_DIR-}"
|
||||
if [ -z "${out_dir}" ]; then
|
||||
if [ "${OUT_DIR_COMMON_BASE-}" ]; then
|
||||
out_dir="${OUT_DIR_COMMON_BASE}/$(basename ${TOP})"
|
||||
else
|
||||
out_dir="out"
|
||||
fi
|
||||
fi
|
||||
if [[ "${out_dir}" != /* ]]; then
|
||||
out_dir="${TOP}/${out_dir}"
|
||||
fi
|
||||
echo "${out_dir}"
|
||||
}
|
||||
|
||||
TOP="$(gettop)"
|
||||
if [ ! "$TOP" ]; then
|
||||
>&2 echo "Couldn't locate the top of the tree. Try setting TOP."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $(uname -s) in
|
||||
Darwin)
|
||||
ANDROID_BAZEL_PATH="${TOP}/prebuilts/bazel/darwin-x86_64/bazel"
|
||||
ANDROID_BAZELRC_NAME="darwin.bazelrc"
|
||||
ANDROID_BAZEL_JDK_PATH="${TOP}/prebuilts/jdk/jdk11/darwin-x86"
|
||||
|
||||
# Lock down PATH in action execution environment, thereby removing
|
||||
# Bazel's default /bin, /usr/bin, /usr/local/bin and ensuring
|
||||
# hermeticity from the system.
|
||||
#
|
||||
# The new PATH components are:
|
||||
#
|
||||
# - prebuilts/build-tools/path: contains checked-in tools that can be
|
||||
# used as executables in actions.
|
||||
#
|
||||
# - out/.path: a special directory created by path_interposer with
|
||||
# config from ui/build/paths/config.go for allowlisting specific
|
||||
# binaries not in prebuilts/build-tools/path, but on the host system.
|
||||
# If one runs Bazel without soong_ui, then this directory wouldn't
|
||||
# exist, making standalone Bazel execution's PATH variable stricter than
|
||||
# Bazel execution within soong_ui.
|
||||
RESTRICTED_PATH="${TOP}/prebuilts/build-tools/path/darwin-x86:${TOP}/out/.path"
|
||||
;;
|
||||
Linux)
|
||||
ANDROID_BAZEL_PATH="${TOP}/prebuilts/bazel/linux-x86_64/bazel"
|
||||
ANDROID_BAZELRC_NAME="linux.bazelrc"
|
||||
ANDROID_BAZEL_JDK_PATH="${TOP}/prebuilts/jdk/jdk11/linux-x86"
|
||||
RESTRICTED_PATH="${TOP}/prebuilts/build-tools/path/linux-x86:${TOP}/out/.path"
|
||||
;;
|
||||
*)
|
||||
>&2 echo "Bazel is supported on Linux and Darwin only. Your OS is not supported for Bazel usage, based on 'uname -s': $(uname -s)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
function verify_soong_outputs_exist() {
|
||||
local to_check="${ABSOLUTE_OUT_DIR}/.path"
|
||||
local no_soong=0
|
||||
if [[ ! -d "${to_check}" ]]; then
|
||||
no_soong=1
|
||||
fi
|
||||
|
||||
local bazel_configs=(
|
||||
"bp2build"
|
||||
"queryview"
|
||||
)
|
||||
local valid_bazel_config=0
|
||||
for c in "${bazel_configs[@]}"
|
||||
do
|
||||
if [[ -d "${ABSOLUTE_OUT_DIR}/soong/""${c}" ]]; then
|
||||
valid_bazel_config=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "${no_soong}" -eq "1" || "${valid_bazel_config}" -eq "0" ]]; then
|
||||
>&2 echo "Error: missing generated Bazel files. Have you run bp2build or queryview?"
|
||||
>&2 echo "Run bp2build with the command: m bp2build"
|
||||
>&2 echo "Run queryview with the command: m queryview"
|
||||
>&2 echo "Alternatively, for non-queryview applications, invoke Bazel using 'b' with the command: source envsetup.sh; b query/build/test <targets>"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function create_bazelrc() {
|
||||
cat > "${ABSOLUTE_OUT_DIR}/bazel/path.bazelrc" <<EOF
|
||||
# This file is generated by tools/bazel. Do not edit manually.
|
||||
build --action_env=PATH=${RESTRICTED_PATH}
|
||||
EOF
|
||||
}
|
||||
|
||||
case "x${ANDROID_BAZELRC_PATH}" in
|
||||
x)
|
||||
# Path not provided, use default.
|
||||
ANDROID_BAZELRC_PATH="${TOP}/build/bazel"
|
||||
;;
|
||||
x/*)
|
||||
# Absolute path, take it as-is.
|
||||
ANDROID_BAZELRC_PATH="${ANDROID_BAZELRC_PATH}"
|
||||
;;
|
||||
x*)
|
||||
# Relative path, consider it relative to TOP.
|
||||
ANDROID_BAZELRC_PATH="${TOP}/${ANDROID_BAZELRC_PATH}"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -d "${ANDROID_BAZELRC_PATH}" ]; then
|
||||
# If we're given a directory, find the correct bazelrc file there.
|
||||
ANDROID_BAZELRC_PATH="${ANDROID_BAZELRC_PATH}/${ANDROID_BAZELRC_NAME}"
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$ANDROID_BAZEL_PATH" -a -f "$ANDROID_BAZEL_PATH" ]; then
|
||||
export ANDROID_BAZEL_PATH
|
||||
else
|
||||
>&2 echo "Couldn't locate Bazel binary"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$ANDROID_BAZELRC_PATH" -a -f "$ANDROID_BAZELRC_PATH" ]; then
|
||||
export ANDROID_BAZELRC_PATH
|
||||
else
|
||||
>&2 echo "Couldn't locate bazelrc file for Bazel"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$ANDROID_BAZEL_JDK_PATH" -a -d "$ANDROID_BAZEL_JDK_PATH" ]; then
|
||||
export ANDROID_BAZEL_JDK_PATH
|
||||
else
|
||||
>&2 echo "Couldn't locate JDK to use for Bazel"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ABSOLUTE_OUT_DIR="$(getoutdir)"
|
||||
|
||||
# In order to be able to load JNI libraries, this directory needs to exist
|
||||
mkdir -p "${ABSOLUTE_OUT_DIR}/bazel/javatmp"
|
||||
|
||||
ADDITIONAL_FLAGS=()
|
||||
if [[ "${STANDALONE_BAZEL}" =~ ^(true|TRUE|1)$ ]]; then
|
||||
# STANDALONE_BAZEL is set.
|
||||
>&2 echo "WARNING: Using Bazel in standalone mode. This mode is not integrated with Soong and Make, and is not supported"
|
||||
>&2 echo "for Android Platform builds. Use this mode at your own risk."
|
||||
>&2 echo
|
||||
else
|
||||
# STANDALONE_BAZEL is not set.
|
||||
>&2 echo "WARNING: Bazel support for the Android Platform is experimental and is undergoing development."
|
||||
>&2 echo "WARNING: Currently, build stability is not guaranteed. Thank you."
|
||||
>&2 echo
|
||||
|
||||
# Generate a bazelrc with dynamic content, like the absolute path to PATH variable values.
|
||||
create_bazelrc
|
||||
# Check that the Bazel synthetic workspace and other required inputs exist before handing over control to Bazel.
|
||||
verify_soong_outputs_exist
|
||||
ADDITIONAL_FLAGS+=("--bazelrc=${ABSOLUTE_OUT_DIR}/bazel/path.bazelrc")
|
||||
fi
|
||||
|
||||
JAVA_HOME="${ANDROID_BAZEL_JDK_PATH}" "${ANDROID_BAZEL_PATH}" \
|
||||
--server_javabase="${ANDROID_BAZEL_JDK_PATH}" \
|
||||
--output_user_root="${ABSOLUTE_OUT_DIR}/bazel/output_user_root" \
|
||||
--host_jvm_args=-Djava.io.tmpdir="${ABSOLUTE_OUT_DIR}/bazel/javatmp" \
|
||||
--bazelrc="${ANDROID_BAZELRC_PATH}" \
|
||||
"${ADDITIONAL_FLAGS[@]}" \
|
||||
"$@"
|
|
@ -0,0 +1,130 @@
|
|||
#!/bin/bash -eux
|
||||
# Verifies that bp2build-generated BUILD files result in successful Bazel
|
||||
# builds.
|
||||
#
|
||||
# This verification script is designed to be used for continuous integration
|
||||
# tests, though may also be used for manual developer verification.
|
||||
|
||||
#######
|
||||
# Setup
|
||||
#######
|
||||
|
||||
if [[ -z ${DIST_DIR+x} ]]; then
|
||||
echo "DIST_DIR not set. Using out/dist. This should only be used for manual developer testing."
|
||||
DIST_DIR="out/dist"
|
||||
fi
|
||||
|
||||
# Generate BUILD files into out/soong/bp2build
|
||||
AOSP_ROOT="$(dirname $0)/../../.."
|
||||
"${AOSP_ROOT}/build/soong/soong_ui.bash" --make-mode BP2BUILD_VERBOSE=1 --skip-soong-tests bp2build dist
|
||||
|
||||
# Dist the entire workspace of generated BUILD files, rooted from
|
||||
# out/soong/bp2build. This is done early so it's available even if builds/tests
|
||||
# fail.
|
||||
tar -czf "${DIST_DIR}/bp2build_generated_workspace.tar.gz" -C out/soong/bp2build .
|
||||
|
||||
# Remove the ninja_build output marker file to communicate to buildbot that this is not a regular Ninja build, and its
|
||||
# output should not be parsed as such.
|
||||
rm -f out/ninja_build
|
||||
|
||||
# Before you add flags to this list, cosnider adding it to the "ci" bazelrc
|
||||
# config instead of this list so that flags are not duplicated between scripts
|
||||
# and bazelrc, and bazelrc is the Bazel-native way of organizing flags.
|
||||
FLAGS_LIST=(
|
||||
--config=bp2build
|
||||
--config=ci
|
||||
)
|
||||
FLAGS="${FLAGS_LIST[@]}"
|
||||
|
||||
###############
|
||||
# Build targets
|
||||
###############
|
||||
BUILD_TARGETS_LIST=(
|
||||
//art/...
|
||||
//bionic/...
|
||||
//bootable/recovery/tools/recovery_l10n/...
|
||||
//build/...
|
||||
//cts/...
|
||||
//development/...
|
||||
//external/...
|
||||
//frameworks/...
|
||||
//libnativehelper/...
|
||||
//packages/...
|
||||
//prebuilts/clang/host/linux-x86:all
|
||||
//system/...
|
||||
//tools/apksig/...
|
||||
//tools/platform-compat/...
|
||||
|
||||
# These tools only build for host currently
|
||||
-//external/e2fsprogs/misc:all
|
||||
-//external/e2fsprogs/resize:all
|
||||
-//external/e2fsprogs/debugfs:all
|
||||
-//external/e2fsprogs/e2fsck:all
|
||||
)
|
||||
BUILD_TARGETS="${BUILD_TARGETS_LIST[@]}"
|
||||
# Iterate over various architectures supported in the platform build.
|
||||
tools/bazel --max_idle_secs=5 build ${FLAGS} --platforms //build/bazel/platforms:android_x86 -k -- ${BUILD_TARGETS}
|
||||
tools/bazel --max_idle_secs=5 build ${FLAGS} --platforms //build/bazel/platforms:android_x86_64 -k -- ${BUILD_TARGETS}
|
||||
tools/bazel --max_idle_secs=5 build ${FLAGS} --platforms //build/bazel/platforms:android_arm -k -- ${BUILD_TARGETS}
|
||||
tools/bazel --max_idle_secs=5 build ${FLAGS} --platforms //build/bazel/platforms:android_arm64 -k -- ${BUILD_TARGETS}
|
||||
|
||||
HOST_INCOMPATIBLE_TARGETS=(
|
||||
# TODO(b/217756861): Apex toolchain is incompatible with host arches but apex modules do
|
||||
# not have this restriction
|
||||
-//build/bazel/examples/apex/...
|
||||
-//packages/modules/adb/apex:com.android.adbd
|
||||
-//system/timezone/apex:com.android.tzdata
|
||||
-//build/bazel/tests/apex/...
|
||||
-//build/bazel/ci/dist/...
|
||||
|
||||
# TODO(b/217927043): Determine how to address targets that are device only
|
||||
-//system/core/libpackagelistparser:all
|
||||
-//external/icu/libicu:all
|
||||
//external/icu/libicu:libicu
|
||||
-//external/icu/icu4c/source/tools/ctestfw:all
|
||||
|
||||
# TODO(b/217926427): determine why these host_supported modules do not build on host
|
||||
-//packages/modules/adb:all
|
||||
-//packages/modules/adb/pairing_connection:all
|
||||
)
|
||||
|
||||
# build for host
|
||||
tools/bazel --max_idle_secs=5 build ${FLAGS} \
|
||||
--platforms //build/bazel/platforms:linux_x86_64 \
|
||||
-- ${BUILD_TARGETS} "${HOST_INCOMPATIBLE_TARGETS[@]}"
|
||||
|
||||
###########
|
||||
# Run tests
|
||||
###########
|
||||
tools/bazel --max_idle_secs=5 test ${FLAGS} //build/bazel/tests/... //build/bazel/rules/apex/... //build/bazel/scripts/...
|
||||
|
||||
###########
|
||||
# Dist mainline modules
|
||||
###########
|
||||
tools/bazel --max_idle_secs=5 run //build/bazel/ci/dist:mainline_modules ${FLAGS} --platforms=//build/bazel/platforms:android_x86 -- --dist_dir="${DIST_DIR}/mainline_modules_x86"
|
||||
tools/bazel --max_idle_secs=5 run //build/bazel/ci/dist:mainline_modules ${FLAGS} --platforms=//build/bazel/platforms:android_x86_64 -- --dist_dir="${DIST_DIR}/mainline_modules_x86_64"
|
||||
tools/bazel --max_idle_secs=5 run //build/bazel/ci/dist:mainline_modules ${FLAGS} --platforms=//build/bazel/platforms:android_arm -- --dist_dir="${DIST_DIR}/mainline_modules_arm"
|
||||
tools/bazel --max_idle_secs=5 run //build/bazel/ci/dist:mainline_modules ${FLAGS} --platforms=//build/bazel/platforms:android_arm64 -- --dist_dir="${DIST_DIR}/mainline_modules_arm64"
|
||||
|
||||
###################
|
||||
# bp2build-progress
|
||||
###################
|
||||
|
||||
# Generate bp2build progress reports and graphs for these modules into the dist
|
||||
# dir so that they can be downloaded from the CI artifact list.
|
||||
BP2BUILD_PROGRESS_MODULES=(
|
||||
com.android.runtime
|
||||
com.android.neuralnetworks
|
||||
com.android.media.swcodec
|
||||
)
|
||||
bp2build_progress_script="${AOSP_ROOT}/build/bazel/scripts/bp2build-progress/bp2build-progress.py"
|
||||
bp2build_progress_output_dir="${DIST_DIR}/bp2build-progress"
|
||||
mkdir -p "${bp2build_progress_output_dir}"
|
||||
|
||||
report_args=""
|
||||
for m in "${BP2BUILD_PROGRESS_MODULES[@]}"; do
|
||||
report_args="$report_args -m ""${m}"
|
||||
"${bp2build_progress_script}" graph -m "${m}" --use_queryview=true > "${bp2build_progress_output_dir}/${m}_graph.dot"
|
||||
done
|
||||
|
||||
"${bp2build_progress_script}" report ${report_args} --use_queryview=true > "${bp2build_progress_output_dir}/progress_report.txt"
|
|
@ -0,0 +1,88 @@
|
|||
#!/bin/bash -eu
|
||||
# checks the diff between legacy Soong built artifacts and their counterparts
|
||||
# built with bazel/mixed build
|
||||
export TARGET_PRODUCT=aosp_arm64
|
||||
export TARGET_BUILD_VARIANT=userdebug
|
||||
|
||||
build/soong/soong_ui.bash \
|
||||
--build-mode \
|
||||
--all-modules \
|
||||
--dir="$(pwd)" \
|
||||
bp2build
|
||||
tools/bazel build --config=bp2build //build/bazel/scripts/difftool:collect_zip
|
||||
tools/bazel build --config=bp2build //build/bazel/scripts/difftool:difftool_zip
|
||||
|
||||
# the following 2 arrays must be of the same size
|
||||
MODULES=(
|
||||
libnativehelper
|
||||
)
|
||||
OUTPUTS=(
|
||||
JNIHelp.o
|
||||
)
|
||||
PATH_FILTERS=(
|
||||
"linux_glibc_x86_shared/\|linux_x86-fastbuild"
|
||||
"linux_glibc_x86_64_shared/\|linux_x86_64-fastbuild"
|
||||
"android_arm64[-_]"
|
||||
# "android_arm[-_]" TODO(usta) investigate why there is a diff for this
|
||||
)
|
||||
readonly AOSP_ROOT="$(readlink -f "$(dirname "$0")"/../../..)"
|
||||
#TODO(usta): absolute path isn't compatible with collect.py and ninja
|
||||
readonly LEGACY_OUTPUT_SEARCH_TREE="out/soong/.intermediates/libnativehelper"
|
||||
readonly MIXED_OUTPUT_SEARCH_TREE="out/bazel/output/execroot/__main__/bazel-out"
|
||||
readonly NINJA_FILE="$AOSP_ROOT/out/combined-$TARGET_PRODUCT.ninja"
|
||||
# python is expected in PATH but used only to start a zipped python archive,
|
||||
# which bundles its own interpreter. We could also simply use `tools/bazel run`
|
||||
# instead however that sets the working directly differently and collect.py
|
||||
# won't work because it expects paths relative to $OUT_DIR
|
||||
# TODO(usta) make collect.py work with absolute paths and maybe consider
|
||||
# using `tools/bazel run` on the `py_binary` target directly instead of using
|
||||
# the python_zip_file filegroup's output
|
||||
readonly stub_python=python3
|
||||
readonly LEGACY_COLLECTION="$AOSP_ROOT/out/diff_metadata/legacy"
|
||||
readonly MIXED_COLLECTION="$AOSP_ROOT/out/diff_metadata/mixed"
|
||||
mkdir -p "$LEGACY_COLLECTION"
|
||||
mkdir -p "$MIXED_COLLECTION"
|
||||
|
||||
function findIn() {
|
||||
result=$(find "$1" -name "$3" | grep "$2")
|
||||
count=$(echo "$result" | wc -l)
|
||||
if [ "$count" != 1 ]; then
|
||||
printf "multiple files found instead of exactly ONE:\n%s\n" "$result" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
for ((i = 0; i < ${#MODULES[@]}; i++)); do
|
||||
MODULE=${MODULES[$i]}
|
||||
echo "Building $MODULE for comparison"
|
||||
build/soong/soong_ui.bash --make-mode "$MODULE"
|
||||
$stub_python "bazel-bin/build/bazel/scripts/difftool/collect.zip" \
|
||||
"$NINJA_FILE" "$LEGACY_COLLECTION"
|
||||
build/soong/soong_ui.bash \
|
||||
--make-mode \
|
||||
USE_BAZEL_ANALYSIS=1 \
|
||||
BAZEL_STARTUP_ARGS="--max_idle_secs=5" \
|
||||
BAZEL_BUILD_ARGS="--color=no --curses=no --noshow_progress" \
|
||||
"$MODULE"
|
||||
$stub_python "bazel-bin/build/bazel/scripts/difftool/collect.zip" \
|
||||
"$NINJA_FILE" "$MIXED_COLLECTION"
|
||||
OUTPUT=${OUTPUTS[$i]}
|
||||
for ((j = 0; j < ${#PATH_FILTERS[@]}; j++)); do
|
||||
PATH_FILTER=${PATH_FILTERS[$j]}
|
||||
LEGACY_OUTPUT=$(findIn "$LEGACY_OUTPUT_SEARCH_TREE" "$PATH_FILTER" "$OUTPUT")
|
||||
MIXED_OUTPUT=$(findIn "$MIXED_OUTPUT_SEARCH_TREE" "$PATH_FILTER" "$OUTPUT")
|
||||
|
||||
LEGACY_COLLECTION_DIR=$(dirname "$LEGACY_COLLECTION/$LEGACY_OUTPUT")
|
||||
mkdir -p "$LEGACY_COLLECTION_DIR"
|
||||
cp "$LEGACY_OUTPUT" "$LEGACY_COLLECTION_DIR"
|
||||
MIXED_COLLECTION_DIR=$(dirname "$MIXED_COLLECTION/$MIXED_OUTPUT")
|
||||
mkdir -p "$MIXED_COLLECTION_DIR"
|
||||
cp "$MIXED_OUTPUT" "$MIXED_COLLECTION_DIR"
|
||||
|
||||
$stub_python "bazel-bin/build/bazel/scripts/difftool/difftool.zip" \
|
||||
--level=SEVERE -v "$LEGACY_COLLECTION" "$MIXED_COLLECTION" \
|
||||
-l="$LEGACY_OUTPUT" -r="$MIXED_OUTPUT"
|
||||
done
|
||||
done
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir")
|
||||
|
||||
# bazel run --package_path=out/soong/workspace //build/bazel/ci/dist:mainline_modules -- --dist_dir=/tmp/dist
|
||||
# TODO(jingwen): use a split transition on --platforms to dist all 4 architectures in a single invocation.
|
||||
copy_to_dist_dir(
|
||||
name = "mainline_modules",
|
||||
data = [
|
||||
"//system/timezone/apex:com.android.tzdata.apex",
|
||||
"//packages/modules/adb/apex:com.android.adbd.apex",
|
||||
],
|
||||
flat = True,
|
||||
)
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/bash -eux
|
||||
# Verifies mixed builds succeeds when building "droid".
|
||||
# This verification script is designed to be used for continuous integration
|
||||
# tests, though may also be used for manual developer verification.
|
||||
|
||||
if [[ -z ${DIST_DIR+x} ]]; then
|
||||
echo "DIST_DIR not set. Using out/dist. This should only be used for manual developer testing."
|
||||
DIST_DIR="out/dist"
|
||||
fi
|
||||
|
||||
# Run a mixed build of "droid"
|
||||
build/soong/soong_ui.bash --make-mode \
|
||||
--mk-metrics \
|
||||
BP2BUILD_VERBOSE=1 \
|
||||
USE_BAZEL_ANALYSIS=1 \
|
||||
BAZEL_STARTUP_ARGS="--max_idle_secs=5" \
|
||||
BAZEL_BUILD_ARGS="--color=no --curses=no --show_progress_rate_limit=5" \
|
||||
TARGET_PRODUCT=aosp_arm64 \
|
||||
TARGET_BUILD_VARIANT=userdebug \
|
||||
droid platform_tests \
|
||||
dist DIST_DIR=$DIST_DIR
|
||||
|
||||
# Verify there are artifacts under the out directory that originated from bazel.
|
||||
echo "Verifying OUT_DIR contains bazel-out..."
|
||||
if find out/ -type d -name bazel-out &>/dev/null; then
|
||||
echo "bazel-out found."
|
||||
else
|
||||
echo "bazel-out not found. This may indicate that mixed builds are silently not running."
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,41 @@
|
|||
#!/bin/bash -eux
|
||||
# Verifies mixed builds succeeds when building "libc".
|
||||
# This verification script is designed to be used for continuous integration
|
||||
# tests, though may also be used for manual developer verification.
|
||||
|
||||
if [[ -z ${DIST_DIR+x} ]]; then
|
||||
echo "DIST_DIR not set. Using out/dist. This should only be used for manual developer testing."
|
||||
DIST_DIR="out/dist"
|
||||
fi
|
||||
|
||||
TARGETS=(
|
||||
libbacktrace
|
||||
libfdtrack
|
||||
libsimpleperf
|
||||
com.android.adbd
|
||||
com.android.runtime
|
||||
bluetoothtbd
|
||||
framework-minus-apex
|
||||
)
|
||||
|
||||
# Run a mixed build of "libc"
|
||||
build/soong/soong_ui.bash --make-mode \
|
||||
--mk-metrics \
|
||||
BP2BUILD_VERBOSE=1 \
|
||||
USE_BAZEL_ANALYSIS=1 \
|
||||
BAZEL_STARTUP_ARGS="--max_idle_secs=5" \
|
||||
BAZEL_BUILD_ARGS="--color=no --curses=no --show_progress_rate_limit=5" \
|
||||
TARGET_PRODUCT=aosp_arm64 \
|
||||
TARGET_BUILD_VARIANT=userdebug \
|
||||
"${TARGETS[@]}" \
|
||||
dist DIST_DIR=$DIST_DIR
|
||||
|
||||
# Verify there are artifacts under the out directory that originated from bazel.
|
||||
echo "Verifying OUT_DIR contains bazel-out..."
|
||||
if find out/ -type d -name bazel-out &>/dev/null; then
|
||||
echo "bazel-out found."
|
||||
else
|
||||
echo "bazel-out not found. This may indicate that mixed builds are silently not running."
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -0,0 +1,467 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generates a dashboard for the current RBC product/board config conversion status."""
|
||||
# pylint: disable=line-too-long
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import dataclasses
|
||||
import datetime
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from typing import List, Tuple
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
_PRODUCT_REGEX = re.compile(r'([a-zA-Z_][a-zA-Z0-9_]*)(?:-(user|userdebug|eng))?')
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class Product:
|
||||
"""Represents a TARGET_PRODUCT and TARGET_BUILD_VARIANT."""
|
||||
product: str
|
||||
variant: str
|
||||
|
||||
def __post_init__(self):
|
||||
if not _PRODUCT_REGEX.match(str(self)):
|
||||
raise ValueError(f'Invalid product name: {self}')
|
||||
|
||||
def __str__(self):
|
||||
return self.product + '-' + self.variant
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class ProductResult:
|
||||
baseline_success: bool
|
||||
product_success: bool
|
||||
board_success: bool
|
||||
product_has_diffs: bool
|
||||
board_has_diffs: bool
|
||||
|
||||
def success(self) -> bool:
|
||||
return not self.baseline_success or (
|
||||
self.product_success and self.board_success
|
||||
and not self.product_has_diffs and not self.board_has_diffs)
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class Directories:
|
||||
out: str
|
||||
out_baseline: str
|
||||
out_product: str
|
||||
out_board: str
|
||||
results: str
|
||||
|
||||
|
||||
def get_top() -> str:
|
||||
path = '.'
|
||||
while not os.path.isfile(os.path.join(path, 'build/soong/soong_ui.bash')):
|
||||
if os.path.abspath(path) == '/':
|
||||
sys.exit('Could not find android source tree root.')
|
||||
path = os.path.join(path, '..')
|
||||
return os.path.abspath(path)
|
||||
|
||||
|
||||
def get_build_var(variable, product: Product) -> str:
|
||||
"""Returns the result of the shell command get_build_var."""
|
||||
env = {
|
||||
**os.environ,
|
||||
'TARGET_PRODUCT': product.product,
|
||||
'TARGET_BUILD_VARIANT': product.variant,
|
||||
}
|
||||
return subprocess.run([
|
||||
'build/soong/soong_ui.bash',
|
||||
'--dumpvar-mode',
|
||||
variable
|
||||
], check=True, capture_output=True, env=env, text=True).stdout.strip()
|
||||
|
||||
|
||||
async def run_jailed_command(args: List[str], out_dir: str, env=None) -> bool:
|
||||
"""Runs a command, saves its output to out_dir/build.log, and returns if it succeeded."""
|
||||
with open(os.path.join(out_dir, 'build.log'), 'wb') as f:
|
||||
result = await asyncio.create_subprocess_exec(
|
||||
'prebuilts/build-tools/linux-x86/bin/nsjail',
|
||||
'-q',
|
||||
'--cwd',
|
||||
os.getcwd(),
|
||||
'-e',
|
||||
'-B',
|
||||
'/',
|
||||
'-B',
|
||||
f'{os.path.abspath(out_dir)}:{os.path.abspath("out")}',
|
||||
'--time_limit',
|
||||
'0',
|
||||
'--skip_setsid',
|
||||
'--keep_caps',
|
||||
'--disable_clone_newcgroup',
|
||||
'--disable_clone_newnet',
|
||||
'--rlimit_as',
|
||||
'soft',
|
||||
'--rlimit_core',
|
||||
'soft',
|
||||
'--rlimit_cpu',
|
||||
'soft',
|
||||
'--rlimit_fsize',
|
||||
'soft',
|
||||
'--rlimit_nofile',
|
||||
'soft',
|
||||
'--proc_rw',
|
||||
'--hostname',
|
||||
socket.gethostname(),
|
||||
'--',
|
||||
*args, stdout=f, stderr=subprocess.STDOUT, env=env)
|
||||
return await result.wait() == 0
|
||||
|
||||
|
||||
async def run_build(flags: List[str], out_dir: str) -> bool:
|
||||
return await run_jailed_command([
|
||||
'build/soong/soong_ui.bash',
|
||||
'--make-mode',
|
||||
*flags,
|
||||
'--skip-ninja',
|
||||
'nothing'
|
||||
], out_dir)
|
||||
|
||||
|
||||
async def run_config(product: Product, rbc_product: bool, rbc_board: bool, out_dir: str) -> bool:
|
||||
"""Runs config.mk and saves results to out/rbc_variable_dump.txt."""
|
||||
env = {
|
||||
'OUT_DIR': 'out',
|
||||
'TMPDIR': 'tmp',
|
||||
'BUILD_DATETIME_FILE': 'out/build_date.txt',
|
||||
'CALLED_FROM_SETUP': 'true',
|
||||
'TARGET_PRODUCT': product.product,
|
||||
'TARGET_BUILD_VARIANT': product.variant,
|
||||
'RBC_PRODUCT_CONFIG': 'true' if rbc_product else '',
|
||||
'RBC_BOARD_CONFIG': 'true' if rbc_board else '',
|
||||
'RBC_DUMP_CONFIG_FILE': 'out/rbc_variable_dump.txt',
|
||||
}
|
||||
return await run_jailed_command([
|
||||
'prebuilts/build-tools/linux-x86/bin/ckati',
|
||||
'-f',
|
||||
'build/make/core/config.mk'
|
||||
], out_dir, env=env)
|
||||
|
||||
|
||||
async def has_diffs(success: bool, file_pairs: List[Tuple[str]], results_folder: str) -> bool:
|
||||
"""Returns true if the two out folders provided have differing ninja files."""
|
||||
if not success:
|
||||
return False
|
||||
results = []
|
||||
for pair in file_pairs:
|
||||
name = 'soong_build.ninja' if pair[0].endswith('soong/build.ninja') else os.path.basename(pair[0])
|
||||
with open(os.path.join(results_folder, name)+'.diff', 'wb') as f:
|
||||
results.append((await asyncio.create_subprocess_exec(
|
||||
'diff',
|
||||
pair[0],
|
||||
pair[1],
|
||||
stdout=f, stderr=subprocess.STDOUT)).wait())
|
||||
|
||||
for return_code in await asyncio.gather(*results):
|
||||
if return_code != 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def generate_html_row(num: int, product: Product, results: ProductResult):
|
||||
def generate_status_cell(success: bool, diffs: bool) -> str:
|
||||
message = 'Success'
|
||||
if diffs:
|
||||
message = 'Results differed'
|
||||
if not success:
|
||||
message = 'Build failed'
|
||||
return f'<td style="background-color: {"lightgreen" if success and not diffs else "salmon"}">{message}</td>'
|
||||
|
||||
return f'''
|
||||
<tr>
|
||||
<td>{num}</td>
|
||||
<td>{product if results.success() and results.baseline_success else f'<a href="{product}/">{product}</a>'}</td>
|
||||
{generate_status_cell(results.baseline_success, False)}
|
||||
{generate_status_cell(results.product_success, results.product_has_diffs)}
|
||||
{generate_status_cell(results.board_success, results.board_has_diffs)}
|
||||
</tr>
|
||||
'''
|
||||
|
||||
|
||||
def get_branch() -> str:
|
||||
try:
|
||||
tree = ET.parse('.repo/manifests/default.xml')
|
||||
default_tag = tree.getroot().find('default')
|
||||
return default_tag.get('remote') + '/' + default_tag.get('revision')
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
print(str(e), file=sys.stderr)
|
||||
return 'Unknown'
|
||||
|
||||
|
||||
def cleanup_empty_files(path):
|
||||
if os.path.isfile(path):
|
||||
if os.path.getsize(path) == 0:
|
||||
os.remove(path)
|
||||
elif os.path.isdir(path):
|
||||
for subfile in os.listdir(path):
|
||||
cleanup_empty_files(os.path.join(path, subfile))
|
||||
if not os.listdir(path):
|
||||
os.rmdir(path)
|
||||
|
||||
|
||||
async def test_one_product(product: Product, dirs: Directories) -> ProductResult:
|
||||
"""Runs the builds and tests for differences for a single product."""
|
||||
baseline_success, product_success, board_success = await asyncio.gather(
|
||||
run_build([
|
||||
f'TARGET_PRODUCT={product.product}',
|
||||
f'TARGET_BUILD_VARIANT={product.variant}',
|
||||
], dirs.out_baseline),
|
||||
run_build([
|
||||
f'TARGET_PRODUCT={product.product}',
|
||||
f'TARGET_BUILD_VARIANT={product.variant}',
|
||||
'RBC_PRODUCT_CONFIG=1',
|
||||
], dirs.out_product),
|
||||
run_build([
|
||||
f'TARGET_PRODUCT={product.product}',
|
||||
f'TARGET_BUILD_VARIANT={product.variant}',
|
||||
'RBC_BOARD_CONFIG=1',
|
||||
], dirs.out_board),
|
||||
)
|
||||
|
||||
product_dashboard_folder = os.path.join(dirs.results, str(product))
|
||||
os.mkdir(product_dashboard_folder)
|
||||
os.mkdir(product_dashboard_folder+'/baseline')
|
||||
os.mkdir(product_dashboard_folder+'/product')
|
||||
os.mkdir(product_dashboard_folder+'/board')
|
||||
|
||||
if not baseline_success:
|
||||
shutil.copy2(os.path.join(dirs.out_baseline, 'build.log'),
|
||||
f'{product_dashboard_folder}/baseline/build.log')
|
||||
if not product_success:
|
||||
shutil.copy2(os.path.join(dirs.out_product, 'build.log'),
|
||||
f'{product_dashboard_folder}/product/build.log')
|
||||
if not board_success:
|
||||
shutil.copy2(os.path.join(dirs.out_board, 'build.log'),
|
||||
f'{product_dashboard_folder}/board/build.log')
|
||||
|
||||
files = [f'build-{product.product}.ninja', f'build-{product.product}-package.ninja', 'soong/build.ninja']
|
||||
product_files = [(os.path.join(dirs.out_baseline, x), os.path.join(dirs.out_product, x)) for x in files]
|
||||
board_files = [(os.path.join(dirs.out_baseline, x), os.path.join(dirs.out_board, x)) for x in files]
|
||||
product_has_diffs, board_has_diffs = await asyncio.gather(
|
||||
has_diffs(baseline_success and product_success, product_files, product_dashboard_folder+'/product'),
|
||||
has_diffs(baseline_success and board_success, board_files, product_dashboard_folder+'/board'))
|
||||
|
||||
# delete files that contain the product name in them to save space,
|
||||
# otherwise the ninja files end up filling up the whole harddrive
|
||||
for out_folder in [dirs.out_baseline, dirs.out_product, dirs.out_board]:
|
||||
for subfolder in ['', 'soong']:
|
||||
folder = os.path.join(out_folder, subfolder)
|
||||
for file in os.listdir(folder):
|
||||
if os.path.isfile(os.path.join(folder, file)) and product.product in file:
|
||||
os.remove(os.path.join(folder, file))
|
||||
|
||||
cleanup_empty_files(product_dashboard_folder)
|
||||
|
||||
return ProductResult(baseline_success, product_success, board_success, product_has_diffs, board_has_diffs)
|
||||
|
||||
|
||||
async def test_one_product_quick(product: Product, dirs: Directories) -> ProductResult:
|
||||
"""Runs the builds and tests for differences for a single product."""
|
||||
baseline_success, product_success, board_success = await asyncio.gather(
|
||||
run_config(
|
||||
product,
|
||||
False,
|
||||
False,
|
||||
dirs.out_baseline),
|
||||
run_config(
|
||||
product,
|
||||
True,
|
||||
False,
|
||||
dirs.out_product),
|
||||
run_config(
|
||||
product,
|
||||
False,
|
||||
True,
|
||||
dirs.out_board),
|
||||
)
|
||||
|
||||
product_dashboard_folder = os.path.join(dirs.results, str(product))
|
||||
os.mkdir(product_dashboard_folder)
|
||||
os.mkdir(product_dashboard_folder+'/baseline')
|
||||
os.mkdir(product_dashboard_folder+'/product')
|
||||
os.mkdir(product_dashboard_folder+'/board')
|
||||
|
||||
if not baseline_success:
|
||||
shutil.copy2(os.path.join(dirs.out_baseline, 'build.log'),
|
||||
f'{product_dashboard_folder}/baseline/build.log')
|
||||
if not product_success:
|
||||
shutil.copy2(os.path.join(dirs.out_product, 'build.log'),
|
||||
f'{product_dashboard_folder}/product/build.log')
|
||||
if not board_success:
|
||||
shutil.copy2(os.path.join(dirs.out_board, 'build.log'),
|
||||
f'{product_dashboard_folder}/board/build.log')
|
||||
|
||||
files = ['rbc_variable_dump.txt']
|
||||
product_files = [(os.path.join(dirs.out_baseline, x), os.path.join(dirs.out_product, x)) for x in files]
|
||||
board_files = [(os.path.join(dirs.out_baseline, x), os.path.join(dirs.out_board, x)) for x in files]
|
||||
product_has_diffs, board_has_diffs = await asyncio.gather(
|
||||
has_diffs(baseline_success and product_success, product_files, product_dashboard_folder+'/product'),
|
||||
has_diffs(baseline_success and board_success, board_files, product_dashboard_folder+'/board'))
|
||||
|
||||
cleanup_empty_files(product_dashboard_folder)
|
||||
|
||||
return ProductResult(baseline_success, product_success, board_success, product_has_diffs, board_has_diffs)
|
||||
|
||||
|
||||
async def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Generates a dashboard of the starlark product configuration conversion.')
|
||||
parser.add_argument('products', nargs='*',
|
||||
help='list of products to test. If not given, all '
|
||||
+ 'products will be tested. '
|
||||
+ 'Example: aosp_arm64-userdebug')
|
||||
parser.add_argument('--quick', action='store_true',
|
||||
help='Run a quick test. This will only run config.mk and '
|
||||
+ 'diff the make variables at the end of it, instead of '
|
||||
+ 'diffing the full ninja files.')
|
||||
parser.add_argument('--exclude', nargs='+', default=[],
|
||||
help='Exclude these producs from the build. Useful if not '
|
||||
+ 'supplying a list of products manually.')
|
||||
parser.add_argument('--results-directory',
|
||||
help='Directory to store results in. Defaults to $(OUT_DIR)/rbc_dashboard. '
|
||||
+ 'Warning: will be cleared!')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.results_directory:
|
||||
args.results_directory = os.path.abspath(args.results_directory)
|
||||
|
||||
os.chdir(get_top())
|
||||
|
||||
def str_to_product(p: str) -> Product:
|
||||
match = _PRODUCT_REGEX.fullmatch(p)
|
||||
if not match:
|
||||
sys.exit(f'Invalid product name: {p}. Example: aosp_arm64-userdebug')
|
||||
return Product(match.group(1), match.group(2) if match.group(2) else 'userdebug')
|
||||
|
||||
products = [str_to_product(p) for p in args.products]
|
||||
|
||||
if not products:
|
||||
products = list(map(lambda x: Product(x, 'userdebug'), get_build_var(
|
||||
'all_named_products', Product('aosp_arm64', 'userdebug')).split()))
|
||||
|
||||
excluded = [str_to_product(p) for p in args.exclude]
|
||||
products = [p for p in products if p not in excluded]
|
||||
|
||||
for i, product in enumerate(products):
|
||||
for j, product2 in enumerate(products):
|
||||
if i != j and product.product == product2.product:
|
||||
sys.exit(f'Product {product.product} cannot be repeated.')
|
||||
|
||||
out_dir = get_build_var('OUT_DIR', Product('aosp_arm64', 'userdebug'))
|
||||
|
||||
dirs = Directories(
|
||||
out=out_dir,
|
||||
out_baseline=os.path.join(out_dir, 'rbc_out_baseline'),
|
||||
out_product=os.path.join(out_dir, 'rbc_out_product'),
|
||||
out_board=os.path.join(out_dir, 'rbc_out_board'),
|
||||
results=args.results_directory if args.results_directory else os.path.join(out_dir, 'rbc_dashboard'))
|
||||
|
||||
for folder in [dirs.out_baseline, dirs.out_product, dirs.out_board, dirs.results]:
|
||||
# delete and recreate the out directories. You can't reuse them for
|
||||
# a particular product, because after we delete some product-specific
|
||||
# files inside the out dir to save space, the build will fail if you
|
||||
# try to build the same product again.
|
||||
shutil.rmtree(folder, ignore_errors=True)
|
||||
os.makedirs(folder)
|
||||
|
||||
# When running in quick mode, we still need to build
|
||||
# mk2rbc/rbcrun/AndroidProducts.mk.list, so run a get_build_var command to do
|
||||
# that in each folder.
|
||||
if args.quick:
|
||||
commands = []
|
||||
for folder in [dirs.out_baseline, dirs.out_product, dirs.out_board]:
|
||||
commands.append(run_jailed_command([
|
||||
'build/soong/soong_ui.bash',
|
||||
'--dumpvar-mode',
|
||||
'TARGET_PRODUCT'
|
||||
], folder))
|
||||
for success in await asyncio.gather(*commands):
|
||||
if not success:
|
||||
sys.exit('Failed to setup output directories')
|
||||
|
||||
with open(os.path.join(dirs.results, 'index.html'), 'w') as f:
|
||||
f.write(f'''
|
||||
<body>
|
||||
<h2>RBC Product/Board conversion status</h2>
|
||||
Generated on {datetime.date.today()} for branch {get_branch()}
|
||||
<table>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>product</th>
|
||||
<th>baseline</th>
|
||||
<th>RBC product config</th>
|
||||
<th>RBC board config</th>
|
||||
</tr>\n''')
|
||||
f.flush()
|
||||
|
||||
all_results = []
|
||||
start_time = time.time()
|
||||
print(f'{"Current product":31.31} | {"Time Elapsed":>16} | {"Per each":>8} | {"ETA":>16} | Status')
|
||||
print('-' * 91)
|
||||
for i, product in enumerate(products):
|
||||
if i > 0:
|
||||
elapsed_time = time.time() - start_time
|
||||
time_per_product = elapsed_time / i
|
||||
eta = time_per_product * (len(products) - i)
|
||||
elapsed_time_str = str(datetime.timedelta(seconds=int(elapsed_time)))
|
||||
time_per_product_str = str(datetime.timedelta(seconds=int(time_per_product)))
|
||||
eta_str = str(datetime.timedelta(seconds=int(eta)))
|
||||
print(f'{f"{i+1}/{len(products)} {product}":31.31} | {elapsed_time_str:>16} | {time_per_product_str:>8} | {eta_str:>16} | ', end='', flush=True)
|
||||
else:
|
||||
print(f'{f"{i+1}/{len(products)} {product}":31.31} | {"":>16} | {"":>8} | {"":>16} | ', end='', flush=True)
|
||||
|
||||
if not args.quick:
|
||||
result = await test_one_product(product, dirs)
|
||||
else:
|
||||
result = await test_one_product_quick(product, dirs)
|
||||
|
||||
all_results.append(result)
|
||||
|
||||
if result.success():
|
||||
print('Success')
|
||||
else:
|
||||
print('Failure')
|
||||
|
||||
f.write(generate_html_row(i+1, product, result))
|
||||
f.flush()
|
||||
|
||||
baseline_successes = len([x for x in all_results if x.baseline_success])
|
||||
product_successes = len([x for x in all_results if x.product_success and not x.product_has_diffs])
|
||||
board_successes = len([x for x in all_results if x.board_success and not x.board_has_diffs])
|
||||
f.write(f'''
|
||||
<tr>
|
||||
<td></td>
|
||||
<td># Successful</td>
|
||||
<td>{baseline_successes}</td>
|
||||
<td>{product_successes}</td>
|
||||
<td>{board_successes}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td># Failed</td>
|
||||
<td>N/A</td>
|
||||
<td>{baseline_successes - product_successes}</td>
|
||||
<td>{baseline_successes - board_successes}</td>
|
||||
</tr>
|
||||
</table>
|
||||
Finished running successfully.
|
||||
</body>\n''')
|
||||
|
||||
print('Success!')
|
||||
print('file://'+os.path.abspath(os.path.join(dirs.results, 'index.html')))
|
||||
|
||||
for result in all_results:
|
||||
if result.baseline_success and not result.success():
|
||||
print('There were one or more failing products. See the html report for details.')
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(main())
|
|
@ -0,0 +1,92 @@
|
|||
#!/bin/bash -u
|
||||
# Regression test for the product and/or board configuration converter.
|
||||
#
|
||||
# Builds 'nothing' for a given product-variant twice: with product/board
|
||||
# config makefiles converted to Starlark, and without such conversion.
|
||||
# The generated Ninja files should be the same.
|
||||
set -u
|
||||
|
||||
function die() {
|
||||
echo $@ >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
function usage() {
|
||||
cat <<EOF >&2
|
||||
Usage: $myname [-p] [-b] [-q] [-r] <product-variant> [product-variant ...]
|
||||
-p: Test RBC product configuration. This is implied if -b is not supplied
|
||||
-b: Test RBC board configuration. This is implied if -p is not supplied
|
||||
-q: Quiet. Suppress all output other than a failure message
|
||||
-r: Retain Ninja files
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
function build() {
|
||||
local -r flavor="$1"
|
||||
local -r product="$2"
|
||||
local -r variant="$3"
|
||||
shift 3
|
||||
command="build/soong/soong_ui.bash --make-mode TARGET_PRODUCT=$product TARGET_BUILD_VARIANT=$variant $@ nothing"
|
||||
if ! ANDROID_QUIET_BUILD=$quiet $command; then
|
||||
printf "%s-%s: %s build failed, actual command:\n %s\n" $product $variant $flavor "$command" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
mypath=$(realpath "$0")
|
||||
declare -r mydir=${mypath%/*/*/*/*}
|
||||
declare -r myname=${mypath#${mydir}/}
|
||||
|
||||
flags_rbc=()
|
||||
quiet=
|
||||
while getopts "bkpqr" o; do
|
||||
case "${o}" in
|
||||
k) ;; # backward compatibility to be removed later
|
||||
q) quiet=true ;;
|
||||
b) flags_rbc+=(RBC_BOARD_CONFIG=true) ;;
|
||||
p) flags_rbc+=(RBC_PRODUCT_CONFIG=true) ;;
|
||||
r) retain_files=t ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
[[ $# -gt 0 ]] || usage
|
||||
((${#flags_rbc[@]})) || flags_rbc+=(RBC_PRODUCT_CONFIG=true RBC_BOARD_CONFIG=true)
|
||||
|
||||
cd $mydir
|
||||
rc=0
|
||||
for arg in $@; do
|
||||
[[ "$arg" =~ ^([a-zA-Z0-9_]+)-([a-zA-Z0-9_]+)$ ]] || \
|
||||
die "Invalid product name: $arg. Example: aosp_arm64-userdebug"
|
||||
product="${BASH_REMATCH[1]}"
|
||||
variant="${BASH_REMATCH[2]}"
|
||||
ninja_files=(soong/build.ninja build-${product}.ninja build-${product}-package.ninja)
|
||||
|
||||
# Build with converter, save Ninja files, build without it.
|
||||
saved_ninja_dir=out/ninja_rbc/${product}-${variant}
|
||||
build RBC $product $variant ${flags_rbc[@]} && \
|
||||
rm -rf $saved_ninja_dir && mkdir -p $saved_ninja_dir/soong && \
|
||||
(for f in ${ninja_files[@]}; do mv -f out/$f $saved_ninja_dir/$f || exit 1; done) && \
|
||||
build baseline $product $variant
|
||||
rc=$?
|
||||
|
||||
# Compare Ninja files
|
||||
if ((rc==0)); then
|
||||
for f in "${ninja_files[@]}"; do
|
||||
diff_file=$(mktemp)
|
||||
diff out/$f $saved_ninja_dir/$f | head >& $diff_file
|
||||
if [[ -s $diff_file ]]; then
|
||||
echo ${product}-${variant}: "$f" is different '< make, > RBC):' >&2
|
||||
cat $diff_file >&2
|
||||
echo ...
|
||||
rc=1
|
||||
fi
|
||||
rm $diff_file
|
||||
done
|
||||
fi
|
||||
[[ -n "${retain_files:-}" ]] || rm -rf $saved_ninja_dir
|
||||
done
|
||||
|
||||
((rc==0)) || printf "In order to reproduce the failures above, run\n %s <product>-<variant>\n" $myname >&2
|
||||
exit $rc
|
|
@ -0,0 +1,109 @@
|
|||
# Platforms and toolchains for AOSP.
|
||||
#
|
||||
# Set default target platform for builds to rely on product config's arch and os variables
|
||||
build --platforms //build/bazel/platforms:android_target
|
||||
|
||||
# Use the target platform (android_x86, android_arm) in the bazel-out/ output
|
||||
# directory name fragment instead of the CPU (darwin, k8). This avoids
|
||||
# thrashing the output directory when switching between top level target
|
||||
# --platforms values.
|
||||
build --experimental_platform_in_output_dir
|
||||
|
||||
# Use toolchain resolution to find the cc toolchain.
|
||||
build --incompatible_enable_cc_toolchain_resolution
|
||||
|
||||
# Ensure that the host_javabase always use @local_jdk, the checked-in JDK.
|
||||
build --tool_java_runtime_version=local_jdk
|
||||
build --java_runtime_version=local_jdk
|
||||
|
||||
# Lock down the PATH variable in actions to /usr/bin and /usr/local/bin.
|
||||
build --experimental_strict_action_env
|
||||
|
||||
# Explicitly allow unresolved symlinks (it's an experimental Bazel feature)
|
||||
build --experimental_allow_unresolved_symlinks
|
||||
|
||||
# Enable usage of experimental cc-related build APIs
|
||||
build --experimental_cc_shared_library
|
||||
build --experimental_starlark_cc_import
|
||||
|
||||
# Do not tokenize copts, other than strings that consist of a single Make
|
||||
# variable. This prevents the need to double-escape characters like backslashes
|
||||
# and quotes in copts.
|
||||
build --features no_copts_tokenization
|
||||
|
||||
# Disable local cpp toolchain detection, as it is explicitly declared in AOSP.
|
||||
build --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1
|
||||
|
||||
build --proto_compiler=//external/protobuf:aprotoc
|
||||
|
||||
# Disable sandboxing for CppCompile actions, as headers are not fully specified.
|
||||
# TODO(b/186116353): This is a temporary fix, as appropriately-sandboxed actions
|
||||
# are a long term goal.
|
||||
build --strategy=CppCompile=standalone
|
||||
|
||||
# Enable use of the implementation_deps attribute in native cc rules
|
||||
build --experimental_cc_implementation_deps
|
||||
|
||||
# Enable building targets in //external:__subpackages__.
|
||||
common --experimental_sibling_repository_layout
|
||||
common --experimental_disable_external_package
|
||||
|
||||
# Enable toplevel_output_directories and Ninja executor in Bazel
|
||||
common --experimental_ninja_actions
|
||||
|
||||
# Increase refresh rate of command line UI for improved perceived responsiveness.
|
||||
common --show_progress_rate_limit=0.05
|
||||
|
||||
# These are disabled when running under soong_ui (default = auto). Force enable them here.
|
||||
common --color=yes
|
||||
common --curses=yes
|
||||
|
||||
# Show the full set of flags for observability and debuggability.
|
||||
common --announce_rc
|
||||
|
||||
# Run bazel query from the workspace, without cd'ing into out/soong/queryview
|
||||
# Note that this hardcodes the output dir. It will not work if $OUT_DIR != out.
|
||||
common:queryview --package_path=%workspace%/out/soong/queryview
|
||||
|
||||
# Run bazel query from the workspace, without cd'ing into out/soong/workspace
|
||||
# Note that this hardcodes the output dir. It will not work if $OUT_DIR != out.
|
||||
common:bp2build --package_path=%workspace%/out/soong/workspace
|
||||
|
||||
# Configurations specific to CI builds, generally to improve signal-to-noise ratio in server logs.
|
||||
common:ci --color=no
|
||||
common:ci --curses=no
|
||||
common:ci --show_progress_rate_limit=5
|
||||
common:ci --noshow_loading_progress
|
||||
test:ci --keep_going
|
||||
test:ci --test_output=errors
|
||||
|
||||
# Support a local user-specific bazelrc file.
|
||||
try-import %workspace%/user.bazelrc
|
||||
|
||||
build --android_sdk=//prebuilts/sdk:android_sdk
|
||||
build --experimental_enable_android_migration_apis
|
||||
build --experimental_google_legacy_api
|
||||
build --incompatible_java_common_parameters
|
||||
build --android_databinding_use_v3_4_args
|
||||
build --experimental_android_databinding_v2
|
||||
build --define=android_incremental_dexing_tool=d8_dexbuilder
|
||||
build --define=android_dexmerger_tool=d8_dexmerger
|
||||
build --nouse_workers_with_dexbuilder
|
||||
build --fat_apk_cpu=k8
|
||||
|
||||
# TODO(b/199038020): Use a python_toolchain when we have Starlark rules_python.
|
||||
# This also means all python scripts are using py3 runtime.
|
||||
build --python_top=//prebuilts/build-tools:python3
|
||||
build --noincompatible_use_python_toolchains
|
||||
|
||||
# Developer instance for result storage. This only works if you have access
|
||||
# to the Bazel GCP project. Follow the GCP gcloud client's auth instructions to
|
||||
# use --google_default_credentials.
|
||||
build:results --remote_instance_name=projects/bazel-untrusted/instances/default_instance
|
||||
build:results --project_id=bazel-untrusted
|
||||
build:results --remote_timeout=600
|
||||
build:results --google_default_credentials
|
||||
build:results --test_summary=detailed
|
||||
build:results --bes_backend=buildeventservice.googleapis.com
|
||||
build:results --bes_results_url=https://source.cloud.google.com/results/invocations
|
||||
build:results --show_progress_rate_limit=5
|
|
@ -0,0 +1,3 @@
|
|||
import %workspace%/build/bazel/common.bazelrc
|
||||
|
||||
build --host_platform //build/bazel/platforms:darwin_x86_64
|
|
@ -0,0 +1,198 @@
|
|||
# Android Build System Concepts
|
||||
|
||||
This document provides high level explanations and mapping of the internal
|
||||
build system components and concepts of the Android build system and Bazel,
|
||||
and how components communicate with each other.
|
||||
|
||||
For implementation concepts, see:
|
||||
https://android.googlesource.com/platform/build/bazel/+/refs/heads/master/docs/internal_concepts.md.
|
||||
|
||||
## High level components
|
||||
|
||||
This table provides a high level overview of the components in the current
|
||||
Android Platform build system, and how each component maps to a concept in
|
||||
Bazel.
|
||||
|
||||
|Android build system component|Description|Mapping to Bazel concepts|
|
||||
|---|---|---|
|
||||
|Kati|Make-compatible front-end. Encodes build logic in `.mk` scripts. Declares buildable units in `Android.mk`. Generates Ninja file directly.|Loading and analysis phase. Conceptually similar to `bazel build --nobuild`.|
|
||||
|Blueprint|Build definition syntax. Build syntax parser. Internal data structures like Modules/Variations/Context/Scope. Ninja file generator.|Starlark.|
|
||||
|Soong|Bazel-like front-end. Encodes build logic in Go. Declares build units in `Android.bp`, parsed by Blueprint. Uses Blueprint to generate Ninja file. Generates a `.mk` file with prebuilt module stubs to Kati.|Loading and analysis phase. Conceptually similar to `bazel build --nobuild command`.|
|
||||
|Ninja|Serialized command line action graph executor. Executes Ninja graph generated from Kati and Soong.|Bazel's execution phase.|
|
||||
|atest|Test executor and orchestrator.|Conceptually similar to `bazel test` command.|
|
||||
|Blueprint + Kati + Soong + Ninja + atest|The entire build pipeline for Android.|Conceptually similar to `bazel build` or `bazel test` commands.|
|
||||
|`<script>.sh`|Running arbitrary scripts in AOSP.|Conceptually similar to `bazel run` command.|
|
||||
|Make (replaced in-place by Kati)|No longer in use. Entire build system, replaced by the tools above.|Loading, analysis, execution phases. Conceptually similar to `bazel build` command.|
|
||||
|`Android.bp`|Build definition file for Soong.|`BUILD.bazel` or `BUILD`.|
|
||||
|`Android.mk`|Build definition file for Kati.|`BUILD.bazel` or `BUILD`.|
|
||||
|
||||
## Communication between components
|
||||
|
||||
* Kati product configuration component to generate config variables (config.mk, AndroidProducts.mk)
|
||||
* **“Kati-config” for the purpose of this document**
|
||||
* Kati component to generate build actions in Ninja files (main.mk, Android.mk files)
|
||||
* **“Kati-build” for the purpose of this document**
|
||||
* Kati component to generate packaging actions in Ninja files (packaging.mk file)
|
||||
* **“Kati-package” for the purpose of this document**
|
||||
* Kati component to generate cleaning actions in Ninja files (cleanbuild.mk, CleanSpec.mk files)
|
||||
* **"Kati-cleanspec" for the purpose of this document**
|
||||
* **soong\_build** (and **Blueprint**) component to generate build actions (Android.bp, Blueprints files)
|
||||
* **Ninja** component to execute actions from Kati-build, Kati-package and soong\_build
|
||||
* **Bazel** as the next generation of the entire build system, starting as a Ninja executor drop-in replacement
|
||||
* **soong\_ui** as the tool to orchestrate all of the above, and with auxiliary tools like finder, path\_interposer, soong\_env, minibp and bpglob.
|
||||
|
||||
The current build system architecture primarily uses **files** as the medium
|
||||
for inter-process communication (IPC), with one known case of unix socket
|
||||
communication (e.g.
|
||||
[path\_interposer](https://cs.android.com/android/platform/superproject/+/master:build/soong/ui/build/paths/logs.go;l=112-133;drc=184901135cda8bdcc51cab4f16c401a28a510593)),
|
||||
and a fifo between Ninja and soong_ui for the Protobuf stream for build
|
||||
status reporting.
|
||||
|
||||
## Component order
|
||||
|
||||
The build system components run in the following order, orchestrated by soong\_ui:
|
||||
|
||||
1. soong\_ui bootstraps itself with microfactory (`go build` replacement) and launches.
|
||||
1. soong\_ui runs auxiliary tools to aggregate files into filelists, for
|
||||
Android.mk, Android.bp, AndroidProducts.mk and several others.
|
||||
1. soong\_ui runs Kati-config with
|
||||
[the config.mk entry point](https://cs.android.com/android/platform/superproject/+/master:build/soong/ui/build/dumpvars.go;l=89;drc=9f43597ff7349c4facd9e338e5b4b277e625e518).
|
||||
1. soong\_ui orchestrates 3 Blueprint/Soong phases to generate the main out/soong/build.ninja file:
|
||||
minibootstrap, bootstrap, and primary.
|
||||
1. Minibootstrap phase uses Blueprint/Microfactory to build itself
|
||||
(minibp) so that Android.bp and Blueprint files can be used to define
|
||||
Soong.
|
||||
1. Bootstrap phase runs Ninja on a build.ninja file that runs minibp to
|
||||
read all Android.bp files across the source tree that describes Soong and
|
||||
plugins, and builds soong\_build.
|
||||
1. Primary phase runs Ninja on a build.ninja file that runs soong_build
|
||||
to generate the final out/soong/build.ninja file.
|
||||
1. soong\_build also runs its own tests alongside generating
|
||||
out/soong/build.ninja, which can be skipped with the `--skip-soong-tests`
|
||||
argument.
|
||||
1. soong\_ui runs Kati-cleanspec with
|
||||
[the cleanbuild.mk entry point](https://cs.android.com/android/platform/superproject/+/master:build/soong/ui/build/kati.go;l=362;drc=b1d30d63c5d1b818ea38e77cd155da2016fe8b6c).
|
||||
1. soong\_ui runs Kati-build to generate a Ninja file, with
|
||||
[the main.mk entry point.](https://cs.android.com/android/platform/superproject/+/master:build/soong/ui/build/kati.go;l=202;drc=b1d30d63c5d1b818ea38e77cd155da2016fe8b6c)
|
||||
1. soong\_ui runs Kati-package to generate a Ninja file, with
|
||||
[the packaging/main.mk](https://cs.android.com/android/platform/superproject/+/master:build/soong/ui/build/kati.go;l=314;drc=b1d30d63c5d1b818ea38e77cd155da2016fe8b6c)
|
||||
entry point.
|
||||
1. soong\_ui generates a Ninja file to combine above Ninja files.
|
||||
1. soong\_ui runs either Ninja or Bazel to execute the build, with the
|
||||
combined Ninja file as entry point.
|
||||
|
||||
soong\_ui has a --skip-make flag that will skip Kati-config, Kati cleanspec,
|
||||
Kati-build and Kati-package, used for Soong-only builds in NDK and some
|
||||
Mainline projects.
|
||||
|
||||
### soong\_ui
|
||||
|
||||
soong\_ui is primarily responsible for orchestrating the build, cleaning the
|
||||
build environment, and running auxiliary tools. These tools (minibp,
|
||||
microfactory) can bootstrap other tools (soong\_build), aggregate file lists
|
||||
(finder.go), improve hermeticity (path\_interposer, nsjail) or perform checks
|
||||
against the environment (soong\_env).
|
||||
|
||||
soong\_ui uses finder.go to generate <filename>.list files for other
|
||||
tools. For example, it generates Android.mk.list for Kati-build,
|
||||
AndroidProducts.mk.list for Kati-config, and Android.bp.list for
|
||||
soong\_build.
|
||||
|
||||
soong\_ui uses path\_interposer to prepare an hermetic $PATH with runtime
|
||||
checks against allowlisted system tools. The $PATH contains these system
|
||||
tools with checked-in prebuilts, and uses path\_interposer to intercept calls
|
||||
and error out whenever non-allowlisted tools are used (see out/.path for
|
||||
directory of intercepted tool symlinks).
|
||||
|
||||
soong\_ui generates a Kati suffix to ensure that Kati-generated files are
|
||||
regenerated if inputs to Kati have changed between builds.
|
||||
|
||||
soong\_ui calls Soong and Kati to generate Ninja files, and eventually
|
||||
creates another Ninja file (out/combined-<product>.ninja) to combine the
|
||||
others, and executes either Ninja or Bazel to complete the build.
|
||||
|
||||
soong\_ui sets up the sandbox and environment for the Ninja/Bazel process.
|
||||
|
||||
## Kati-config
|
||||
|
||||
As a product configuration tool, soong\_ui runs Kati-config in
|
||||
**[--dumpvars-mode](https://cs.android.com/android/platform/superproject/+/master:build/soong/cmd/soong_ui/main.go;l=298-305;drc=master)**
|
||||
to dump the values of specified Make variables at the end of an evaluation,
|
||||
with build/make/core/config.mk as the entry point. During this phase,
|
||||
Kati-config eventually evaluates[
|
||||
soong\_config.mk](https://cs.android.com/android/platform/superproject/+/master:build/make/core/soong_config.mk;l=2?q=soong.variables)
|
||||
to generate the **[soong.variables JSON
|
||||
file](https://cs.android.com/android/platform/superproject/+/master:build/make/core/soong_config.mk;l=16-222;drc=341928ecc5da205401bcfd86f098662b0cee7857)**.
|
||||
This way, Kati-config can communicate product configuration to soong\_build,
|
||||
as soong\_build parses the dumped variables from the JSON on startup, and
|
||||
stores them into an in-memory Config object.
|
||||
|
||||
To communicate
|
||||
[dexpreopt](https://cs.android.com/android/platform/superproject/+/master:build/soong/java/dexpreopt.go;l=115;drc=8cbc5d269b20b5743679bfb8684ed174dcf58a30)
|
||||
variables to soong\_build, [dexpreopt.config is also
|
||||
generated](https://cs.android.com/android/platform/superproject/+/master:build/make/core/dex_preopt_config.mk;l=71-142;drc=f26015449f0747b9fdeceb5ce70e30ecd76e20e8)
|
||||
as a $(shell) action and [read by
|
||||
soong\_build](https://cs.android.com/android/platform/superproject/+/master:build/soong/dexpreopt/config.go;l=175-196;drc=1af783fae74715bcf1a94733bd75b2e6cc688e8c)
|
||||
in a similar way as Kati-config evaluates dex\_preopt\_config.mk included in
|
||||
soong\_config.mk.
|
||||
|
||||
soong\_ui sets up a **KatiReader** to monitor Kati-config’s stdout/err for UI
|
||||
reporting and error handling purposes.
|
||||
|
||||
## soong\_build
|
||||
|
||||
soong\_build’s primary role is to evaluate all Android.bp files, run a series
|
||||
of mutators, and generate out/soong/build.ninja file.
|
||||
|
||||
soong\_build communicates with Kati-build by generating Make Vars and running
|
||||
the AndroidMk singleton to generate .mk files in the output directory
|
||||
(out/soong/{Android, late, make\_vars}-<product>.mk).
|
||||
|
||||
* Android-<product>.mk contains Soong modules as Make modules so Make
|
||||
modules can depend on Soong modules.
|
||||
* make\_vars-<product>.mk contains Make variables for Kati-build, exported
|
||||
from Soong modules. There are also checks built into this .mk file to ensure that
|
||||
if a duplicate Make variable of the same name comes from another source, the Soong
|
||||
and Make variable values are identical.
|
||||
* late-<product>.mk contains Make variables that are not read while Kati-build
|
||||
parses the Android.mk file. (Late variables)
|
||||
* soong\_ui invokes Kati to parse make\_vars .mk file earlier than the Android.mk
|
||||
files,and late.mk after parsing the Android.mk files.
|
||||
* late.mk is used to define phony rules to take advantage of Make’s ability to
|
||||
add extra dependencies to an existing rule. late.mk is not strictly necessary to
|
||||
make this happen at this moment, since late.mk rules don’t currently depend on any
|
||||
variables defined during Android.mk processing (e.g. ALL\_MODULES$(module).INSTALLED).
|
||||
|
||||
## Kati-build / Kati-package
|
||||
|
||||
Kati-build’s primary role is to evaluate all Android.mk files with
|
||||
build/make/core/main.mk as entry point, and generate
|
||||
out/build-<product>.ninja. It also generates cleanspec.ninja for the
|
||||
product, containing statements on how to remove stale output files.
|
||||
|
||||
Kati-build’s primary role is to evaluate all packaging .mk files with
|
||||
build/make/packaging/main.mk as entry point, including
|
||||
build/make/packaging/distdir.mk for dist-for-goals calls, and generate
|
||||
out/package-<product>.ninja.
|
||||
|
||||
Kati-build/Kati-package’s stdout/stderr is monitored by soong\_ui’s
|
||||
KatiReader to UI and error handling.
|
||||
|
||||
As Kati-build/Kati-package generates Ninja files, they also generate
|
||||
out/ninja-<product>.sh and out/env-<product>.sh. These scripts are
|
||||
wrappers for soong\_ui to execute Ninja with the correct Ninja files, in a
|
||||
controlled environment.
|
||||
|
||||
## Ninja
|
||||
|
||||
As Ninja executes files from Kati-build, Kati-package, soong\_build and other
|
||||
bootstrapping tools like Blueprint, it writes to a fifo in a proto front end
|
||||
that soong\_ui monitors with NinjaReader. NinjaReader ensures that the user
|
||||
interface for Ninja progress is consistent with the rest of the build.
|
||||
|
||||
## Bazel
|
||||
|
||||
As more Soong modules are converted to BUILD files, soong\_build serializes
|
||||
information about converted modules to BUILD/bzl files on disk. soong\_build
|
||||
then consumes information about these targets from Bazel by directly calling
|
||||
the Bazel client to issue `cquery` calls about these targets.
|
|
@ -0,0 +1,616 @@
|
|||
# Soong-Bazel equivalents
|
||||
|
||||
This doc aims to describe *internal*-facing implementation concepts. For
|
||||
external-facing, see
|
||||
https://android.googlesource.com/platform/build/bazel/+/refs/heads/master/docs/concepts.md.
|
||||
|
||||
[TOC]
|
||||
|
||||
## Overview
|
||||
|
||||
Soong/Ninja | Bazel | Remarks
|
||||
--------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------
|
||||
make phony goal, e.g. "dist", "sdk", "apps_only", "droidcore" | Top level `filegroup` rule target | [Details](#phony-goal)
|
||||
Ninja build target (phony) | (readable) alias to a file target |
|
||||
Ninja build target (non-phony) | File target |
|
||||
`ModuleFactory` | `RuleConfiguredTargetFactory` |
|
||||
`Module type` (e.g. `cc_library`) | Rule class (e.g. `cc_library`) |
|
||||
Module object instance | Target (instance of a rule) | [Details](#instance)
|
||||
Module properties | [Rule attributes](https://docs.bazel.build/versions/main/skylark/rules.html#attributes) | [Details](#props)
|
||||
Module name | Target label |
|
||||
Module variant | (Split) configured target |
|
||||
[LoadHooks](#loadhooks) | [macros (ish)](https://docs.bazel.build/versions/main/skylark/macros.html) |
|
||||
Top-down mutators on modules | Split configuration on targets | Allows building multiple "variants" of the same build artifact in the same build.
|
||||
Bottom-up mutators on modules | [Aspects](https://docs.bazel.build/versions/main/skylark/aspects.html) on targets |
|
||||
[Build statement (Ninja)](#ninja-build-statement) | Action (result of ctx.actions.run) |
|
||||
[Rule statement (Ninja)](#ninja-rules) | [ctx.actions.run() API](https://docs.bazel.build/versions/main/skylark/lib/actions.html) |
|
||||
`out/soong/build.ninja` and `out/build-<target>.ninja` | Action graph (serialized) |
|
||||
Pool (ninja) | Thread pools / `ExecutorService` |
|
||||
Blueprint's Registration and Parse, `ResolveDependencies` phase | Loading phase |
|
||||
Blueprint's [Generate and Write phases](#blueprint-analysis) | Analysis Phase |
|
||||
Ninja execution | Execution phase |
|
||||
Blueprints/`Android.bp` files | `BUILD`/`BUILD.bazel` files |
|
||||
[Namespaces](#namespaces) | [Packages](#pkgs) | Most Soong modules are within the global namespace
|
||||
[Mutators](#mutators) | Configuration keys (ish) |
|
||||
[Variation](#variation) | Configuration value |
|
||||
[Singleton](#singleton) | Aspect-ish |
|
||||
Target (system + vendor + product) | [Platform](https://docs.bazel.build/versions/main/platforms.html) |
|
||||
Bash scripts e.g. envsetup functions, `soong_ui.bash`) | Repository rule |
|
||||
Product and board configuration makefile and env variables | Configuration in Bazel (ish) | [Details](#config)
|
||||
[Dependency Tags](#deptags) | Provider names |
|
||||
|
||||
## Remarks
|
||||
|
||||
### Phony goals {#phony-goal}
|
||||
|
||||
Soong maintains the make terminology of
|
||||
[goals](https://www.gnu.org/software/make/manual/html_node/Goals.html) to denote
|
||||
what should be built. All modules can be specified by name as a goal, in
|
||||
addition, phony goals are supported.
|
||||
|
||||
A Phony goal creates a Make-style phony rule, a rule with no commands that can
|
||||
depend on other phony rules or real files. Phony can be called on the same name
|
||||
multiple times to add additional dependencies. These are often used to build
|
||||
many targets at once. The default goal for Android's build system is `droid`.
|
||||
Some other common phony goals include: `nothing` (perform loading/analysis),
|
||||
`docs`, `checkbuild`, `apps_only`.
|
||||
|
||||
Some common phony goals are defined in
|
||||
[`build/make/core/main.mk`](http://cs.android.com/android/platform/superproject/+/master:build/make/core/main.mk)
|
||||
The purpose is to help `soong_ui` to determine what top level files to build.
|
||||
|
||||
### Module/Target {#instance}
|
||||
|
||||
When a Module is instantiated by Blueprint (which calls the appropriate
|
||||
`ModuleFactory`), the [property structs](#props) are populated by Blueprint.
|
||||
|
||||
Blueprint performs no additional operations on these properties, such that
|
||||
dependencies on other modules and references to source files are unresolved
|
||||
initially. [`Mutators`](#mutators) then introspect the values of properties to
|
||||
[specify dependencies](https://cs.android.com/android/platform/superproject/+/master:build/blueprint/module_ctx.go;l=871-886,918-960;drc=030150d8f9d164783ea661f07793c45198739cca)
|
||||
between modules, which
|
||||
[Blueprint resolves](https://cs.android.com/android/platform/superproject/+/master:build/blueprint/context.go;l=1630,1667;drc=5c4abb15e3b84ab0bcedfa119e2feb397d1fb106).
|
||||
Source files (including globs) and output paths for references to other modules
|
||||
are resolved during [blueprint analysis](#blueprint-analysis) via the various
|
||||
`Path[s]ForModuleSrc[Excludes]` functions within
|
||||
[build/soong/android/paths.go](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/paths.go).
|
||||
|
||||
For a Bazel target instance, the dependencies and source file references within
|
||||
[`attrs`](#attributes) have been resolved by Bazel.
|
||||
|
||||
Bazel
|
||||
[implementation](https://github.com/bazelbuild/bazel/blob/a20b32690a71caf712d1d241f01fef16649562ba/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveBaseTraversalFunction.java#L113-L140)
|
||||
to collect deps.
|
||||
|
||||
### Properties/Attributes {#props}
|
||||
|
||||
#### Properties
|
||||
|
||||
Within Soong/Blueprint, properties are represented as Go structs, which can be
|
||||
nested, with no depth limit. Properties can be primitive or pointer types, but
|
||||
they must be one of these types: `int64`, `string`, `bool`, `list`.
|
||||
|
||||
These properties can be defined from various structs within the module type
|
||||
factory itself (via
|
||||
[AddProperties](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=1276;drc=8631cc7327919845c9d9037188cbd483d22ba077))
|
||||
or from common helper functions such as:
|
||||
|
||||
* `InitAndroidModule`:
|
||||
[specifies](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=1042-1045;drc=8631cc7327919845c9d9037188cbd483d22ba077)
|
||||
name-related, common, and dist properties.
|
||||
* `InitAndroidArchModule`: adds
|
||||
[host/device properies](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=1077;drc=8631cc7327919845c9d9037188cbd483d22ba077)
|
||||
|
||||
Go comments for a property will be treated as documentation to describe the
|
||||
property. In some cases, these comments describe a default value for the
|
||||
property. However, the default value is not based on the comment or field
|
||||
definition but resolved somewhere within the module's mutators or build. These
|
||||
defaults are often determined using Blueprint
|
||||
[`proptools`](https://cs.android.com/android/platform/superproject/+/master:build/blueprint/proptools/proptools.go)
|
||||
`*Default` functions. For example, `cc` modules have a property
|
||||
[`include_build_directory`](https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/compiler.go;l=265;drc=135bf55281d79576f33469ce4f9abc517a614af5),
|
||||
which is described in the comments. The default value is
|
||||
[resolved](https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/compiler.go;l=265;drc=135bf55281d79576f33469ce4f9abc517a614af5)
|
||||
when compiler flags are being determined.
|
||||
|
||||
In general, these can be set in an Android.bp file. However, if the property is
|
||||
tagged with `` `blueprint:"mutated"` ``, it can only be set programmatically
|
||||
within Blueprint/Soong. Additionally, `mutated` tagged properties also support
|
||||
`map` and `int` types in addition to those mentioned above. These `mutated`
|
||||
properties are used to propagate data that gets set during mutations, which
|
||||
ensures that the information is copied successfully to module variants during
|
||||
mutation.
|
||||
|
||||
Soong supports additional property tags to provide additional
|
||||
functionality/information about a property:
|
||||
|
||||
* `` `android:arch_variant` ``: This specifies that a property can be
|
||||
configured for different architectures, operating systems, targets, etc. The
|
||||
[arch mutator](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/arch.go;l=597;drc=135bf55281d79576f33469ce4f9abc517a614af5),
|
||||
will merge target-specific properties into the correct variant for
|
||||
properties with this tag.
|
||||
|
||||
Note: if a nested property is arch-variant, all recursively nesting structs
|
||||
that can be specified in an Android.bp file must also be tagged as
|
||||
arch-variant.
|
||||
|
||||
* `` `android:variant_prepend` ``: When merging properties for the arch
|
||||
variant, the arch-specific values should be *prepended* rather than appended
|
||||
to existing property values.
|
||||
|
||||
* `` `android:path` ``: This specifies that this property will contain some
|
||||
combination of:
|
||||
|
||||
* module-relative paths
|
||||
* references to other modules in the form:
|
||||
* `":<name>{.<tag>}"`, where `{.<tag>}` is optional to specify a
|
||||
non-default output file, specific to the module type
|
||||
* `"<namespace>:<name>{.<tag>}""`
|
||||
|
||||
Note: Dependencies to other modules for these properties will be
|
||||
automatically added by the
|
||||
[pathdeps mutator](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/path_properties.go;l=40;drc=40131a3f9e5ac974a44d3bd1293d31d585dc3a07).
|
||||
|
||||
#### Attributes
|
||||
|
||||
Similar to properties,
|
||||
[attributes](https://docs.bazel.build/versions/main/skylark/lib/attr.html) only
|
||||
support a few types. The difference is that Bazel attributes cannot be nested .
|
||||
|
||||
Some attributes are
|
||||
[common](https://docs.bazel.build/versions/2.1.0/be/common-definitions.html#common-attributes)
|
||||
across many/all rule classes, including (but not limited to) `name`, `tag`,
|
||||
`visibility`.
|
||||
|
||||
The definition of an attribute can contain settings, such as: its default value,
|
||||
whether it is mandatory ot have a value, and its documentation.
|
||||
|
||||
To specify a source file or reference to another module, use `label` or
|
||||
`label_list` attribute types (rather than regular `string` or `string_list`
|
||||
types). These support additional restrictions (as compared to `string*` types),
|
||||
such as:
|
||||
|
||||
* whether files are supported
|
||||
* the providers that must be given by a dependency
|
||||
* whether the dependency should be executable
|
||||
* the configuration (host, target)
|
||||
* aspects
|
||||
|
||||
Unlike Soong, when accessing this attribute within the rule's implementation (at
|
||||
anlysis time), the label(s) will be resolved to the file or target they refer
|
||||
to.
|
||||
|
||||
Attributes do not need to specify whether they accept
|
||||
[configurable attribute](https://docs.bazel.build/versions/main/configurable-attributes.html).
|
||||
However, the rule definition can specify the configuration or specify a
|
||||
[configuration transition](https://docs.bazel.build/versions/main/skylark/lib/transition.html).
|
||||
|
||||
However, not all target definitions within a `BUILD` file are invoking a rule.
|
||||
Instead, they may invoke a Starlark macro, which is a load-time wrapper around
|
||||
rules. Arguments for a macro are not typed. If macros are used, their arguments
|
||||
would have to be wrangled into an attribute-compatible type.
|
||||
|
||||
### LoadHooks
|
||||
|
||||
[LoadHooks](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/hooks.go;l=24-36;drc=07656410df1836a70bea3054e50bb410ecbf8e07)
|
||||
provide access to :
|
||||
|
||||
* append/prepend additional properties to the module
|
||||
(`AppendProperties`/`PrependProperties`)
|
||||
* create a new module `CreateModule`
|
||||
|
||||
`LoadHooks` make it easier to extend existing module factories to always specify
|
||||
certain properties or to split a single `Android.bp` definition into multiple
|
||||
Module instances .
|
||||
|
||||
### Build Statement (ninja) {#ninja-build-statement}
|
||||
|
||||
[Ninja build statements](https://ninja-build.org/manual.html#_build_statements) can be
|
||||
expanded from [Ninja rules](https://ninja-build.org/manual.html#_rules), which are like
|
||||
templates.
|
||||
|
||||
```
|
||||
# rule
|
||||
rule cattool
|
||||
depfile = out/test/depfile.d
|
||||
command = ${in} ${out}
|
||||
|
||||
# build statement
|
||||
build out/test/output.txt: cattool test/cattool.sh test/one test/two
|
||||
|
||||
# build statement
|
||||
build out/test/other_output.txt: cattool test/cattool.sh test/three test/four
|
||||
```
|
||||
|
||||
Rules for `Android.mk` modules (`out/build-<target>.ninja`) and build statements
|
||||
are 1:1. That is every rule is only used once by a single build statement.
|
||||
|
||||
Soong (`out/soong/build.ninja`) rules are reused extensively in build statements
|
||||
(1:many). For example the `Cp` rule is a commonly used rule for creating build
|
||||
statements which copy files.
|
||||
|
||||
### Ninja Rules in Soong {#ninja-rules}
|
||||
|
||||
In Soong, Ninja rules can be defined in two ways:
|
||||
|
||||
* [rule_builder](http://cs.android.com/android/platform/superproject/+/master:build/soong/android/rule_builder.go)
|
||||
* [package_ctx](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/package_ctx.go;l=102-293;drc=77cdcfdeafd383ef1f1214226c47eb20c902a28f)
|
||||
|
||||
### Blueprint Generate & Write phase {#blueprint-analysis}
|
||||
|
||||
1. [`ResolveDependencies`](https://cs.android.com/android/platform/superproject/+/master:build/blueprint/context.go;l=1547;drc=5c4abb15e3b84ab0bcedfa119e2feb397d1fb106)
|
||||
Running a series of Mutators, to add dependencies, split modules with
|
||||
variations, etc
|
||||
1. [`PrepareBuildActions`](https://cs.android.com/android/platform/superproject/+/master:build/blueprint/context.go;l=2367;drc=5c4abb15e3b84ab0bcedfa119e2feb397d1fb106):
|
||||
|
||||
1. Running Modules’ `GenerateBuildActions` to generate Ninja statements,
|
||||
which in turn calls each module's
|
||||
[`GenerateAndroidBuildActions`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=445-448;drc=8631cc7327919845c9d9037188cbd483d22ba077).
|
||||
1. Running Singletons to generate Ninja statements that generate docs,
|
||||
android.mk statements, etc
|
||||
|
||||
### Soong namespaces {#namespace}
|
||||
|
||||
Module
|
||||
[Namespaces](https://android.googlesource.com/platform/build/soong/+/master/README.md#namespaces)
|
||||
can import other namespaces, and there’s a module name lookup algorithm which
|
||||
terminates in the global namespace.
|
||||
|
||||
Note: this is not widely used and most Soong modules are in the global
|
||||
namespace.
|
||||
|
||||
### Bazel packages {#pkgs}
|
||||
|
||||
[Packages](https://docs.bazel.build/versions/main/build-ref.html#packages) can
|
||||
nest subpackages recursively, but they are independent containers of Bazel
|
||||
targets. This means that Bazel target names only need to be unique within a
|
||||
package.
|
||||
|
||||
### Mutators
|
||||
|
||||
blueprint invokes mutators are invoking in the order they are registered (e.g.
|
||||
top-down and bottom-up can be interleaved). Each mutator applys a single
|
||||
visitation to every module in the graph.
|
||||
|
||||
Mutators visiting module can parallelized, while maintaining their ordering, by
|
||||
calling `.Parallel()`.
|
||||
|
||||
While top-down and bottom-up mutators differ in their purposes, the interface
|
||||
available to each contains many similarities. Both have access to:
|
||||
[`BaseModuleContext`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=139;drc=8631cc7327919845c9d9037188cbd483d22ba077)
|
||||
and
|
||||
[`BaseMutatorContext`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/mutator.go;l=246;drc=2ada09a5463a0108d713773679c5ba2c35450fa4).
|
||||
|
||||
In addition to the registration order, Soong supports phase-based ordering of
|
||||
mutators:
|
||||
|
||||
1. Pre-Arch: mutators that need to run before arch-variation. For example,
|
||||
defaults are handled at this stage such properties from defaults are
|
||||
correctly propagated to arch-variants later.
|
||||
|
||||
1. (Hard-coded)
|
||||
[`archMutator`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/arch.go;l=597;drc=135bf55281d79576f33469ce4f9abc517a614af5)
|
||||
splits a module into the appropriate target(s). Next, the arch- and
|
||||
OS-specific properties are merged into the appropriate variant.
|
||||
|
||||
1. Pre-Deps: mutators that can/need to run before deps have been resolved, for
|
||||
instance, creating variations that have an impact on dependency resolution.
|
||||
|
||||
1. (Hard-coded)
|
||||
[`depsMutator`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/mutator.go;l=502;drc=2ada09a5463a0108d713773679c5ba2c35450fa4),
|
||||
which calls the `DepsMutator` function that *must* be part of a Soong
|
||||
`Module`'s interface.
|
||||
|
||||
1. Post-Deps: mutators that need to run after deps have been resolved
|
||||
|
||||
1. Final-Deps like post-deps but variations cannot be created
|
||||
|
||||
#### Top-down Mutator
|
||||
|
||||
A top-down mutator is invoked on a module before its dependencies.
|
||||
|
||||
The general purpose is to propagate dependency info from a module to its
|
||||
dependencies.
|
||||
|
||||
#### Bottom-up Mutator
|
||||
|
||||
A bottom-up mutator is invoked on a module only after the mutator has been
|
||||
invoked on all its dependencies.
|
||||
|
||||
The general purpose of a bottom-up mutator is to split modules into variants.
|
||||
|
||||
### Soong/Blueprint Variation {#variation}
|
||||
|
||||
A tuple (name of mutator, variation / config value) passed to
|
||||
`CreateVariations`.
|
||||
|
||||
### Configuration {#config}
|
||||
|
||||
Soong's config process encompasses both *what* should build and *how* it should
|
||||
build. This section focuses on the *how* aspect.
|
||||
|
||||
We do not cover how Soong's configuration will be implemented in Bazel, but the
|
||||
general capabilities of Bazel to configure builds.
|
||||
|
||||
#### Soong
|
||||
|
||||
Android users can configure their builds based on:
|
||||
|
||||
* Specifying a target (via lunch, banchan, tapas, or Soong’s command line
|
||||
options)
|
||||
* Environment variables
|
||||
|
||||
Some environment variables or command line options are used directly to alter
|
||||
the build. However, specification of target product encompasses many aspects of
|
||||
both *what* and *how* things are built. This configuration is currently handled
|
||||
within Make but is in the process of being migrated to Starlark.
|
||||
|
||||
Soong
|
||||
[invokes Kati](https://cs.android.com/android/platform/superproject/+/master:build/soong/ui/build/dumpvars.go;drc=7ae80a704494bbb934dced97ed97eb55a21a9a00)
|
||||
to run in a "config" mode, also commonly known as "product config". This mode
|
||||
limits the scope of what `.mk` files are parsed. The product-specific handlers
|
||||
are largely in:
|
||||
|
||||
* [`product_config.mk`](https://cs.android.com/android/platform/superproject/+/master:build/make/core/product_config.mk;drc=d189ab71f3505ea28324ebfaced2466af5eb0af7):
|
||||
this subset of functionality is also commonly referred to as "product
|
||||
config"
|
||||
* [`board_config.mk`](https://cs.android.com/android/platform/superproject/+/master:build/make/core/board_config.mk)
|
||||
|
||||
However, these cover only a subset of
|
||||
[`config.mk`](https://cs.android.com/android/platform/superproject/+/master:build/make/core/config.mk).
|
||||
This ensures that all values have appropriate defaults and specify details
|
||||
necessary to the build. Some examples:
|
||||
|
||||
* [handling of version defaults](https://cs.android.com/android/platform/superproject/+/master:build/make/core/version_defaults.mk)
|
||||
* [rbe setup](https://cs.android.com/android/platform/superproject/+/master:build/make/core/rbe.mk)
|
||||
* [user-defined config](https://cs.android.com/android/platform/superproject/+/master:build/make/core/config.mk;l=300-308;drc=ee20ae1a8dcdfe7b843d65099000708800d9b93a):
|
||||
[buildspec.mk](http://cs.android.com/android/platform/superproject/+/master:build/make/buildspec.mk.default)
|
||||
is similar to
|
||||
[`.bazelrc`](https://docs.bazel.build/versions/main/guide.html#bazelrc-the-bazel-configuration-file)
|
||||
file.
|
||||
* ensuring
|
||||
[`PRODUCT_SHIPPING_API_LEVEL`](https://cs.android.com/android/platform/superproject/+/master:build/make/core/config.mk;l=729-745;drc=ee20ae1a8dcdfe7b843d65099000708800d9b93a)
|
||||
is defaulted if not specified by the target.
|
||||
|
||||
Finally, Kati dumps variables to be consumed by Soong:
|
||||
|
||||
* environment variables specifically requested by Soong
|
||||
* writes
|
||||
[`soong.variables`](http://cs.android.com/android/platform/superproject/+/master:build/make/core/soong_config.mk),
|
||||
a JSON file
|
||||
|
||||
Throughout Soong, environment variables can be accessed to alter the build via
|
||||
the `Config`:
|
||||
|
||||
* [`GetEnv`](http://cs.android.com/search?q=f:soong%20%5C.GetEnv%5C%28%20-f:%2Fui%2F%20-f:%2Fcmd%2F&sq=)
|
||||
* [`GetEnvWithDefault`](http://cs.android.com/search?q=f:soong%20%5C.GetEnvWithDefault%5C%28%20-f:%2Fui%2F%20-f:%2Fcmd%2F&sq=)
|
||||
* [`IsEnvTrue`](http://cs.android.com/search?q=f:soong%20%5C.IsEnvTrue%5C%28%20-f:%2Fui%2F%20-f:%2Fcmd%2F&sq=)
|
||||
* [`IsEnvFalse`](http://cs.android.com/search?q=f:soong%20%5C.IsEnvFalse%5C%28%20-f:%2Fui%2F%20-f:%2Fcmd%2F&sq=)
|
||||
|
||||
Soong
|
||||
[loads the `soong.variables`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/config.go;l=174;drc=b078ade28d94c85cec78e9776eb31948a5647070)
|
||||
config file, stored as
|
||||
[`productVariables`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/variable.go;l=163;drc=16e77a9b303a71018eb6630f12f1414cd6ad615c).
|
||||
These variables are used in three ways:
|
||||
|
||||
* Direct access from `Config`, for example: paths can be
|
||||
[opted out](https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/sanitize.go;l=364,371,393;drc=582fc2d1dde6c70687e6a0bea192f2a2ef67bbd5)
|
||||
of specific sanitizers
|
||||
* In limited cases, users can use these within their `Android.bp` file to
|
||||
control what is built or perform variable replacement.
|
||||
[`variableProperties`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/variable.go;l=38;drc=16e77a9b303a71018eb6630f12f1414cd6ad615c)
|
||||
limits which configuration variables can be specified within an `Android.bp`
|
||||
file and which properties they can apply to. The values specified within an
|
||||
`Android.bp` file, are merged/replaced by the
|
||||
[`VariableMutator`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/variable.go;l=539;drc=16e77a9b303a71018eb6630f12f1414cd6ad615c),
|
||||
which appends performs string replacement if requested and merges the
|
||||
properties into the modules.
|
||||
* Through
|
||||
[Soong Config Variables](https://android.googlesource.com/platform/build/soong/+/refs/heads/master/README.md#soong-config-variables):
|
||||
which allow users to specify additional configuration variables that can be
|
||||
used within an `Android.bp` file for the module type and properties they
|
||||
request. Soong config variable structs are
|
||||
[dynamically generated](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/soongconfig/modules.go;l=257;drc=997f27aa0353dabf76d063d78ee5d4495da85651)
|
||||
via reflection. In the
|
||||
[factory](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/soong_config_modules.go;l=423;drc=18fd09998223d004a926b02938e4cb588e4cc934),
|
||||
the properties to merge into the module instance are
|
||||
[identified](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/soongconfig/modules.go;l=416;drc=997f27aa0353dabf76d063d78ee5d4495da85651)
|
||||
based on the config variable's type.
|
||||
|
||||
The product configuration also provides information about architecture and
|
||||
operating system, both for target(s) and host. This is used within the
|
||||
[`archMutator`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/arch.go;l=569-597;drc=135bf55281d79576f33469ce4f9abc517a614af5)
|
||||
to split a module into the required variants and merge target-specific
|
||||
properties into the appropriate variant. Only properties which have been tagged
|
||||
with `android:"arch_variant"` can be specified within an `Android.bp` as
|
||||
arch/os/target-specific. For example:
|
||||
|
||||
```go
|
||||
type properties struct {
|
||||
// this property will be arch-variant
|
||||
Arch_variant_not_nested *string `android:"arch_variant"`
|
||||
|
||||
Nested_with_arch_variant struct {
|
||||
// this property is arch-variant
|
||||
Arch_variant_nested *string `android:"arch_variant"`
|
||||
|
||||
// this property is **not** arch-variant
|
||||
Not_arch_variant_nested *string
|
||||
} `android:"arch_variant"`
|
||||
|
||||
Nested_no_arch_variant struct {
|
||||
// this property is **NOT** arch-variant
|
||||
No_arch_variant_nested_not_arch_variant *string `android:"arch_variant"`
|
||||
|
||||
// this property is **not** arch-variant
|
||||
No_arch_variant_nested *string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The arch/os/target-specific structs are
|
||||
[dynamically generated](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/arch.go;l=780-787;drc=135bf55281d79576f33469ce4f9abc517a614af5)
|
||||
based on the tags using reflection.
|
||||
|
||||
#### Bazel
|
||||
|
||||
Bazel documentation covers configurable builds fairly extensively, so this is a
|
||||
short overview that primarily links to existing Bazel documentation rather than
|
||||
repeating it here.
|
||||
|
||||
[Configurable attributes](https://docs.bazel.build/versions/main/configurable-attributes.html),
|
||||
(aka `select()`) allows users to toggle values of build rule attributes on the
|
||||
command line.
|
||||
|
||||
Within a `rule`, the value of a `select` will have been resolved based on the
|
||||
configuration at analysis phase. However, within a macro (at loading phase,
|
||||
before analysis phase), a `select()` is an opaque type that cannot be inspected.
|
||||
This restricts what operations are possible on the arguments passed to a macro.
|
||||
|
||||
The conditions within a `select` statement are one of:
|
||||
|
||||
* [`config_setting`](https://docs.bazel.build/versions/main/be/general.html#config_setting)
|
||||
* [`constraint_value`](https://docs.bazel.build/versions/main/be/platform.html#constraint_value)
|
||||
|
||||
A `config_setting` is a collection of build settings, whether defined by Bazel,
|
||||
or user-defined.
|
||||
|
||||
User-defined
|
||||
[build settings](https://docs.bazel.build/versions/main/skylark/config.html#defining-build-settings)
|
||||
allow users to specify additional configuration, which *optionally* can be
|
||||
specified as a flag. In addition to specifying build settings within a
|
||||
`config_setting`, rules can depend directly on them.
|
||||
|
||||
In addition, Bazel supports
|
||||
[`platform`s](https://docs.bazel.build/versions/main/be/platform.html#platform),
|
||||
which is a named collection of constraints. Both a target and host platform can
|
||||
be specified on the command line.
|
||||
[More about platforms](https://docs.bazel.build/versions/main/platforms.html).
|
||||
|
||||
## Communicating between modules/targets
|
||||
|
||||
### Soong communication
|
||||
|
||||
There are many mechanisms to communicate between Soong modules. Because of this,
|
||||
it can be difficult to trace the information communicated between modules.
|
||||
|
||||
#### Dependency Tags {#deptags}
|
||||
|
||||
Dependency tags are the primary way to filter module dependencies by what
|
||||
purpose the dependency serves. For example, to filter for annotation processor
|
||||
plugins in the deps of a Java library module, use `ctx.VisitDirectDeps` and
|
||||
check the tags:
|
||||
|
||||
```
|
||||
ctx.VisitDirectDeps(func(module android.Module) {
|
||||
tag := ctx.OtherModuleDependencyTag(module)
|
||||
if tag == pluginTag { patchPaths += ":" + strings.Split(ctx.OtherModuleDir(module), "/")[0] }
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
At this point the module managing the dependency, may have enough information to
|
||||
cast it to a specific type or interface and perform more specific operations.
|
||||
|
||||
For instance, shared libraries and executables have
|
||||
[special handling](http://cs.android.com/android/platform/superproject/+/master:build/soong/cc/cc.go;l=2771-2776;drc=5df7bd33f7b64e2b880856e3193419697a8fb693)
|
||||
for static library dependencies: where the coverage files and source based ABI
|
||||
dump files are needed explicitly. Based on the dependency tag, the module is
|
||||
cast to a concrete type, like `cc.Module`, where internal fields are accessed
|
||||
and used to obtain the desired data.
|
||||
|
||||
Usage of dependency tags can be more evident when used between module types
|
||||
representing different langauges, as the functions must be exported in Go due to
|
||||
Soong's language-based package layout. For example, rust uses `cc` module's
|
||||
[`HasStubVariants`](http://cs.android.com/android/platform/superproject/+/master:build/soong/rust/rust.go;l=1457-1458;drc=9f59e8db270f58a3f2e4fe5bc041f84363a5877e).
|
||||
|
||||
#### Interfaces
|
||||
|
||||
A common mechanism for a module to communicate information about itself is to
|
||||
define or implement a Go interface.
|
||||
|
||||
Some interfaces are common throughout Soong:
|
||||
|
||||
* [`SourceFileProducer`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=2967;drc=8707cd74bf083fe4a31e5f5aa5e74bd2a47e9e58),
|
||||
by implementing `Srcs() Paths`
|
||||
* [`OutputFileProducer`](http://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=2974;drc=8707cd74bf083fe4a31e5f5aa5e74bd2a47e9e58)
|
||||
by implementing `OutputFiles(string) (Paths, error)`
|
||||
* [`HostToolProvider`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=3032;drc=8707cd74bf083fe4a31e5f5aa5e74bd2a47e9e58)
|
||||
by implementing `HostToolPath() OptionalPath`
|
||||
|
||||
`SourceFileProducer` and `OutputFileProducer` are used to resolve references to
|
||||
other modules via `android:"path"` references.
|
||||
|
||||
Modules may define additional interfaces. For example, `genrule` defines a
|
||||
[`SourceFileGenerator` interface](http://cs.android.com/android/platform/superproject/+/master:build/soong/genrule/genrule.go;l=98-102;drc=2ada09a5463a0108d713773679c5ba2c35450fa4).
|
||||
|
||||
#### Providers
|
||||
|
||||
Soong has Bazel-inspired providers, but providers are not used in all cases yet.
|
||||
|
||||
Usages of providers are the easiest, simplest, and cleanest communication
|
||||
approach in Soong.
|
||||
|
||||
In the module providing information, these are specified via
|
||||
[`SetProvider`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=212;drc=5a34ffb350fb295780e5c373fd1c78430fa4e3ed)
|
||||
and
|
||||
[`SetVariationProvider`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/mutator.go;l=719;drc=5a34ffb350fb295780e5c373fd1c78430fa4e3ed).
|
||||
|
||||
In the module retrieving information,
|
||||
[`HasProvider`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=205-206;drc=8631cc7327919845c9d9037188cbd483d22ba077)
|
||||
and
|
||||
[`Provider`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=198-203;drc=8631cc7327919845c9d9037188cbd483d22ba077)
|
||||
or
|
||||
[`OtherModuleHasProvider`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=195-196;drc=8631cc7327919845c9d9037188cbd483d22ba077)
|
||||
and
|
||||
[`OtherModuleProvider`](https://cs.android.com/android/platform/superproject/+/master:build/soong/android/module.go;l=189-193;drc=8631cc7327919845c9d9037188cbd483d22ba077)
|
||||
are used to test existence and retrieve a provider.
|
||||
|
||||
### Bazel communication
|
||||
|
||||
Targets primarily communicate with each other via providers in Bazel rule
|
||||
implementations. All rules have access to any of the providers but rules will
|
||||
pick and choose which ones to access based on their needs. For example, all
|
||||
rules can access `JavaInfo` provider, which provides information about compile
|
||||
and rolled-up runtime jars for javac and java invocations downstream. However,
|
||||
the `JavaInfo` provider is only useful to `java_*` rules or rules that need jvm
|
||||
information.
|
||||
|
||||
#### Starlark rules
|
||||
|
||||
[Providers](https://docs.bazel.build/versions/main/skylark/rules.html#providers)
|
||||
are pieces of information exposed to other modules.
|
||||
|
||||
One such provider is `DefaultInfo`, which contains the default output files and
|
||||
[`runfiles`](https://docs.bazel.build/versions/main/skylark/rules.html#runfiles).
|
||||
|
||||
Rule authors can also create
|
||||
[custom providers](https://docs.bazel.build/versions/main/skylark/lib/Provider.html#modules.Provider)
|
||||
or implement existing providers to communicate information specific to their
|
||||
rule logic. For instance, in Android Starlark
|
||||
[`cc_object`](http://cs/android/build/bazel/rules/cc_object.bzl?l=86-87&rcl=42607e831f8ff73c82825b663609cafb777c18e1)
|
||||
rule implementation, we return a
|
||||
[`CcInfo`](https://docs.bazel.build/versions/main/skylark/lib/CcInfo.html)
|
||||
provider and a custom
|
||||
[`CcObjectInfo`](http://cs/android/build/bazel/rules/cc_object.bzl?l=17-21&rcl=42607e831f8ff73c82825b663609cafb777c18e1)
|
||||
provider.
|
||||
|
||||
#### Native rules
|
||||
|
||||
For implementation of native rules in Java,
|
||||
[`ruleContext.getPrerequisite`](https://github.com/bazelbuild/bazel/blob/a20b32690a71caf712d1d241f01fef16649562ba/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java#L911-L983)
|
||||
is used to extract providers from dependencies.
|
||||
|
||||
#### `depset` construction
|
||||
|
||||
[`depset`](https://docs.bazel.build/versions/main/glossary.html#depset) are used
|
||||
in conjunction with providers to accumulate data efficiently from transitive
|
||||
dependencies. used to accumulate data from transitive dependencies.
|
||||
|
||||
#### `exports`
|
||||
|
||||
Some target have an `exports` attribute by convention, like
|
||||
[`java_library.exports`](https://docs.bazel.build/versions/main/be/java.html#java_import.exports).
|
||||
This attribute is commonly used to propagate transitive dependencies to the
|
||||
dependent as though the dependent has a direct edge to the transitive
|
||||
dependencies.
|
|
@ -0,0 +1,20 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.app"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="21"
|
||||
android:targetSdkVersion="21" />
|
||||
|
||||
<application android:label="Test App" >
|
||||
<activity
|
||||
android:name="com.app.MainActivity"
|
||||
android:label="App" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
|
@ -0,0 +1,62 @@
|
|||
load("//build/bazel/rules/android:android_binary.bzl", "android_binary")
|
||||
load("//build/bazel/rules/cc:cc_library_static.bzl", "cc_library_static")
|
||||
load("//build/bazel/rules/cc:cc_library_shared.bzl", "cc_library_shared")
|
||||
load("@rules_android//rules:rules.bzl", "android_library")
|
||||
|
||||
android_binary(
|
||||
name = "app",
|
||||
manifest = "AndroidManifest.xml",
|
||||
deps = [
|
||||
":applib",
|
||||
],
|
||||
)
|
||||
|
||||
android_binary(
|
||||
name = "app-cert-string",
|
||||
certificate_name = "platform",
|
||||
manifest = "AndroidManifest.xml",
|
||||
deps = [
|
||||
":applib",
|
||||
],
|
||||
)
|
||||
|
||||
android_binary(
|
||||
name = "app-cert-module",
|
||||
certificate = "//build/make/target/product/security:aosp-testkey",
|
||||
manifest = "AndroidManifest.xml",
|
||||
deps = [
|
||||
":applib",
|
||||
],
|
||||
)
|
||||
|
||||
android_library(
|
||||
name = "applib",
|
||||
srcs = [
|
||||
"Jni.java",
|
||||
"MainActivity.java",
|
||||
],
|
||||
manifest = "AndroidManifest.xml",
|
||||
resource_files = glob(["res/**"]),
|
||||
deps = [
|
||||
":jni",
|
||||
":lib",
|
||||
],
|
||||
)
|
||||
|
||||
android_library(
|
||||
name = "lib",
|
||||
srcs = ["Lib.java"],
|
||||
)
|
||||
|
||||
cc_library_shared(
|
||||
name = "jni",
|
||||
srcs = ["jni.cc"],
|
||||
deps = [":jni_dep"],
|
||||
)
|
||||
|
||||
cc_library_static(
|
||||
name = "jni_dep",
|
||||
srcs = ["jni_dep.cc"],
|
||||
hdrs = ["jni_dep.h"],
|
||||
deps = ["//libnativehelper:jni_headers"],
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* 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.app;
|
||||
|
||||
public class Jni {
|
||||
public static native String hello();
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* 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.app;
|
||||
|
||||
public class Lib {
|
||||
public static String message() {
|
||||
return "Hello Lib";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* 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.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.view.View;
|
||||
import android.util.Log;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main_layout);
|
||||
Log.i("tag", Lib.message());
|
||||
|
||||
final TextView textView = findViewById(R.id.text);
|
||||
|
||||
Button button = (Button) findViewById(R.id.button);
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
textView.setText("Button clicked");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
|
||||
#include "build/bazel/examples/android_app/java/com/app/jni_dep.h"
|
||||
|
||||
extern "C" JNIEXPORT jstring JNICALL
|
||||
Java_com_app_Jni_hello(JNIEnv *env, jclass clazz) {
|
||||
std::string hello = "Hello";
|
||||
std::string jni = "JNI";
|
||||
return NewStringLatin1(env, (hello + " " + jni).c_str());
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "build/bazel/examples/android_app/java/com/app/jni_dep.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
jstring NewStringLatin1(JNIEnv *env, const char *str) {
|
||||
int len = strlen(str);
|
||||
jchar *str1;
|
||||
str1 = reinterpret_cast<jchar *>(malloc(len * sizeof(jchar)));
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
str1[i] = (unsigned char)str[i];
|
||||
}
|
||||
jstring result = env->NewString(str1, len);
|
||||
free(str1);
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
jstring NewStringLatin1(JNIEnv *env, const char *str);
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
<TextView android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello, I am a TextView" />
|
||||
<Button android:id="@+id/button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Button" />
|
||||
</LinearLayout>
|
|
@ -0,0 +1,133 @@
|
|||
// Copyright (C) 2021 The Android Open Source Project
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This is a minimal apex that contains no files.
|
||||
// Build with `m build.bazel.examples.apex.minimal`.
|
||||
//
|
||||
// Generated by system/apex/tools/create_apex_skeleton.sh.
|
||||
|
||||
// WARNING: These keys are for test and dev purposes only.
|
||||
package {
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
apex_key {
|
||||
name: "build.bazel.examples.apex.minimal.key",
|
||||
public_key: "build.bazel.examples.apex.minimal.avbpubkey",
|
||||
private_key: "build.bazel.examples.apex.minimal.pem",
|
||||
}
|
||||
|
||||
android_app_certificate {
|
||||
name: "build.bazel.examples.apex.minimal.certificate",
|
||||
certificate: "build.bazel.examples.apex.minimal",
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "build.bazel.examples.apex.minimal-file_contexts",
|
||||
srcs: [
|
||||
"file_contexts",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "build.bazel.examples.apex.minimal_dummy_cc_lib",
|
||||
|
||||
srcs: ["dummy_cc_lib.cc"],
|
||||
|
||||
apex_available: [
|
||||
"build.bazel.examples.apex.minimal",
|
||||
"build.bazel.examples.apex.minimal_compressed",
|
||||
],
|
||||
|
||||
// Because the APEX sets this
|
||||
product_specific: true,
|
||||
|
||||
// Because the APEX sets this
|
||||
min_sdk_version: "30",
|
||||
}
|
||||
|
||||
prebuilt_etc {
|
||||
name: "build.bazel.examples.apex.minimal_dummy_named_prebuilt_etc",
|
||||
src: "dummy_prebuilt_etc_data_1",
|
||||
filename: "dummy_prebuilt_etc_data_1_renamed",
|
||||
sub_dir: "dummy_sub_dir",
|
||||
}
|
||||
|
||||
prebuilt_etc {
|
||||
name: "build.bazel.examples.apex.minimal_dummy_unnamed_prebuilt_etc",
|
||||
src: "dummy_prebuilt_etc_data_2",
|
||||
sub_dir: "dummy_sub_dir",
|
||||
}
|
||||
|
||||
prebuilt_etc {
|
||||
name: "build.bazel.examples.apex.minimal_dummy_prebuilt_etc_without_subdir",
|
||||
src: "dummy_prebuilt_etc_data_3",
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "build.bazel.examples.apex.cc_binary",
|
||||
srcs: ["main.cc"],
|
||||
|
||||
apex_available: [
|
||||
"build.bazel.examples.apex.minimal",
|
||||
"build.bazel.examples.apex.minimal_compressed"
|
||||
],
|
||||
|
||||
// Because the APEX sets these
|
||||
product_specific: true,
|
||||
min_sdk_version: "30",
|
||||
}
|
||||
|
||||
apex_defaults {
|
||||
name: "build.bazel.examples.apex.minimal_defaults",
|
||||
manifest: "manifest.json",
|
||||
file_contexts: ":build.bazel.examples.apex.minimal-file_contexts",
|
||||
|
||||
// So that we aren't considered a "platform APEX" and can use a file_context that lives outside of system/sepolicy/apex
|
||||
product_specific: true,
|
||||
|
||||
key: "build.bazel.examples.apex.minimal.key",
|
||||
min_sdk_version: "30",
|
||||
|
||||
native_shared_libs: [
|
||||
"build.bazel.examples.apex.minimal_dummy_cc_lib",
|
||||
],
|
||||
|
||||
prebuilts: [
|
||||
"build.bazel.examples.apex.minimal_dummy_named_prebuilt_etc",
|
||||
"build.bazel.examples.apex.minimal_dummy_unnamed_prebuilt_etc",
|
||||
"build.bazel.examples.apex.minimal_dummy_prebuilt_etc_without_subdir",
|
||||
],
|
||||
|
||||
binaries: [
|
||||
"build.bazel.examples.apex.cc_binary",
|
||||
],
|
||||
|
||||
certificate: ":build.bazel.examples.apex.minimal.certificate",
|
||||
}
|
||||
|
||||
apex {
|
||||
name: "build.bazel.examples.apex.minimal",
|
||||
defaults: [
|
||||
"build.bazel.examples.apex.minimal_defaults",
|
||||
]
|
||||
}
|
||||
|
||||
apex {
|
||||
name: "build.bazel.examples.apex.minimal_compressed",
|
||||
compressible: true,
|
||||
defaults: [
|
||||
"build.bazel.examples.apex.minimal_defaults",
|
||||
]
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,51 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIJKQIBAAKCAgEA3kVUTZJFAc0jOjcBQeikubCeYb6AGWzowgGurkwkX7zGY0rN
|
||||
s30r8vTuFtmQreU1vjp3e5mOTas7TE9A6BevTSZGgaZEHPujolgf0hfPaCLlZw3p
|
||||
BwEwE+lQppbRV/PEWLWM5suHUtFgAmch7o3dXO+5Kxy3T1wdivUT7rgIsWZZLwt7
|
||||
JNtTkm0YucmSBsN3QLhbevqb8msZrt8GgvJyd2jbGlTsP4j0R0DgSehkWwNFsxzn
|
||||
abdT1Uk+uwEY0p3uHhlLxkIDoOV0LmKmrwTmfEDJFMqlhdJNWfZ80sYG+vYcb1YF
|
||||
+5YwqnGiZwPUb4ARzdXwg7kjZVnKegi9tuTbVdkCT3MbS5r/uLQ1/SyD1aCg0iHS
|
||||
pltJhqa5VddvuvNjuWgjDrvPJlub8DMfn3YSX6qaPSEBqDCDhbERzpAIGhAV8rUL
|
||||
VbSS1E5F+YNvfNwGXVxd9u4D6HqS0sxA30RERYwYiBl8f8g7n9Kyw/pKNQ+ii5q7
|
||||
MtXcN7mBUPUwj4NpFnMyXjPWje1r2T0ZdwxXnU+hw1Kzgp5o/r5WJsh/GhJq52wt
|
||||
WcMR3AnNf4IB1UAVKhlY9/6zHLqNDH/dRnuYkhLvUqheh/rVrdbwPnPhbSnxDE4D
|
||||
WGXVM/dwoB5cqt2ZOQnIm4Ro4R5NR2mJ354Mene51pTx5qenZUKvo/UUC3UCAwEA
|
||||
AQKCAgEAyezOA5LIYjSMtkxWNhw12gQcPswj7/VDF00T9oBx4w/KY1YHvfIPRS9C
|
||||
RTvt9izvQBw5g+4im2jd/Btb6f3qYfpNv2bfJj1tkQTiE6lR4VcidRbsBlML7Grf
|
||||
vBfzoyVv0O9OTDXGgHR59nTfHKuA2Pdnj0UNO2mB5UV0kEBclV1X1Cdn/jnKmJHI
|
||||
DrCSmtZktkVFxll55ydpM7alYb0ERHrb4fYYkjfHRBwqJrqawRwd6/RsP1wvKurZ
|
||||
tGXwuRaExo9QiZJbXYZWn/U7XHDlOyhYBS18ZjCB2SLWj10b5k5D0tmhocf1+kI1
|
||||
ucR+77S3d/nOALzm7SI/kdHzF/6dSpQEptNeYaBxfNnDe+tjTseuINN0L+q/gU/j
|
||||
tt2+HtAKzEwNsZTbbU6CHkMXIndiKzMRNtQQvqL0st+5EY3LNzAhq81xPpIEk+lR
|
||||
3/lh1utDExr5APIzGzreNTthmZ/mUBtb412retgtvqZenUqmOw6bE/HsesuvNcT5
|
||||
kwPgwv6pXnuVUJpofBmq3iH9q1oNfNapLWMVSzsqYncMG0rJx98WcZzcuXFrpYic
|
||||
fnDLJ7f38PguX5IUTAVj4vxbAmPizDz4pByW6pwKtHegSHf35Zj7dZovV7dsjHg5
|
||||
KKOpEi86bo4jBlGtAQ41/mZi38yrnd2WZlYHb542gimDWPJb3FkCggEBAP5mqdJw
|
||||
NCDDCKlp/TMiP1MfgyLIgy4AELuU8AV6pSxYSd6bJZmEe6IWxgrzmBn4HdtL1W4B
|
||||
asSjRTKeTxcStB3Kang5OAYWFP/IoWprNXcNWdHZmfLXcK4kU4JoXxGZawsBwGip
|
||||
2ZlXdvWcAc/FABVGOoj0SHDT6/9GCXBw5+6u9aQLJ05E75hd3t6kMZAXaKfL1di+
|
||||
EzGhkT7bTIWDBfAGWVfAv9fbWki3/Tr4S3TCRZdDry3oLtum9f9dvdRch3Zmx3WS
|
||||
wKCVsD5cAb1HMc1wc6ftb0AHRaeC/Ff5mBjXASPf6FrcJoqn0xvIwrjO+haUlsJa
|
||||
+evcIY+ZzEzMGscCggEBAN+q976fvGwCNIV+aocE5FBJlwTvPaAGTnUx54VZLD9Y
|
||||
b0IlZVOHQjS+33kl35WqTAm2byziWn05YN6Twgmz8V18GBg72Ow6JOKKV1F/1f77
|
||||
aVnX1uIY4XGzQAyUNRmmzZkFhINPdfeKwVDij4bJdnxZz9TC6emRkqFFF2xygRm3
|
||||
sIeFEbJAKU8VFQPqDl89rHAnS99ey6uZsmiaRh0Fiz4zz0sMD7b95FRrhF7ISF0w
|
||||
2f+75tsud/JIVg00O6HAY1NN7uNBHUrVe6WUDmC5zX1dgfKOrLTs8y9SBMHUmvDw
|
||||
xMYBp16LBeC2AX1QH2H4eqw8Un2KfcZsKREQNS3AS+MCggEBAJ3JfzsObMaFMTIi
|
||||
kvDMJQqhWOySAQre74Ho9pXvY9MFT4vKHqABE82M4niYbZZt1dbWSiJYrqgXvCuR
|
||||
FOzypNR1X2QB2UWtHIkpHzSqGhclKLiHhnygMztPPJx9r7lytnm1NGm2L0h0f0wG
|
||||
3vjG7y5CyLt5CBUy3AUQo3oiDTh1O9XrNQ3Oo+yVDE56+GKuojKwsookGjOGSlf6
|
||||
HJQSl/Qve+p5moN/gZfoxh91MRfSBuezC0wl3ipOe/VPZxX37ez6AmxiASeYsB99
|
||||
YXbMWY9aV+Gn2oCUAhfLnkfSfwupDwP5NFxmf2EwhjeNZXjKp0KqFnelha1Mc2Rl
|
||||
t9lKHrECggEAINhieUPLz7CjNddSnXFCdefYnYjka9OBQgSKEzL9JHBAJl6HerSq
|
||||
LES7XHcLVlcjw2le+iBjWXBLoWPhYrth/nByuVxQhqAjOoFGQVmce01AM0lW7Ozq
|
||||
bl/8T9yTz6iHGKmOxBmvISLnMJGUsh5zn98wffYBk6Mk/TnALtTB0J0A92W7K4nw
|
||||
hwR5iZGdeq7725xpr+ujzRdM879z/F8MC55gGo0y4ZR3K05+qcyPk9/Qo5VcWWOB
|
||||
ibrFqDq7Zw1xiJIxOn4dZxfiiHYthlbCrl5E7vG0uvzw2UoaGLy35Bn3S3yCr4eK
|
||||
3Wzc2yIg+aobmZ9iHb1wqurHPRI8PPO4MQKCAQBU7kJwRhJ1BUd0mG59aJSIwWOn
|
||||
PBl7oMBwGGrKp7/lquK+2VAR/Q0uFnGtYkjFg4n2kzi72F1IkLS02BTo5QR5Jwfr
|
||||
oJmH9ZldB+StNuqA4Zhg53dSW0WSkVN/xBGIWBY99b+yJi0NONrIL11xbBwPTMMp
|
||||
3CI0kfNnl9iWuNq/7q0eilf1S2P+L4uaE+N5fmfS2VVRTV1ChiSZcZEHBKBp32MC
|
||||
e04kkElHzDGaK5Jsi6AlPppH2TYsewmbMwseBUTH/pst0HJK2pTLpbsNQKA7e2v9
|
||||
4O3DzvgWLrXNqdvwSnd4efahsm+aoE9eyj3rIMj1JKsvAtc5WEmXhEke22dX
|
||||
-----END RSA PRIVATE KEY-----
|
Binary file not shown.
|
@ -0,0 +1,34 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIF5TCCA80CFG12QQebWMaR+Kj0TNs0Y7VzDDVEMA0GCSqGSIb3DQEBCwUAMIGt
|
||||
MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
|
||||
bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
|
||||
MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEpMCcGA1UEAwwgYnVp
|
||||
bGQuYmF6ZWwuZXhhbXBsZXMubWluaW1hbGFwZXgwIBcNMjEwNzE2MDU1MTExWhgP
|
||||
NDc1OTA2MTIwNTUxMTFaMIGtMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZv
|
||||
cm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQ
|
||||
MA4GA1UECwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lk
|
||||
LmNvbTEpMCcGA1UEAwwgYnVpbGQuYmF6ZWwuZXhhbXBsZXMubWluaW1hbGFwZXgw
|
||||
ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCu0WkwooTpX9wzJoM79KjD
|
||||
ZNj1tl74H/v2Iac/j4QYZiYBtcZelPCHISY5CWYPjkA5HY3dka6zjMeh7gUjRLre
|
||||
7pYiFWwdeQmv6sAO3q0bYEK4+WqLdiYQR9tV8bkSPWy+3DUqKkHEfbNCPip0tlYw
|
||||
h4rnZ0b5YZPGRLHsFtX1SS+RRtlg91eiAgpWdhhL4fELJUv2jD2o/DKYZI+4fwwx
|
||||
P/sgoiS18IAxiHvN6a3AcC70YvWape+GhVtptlYBaFNNQ7jmVLXsXIyCMrfFypbT
|
||||
jopjMhuk/pnazA/3+eK1Yay3OPtPM9NGE2VVBvHDqwCeQT0EIe8hIsrHIUVy067q
|
||||
/byNk3hVM3tK9z8/OPYRDlLyzxshfdt0Q0JpkTdzXXBT2t5i0bow6+9e1rJyw7xM
|
||||
zRczYxfmyKti4KZ9ZrykENW8P2vYQNj10ZANvC1WGM8nFSet5I61xnxuQMy4wZwz
|
||||
4a3yz3PPdD1iFxjw0r57z1/8k9qSsRCVXipLOo7ZxweoGyyEgUuTcvrel6fAcvct
|
||||
V+m0oBNLWG6+uAViPKWdNr0Wl0odamjj2IOowaw5/1QHWGADpXGob6Dy7k0fVL8Z
|
||||
U/3VeNA/e293MHM9M7eWRxrMduUGCDYicyTUsHKPgFVpk5A9kHe4b6iQb/6fztyy
|
||||
IZ5lz/jGQOITXe0HE4CRywIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQA9gnyIrSW3
|
||||
2/oOfApLdPcKLXxOKF0MGykV4OQjWJTCwIOojmPVmFfd2nDFdAy6yW5kSVas0Om0
|
||||
CABQqMHqfayCzgECgNkzdNRwwczKgPMBijt+SpSqpA9ma9KTTyWI20vZfXj/5d4G
|
||||
3cZXCJ20hYP5eCjz2JoqEKuHvzcf4k4U6hPOyGHw7Zj8XQuoHHUJzpWZzn6/8Qh5
|
||||
ESAmQ6JJWT2JrpKVvHcaO+SNQmox1+s0+4e3L6WqtoMAHkaKSNGq/8/VH1A+0qg8
|
||||
BQGTycPQb0lhV3laDxkKVnBNC5tB1qi+i8mHxQnTGh7GsZWgvFwyPMdqchJa/c69
|
||||
oZX06Ip99UZSQpMCh6GOxs7KoD7idN9mmsKtE7ycu6mYr4/tEGbAv0/rBiZvxIXU
|
||||
K22GfQlGKpFRd2rxOcguRj+KavdM8N+zokT9i+k+w0xJQWnHWp6faw/oYBkahAkr
|
||||
GKh60mALHcU6L7SGM3TAJV4Xsy+wy6KwhkJZVFgMGKsdcx9aj7tSwmgW8RMiYrpQ
|
||||
B6j8s4jxmRQn0yFBkmjRr9dgWFQh8I2hoMt+Wu4AuIH6Ui4PvE7gcV0h2ws+QMsA
|
||||
+64a702ESExURkhtamWlxiKbnmy4rcDycdE1rb2XnZM1hic1R0PYmZV9jZo1tPk+
|
||||
YAqGsO9wGSNNs9Lej85K8DzErmYEVQZuTQ==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,9 @@
|
|||
int main(int argc, char** argv) {
|
||||
// Unused
|
||||
(void)argc;
|
||||
|
||||
// Unused
|
||||
(void)argv;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
1
|
|
@ -0,0 +1 @@
|
|||
2
|
|
@ -0,0 +1 @@
|
|||
3
|
|
@ -0,0 +1,5 @@
|
|||
/bin/apex_test_preInstallHook u:object_r:apex_test_prepostinstall_exec:s0
|
||||
/bin/apex_test_postInstallHook u:object_r:apex_test_prepostinstall_exec:s0
|
||||
/bin/surfaceflinger u:object_r:surfaceflinger_exec:s0
|
||||
/lib(64)?(/.*)? u:object_r:system_lib_file:s0
|
||||
(/.*)? u:object_r:system_file:s0
|
|
@ -0,0 +1 @@
|
|||
int main() { return 0; }
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "build.bazel.examples.apex.minimal",
|
||||
"version": 1
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
java_binary(
|
||||
name = "hello_java",
|
||||
srcs = ["example/HelloWorld.java"],
|
||||
main_class = "com.bazel.example.HelloWorld",
|
||||
deps = [":hello_java_lib"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "hello_java_lib",
|
||||
srcs = ["example_lib/HelloLib.java"],
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
package com.bazel.example;
|
||||
|
||||
import com.bazel.example_lib.HelloLib;
|
||||
|
||||
public class HelloWorld {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello world!");
|
||||
System.out.println("Library says: " + HelloLib.libValue());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.bazel.example_lib;
|
||||
|
||||
public class HelloLib {
|
||||
public static String libValue() {
|
||||
return "Hello Library!";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
# Examples of Bazel queries in the QueryView
|
||||
|
||||
**Warning**: This feature is undergoing active development and the generated
|
||||
Bazel BUILD files and other user-facing APIs will change without warning. We
|
||||
recommend to use this feature for learning, exploration, information gathering
|
||||
and debugging purposes only.
|
||||
|
||||
## Usage
|
||||
|
||||
Setup your AOSP product config and create the queryview directory:
|
||||
|
||||
```
|
||||
source build/envsetup.sh
|
||||
lunch aosp_arm # or your preferred target
|
||||
m queryview
|
||||
```
|
||||
|
||||
Then, run `bazel query` with the `queryview` config, and `--query_file` pointing
|
||||
to the file containing the query expression to run for the current product
|
||||
configuration:
|
||||
|
||||
```
|
||||
bazel query --config=queryview --query_file=build/bazel/examples/queries/android_app.txt
|
||||
```
|
||||
|
||||
Alternatively, you can also write the expression directly in the command:
|
||||
|
||||
```
|
||||
bazel query --config=queryview 'kind("android_app rule", //...)'
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* `android_apps`: lists all `android_app` modules for the current product configuration
|
||||
* `nocrt`: modules with `nocrt: True`
|
||||
* `apex_available`: modules with `//apex_available:platform` in the `apex_available` list property
|
||||
* `libc_variant`: all variants for `libc`
|
|
@ -0,0 +1 @@
|
|||
kind("android_app rule", //...)
|
|
@ -0,0 +1 @@
|
|||
attr(apex_available, //apex_available:platform, //...)
|
|
@ -0,0 +1 @@
|
|||
attr(module_name, \Alibc$, //bionic/libc:all)
|
|
@ -0,0 +1 @@
|
|||
attr(nocrt, 1, //...)
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2020 The Android Open Source Project
|
||||
#
|
||||
# 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.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
function run_query() {
|
||||
local f=$1; shift;
|
||||
bazel query --config=queryview --query_file="${f}"
|
||||
}
|
||||
|
||||
function run_all_queries() {
|
||||
for f in $(ls -1 | grep .txt); do
|
||||
run_query "${f}"
|
||||
done
|
||||
}
|
||||
|
||||
run_all_queries
|
|
@ -0,0 +1,101 @@
|
|||
// Use local copy of the soong_config_module_type dep graph to keep this Android.bp
|
||||
// self-contained.
|
||||
|
||||
package {
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
soong_config_string_variable {
|
||||
name: "fake_library_linking_strategy",
|
||||
values: [
|
||||
"prefer_static",
|
||||
],
|
||||
}
|
||||
|
||||
soong_config_module_type {
|
||||
name: "fake_library_linking_strategy_cc_defaults",
|
||||
module_type: "cc_defaults",
|
||||
config_namespace: "bp2build",
|
||||
variables: ["fake_library_linking_strategy"],
|
||||
properties: [
|
||||
"shared_libs",
|
||||
"static_libs",
|
||||
],
|
||||
}
|
||||
|
||||
// Fake cc_library modules for testing
|
||||
cc_library {
|
||||
name: "bp2build_foo",
|
||||
srcs: ["main.cpp"],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "bp2build_bar",
|
||||
srcs: ["main.cpp"],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "bp2build_baz",
|
||||
srcs: ["main.cpp"],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "bp2build_qux",
|
||||
srcs: ["main.cpp"],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "bp2build_quux",
|
||||
srcs: ["main.cpp"],
|
||||
}
|
||||
|
||||
fake_library_linking_strategy_cc_defaults {
|
||||
name: "fake_libadbd_binary_dependencies",
|
||||
static_libs: [
|
||||
"bp2build_foo",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"bp2build_bar",
|
||||
],
|
||||
|
||||
soong_config_variables:{
|
||||
fake_library_linking_strategy: {
|
||||
prefer_static: {
|
||||
static_libs: [
|
||||
"bp2build_baz",
|
||||
],
|
||||
},
|
||||
conditions_default: {
|
||||
shared_libs: [
|
||||
"bp2build_qux",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
target: {
|
||||
android: {
|
||||
shared_libs: ["bp2build_quux"],
|
||||
},
|
||||
linux_glibc: {
|
||||
enabled: false,
|
||||
},
|
||||
linux_musl: {
|
||||
enabled: false,
|
||||
},
|
||||
linux_bionic: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Experimental "stub" adbd for bp2build development
|
||||
cc_binary {
|
||||
name: "bp2build_adbd",
|
||||
defaults: ["adbd_defaults", "host_adbd_supported", "fake_libadbd_binary_dependencies"],
|
||||
srcs: [
|
||||
"main.cpp",
|
||||
],
|
||||
use_version_lib: false,
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
int main() {return 0; }
|
|
@ -0,0 +1,39 @@
|
|||
# JSON module graph queries
|
||||
|
||||
This directory contains `jq` scripts that query Soong's module graph.
|
||||
`jq` may be installed through your distribution's repository.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
m json-module-graph
|
||||
query.sh [-C] <command> <base-of-your-tree>/out/soong/module-graph.json [argument]
|
||||
```
|
||||
|
||||
The following commands are available:
|
||||
* `directDeps` prints the names of the direct dependencies of the given module
|
||||
* `distanceFromLeaves` prints the longest distance each module has from a leaf
|
||||
in the module graph within the transitive closure of given module
|
||||
* `filterSubtree` dumps only those modules that are in the given subtree of the
|
||||
source tree
|
||||
* `fullTransitiveDeps` returns the full transitive dependencies of the given
|
||||
module
|
||||
* `moduleTypeStats`: returns of a summary of the module types present on the
|
||||
input
|
||||
* `modulesOfType`: returns the names of modules of the input type
|
||||
* `printModule` prints all variations of a given module
|
||||
* `printModule`: returns a slightly more consise view of the input module
|
||||
* `properties`: returns the properties set in the input module, includes
|
||||
properties set via defaults
|
||||
* `transitiveDeps` prints the names of the transitive dependencies of the given
|
||||
module
|
||||
* `usedVariations` returns a map that shows which variations are used in the
|
||||
input and what values they take
|
||||
* `variantTransitions` summarizes the variant transitions in the transitive
|
||||
closure of the given module
|
||||
* `fullTransitiveDepsProperties` returns the properties set (including via
|
||||
defaults) grouped by module type of the modules in the transitive closure of
|
||||
the given module
|
||||
|
||||
It's best to filter the full module graph to the part you are interested in
|
||||
because `jq` isn't too fast on the full graph.
|
|
@ -0,0 +1,5 @@
|
|||
# CMD: Returns the names of the direct dependencies of the module named $arg
|
||||
|
||||
include "library";
|
||||
|
||||
[.[] | select(.Name == $arg) | .Deps | map(.Name)] | flatten | unique | sort
|
|
@ -0,0 +1,56 @@
|
|||
# CMD: Returns the maximum distance from a leaf for each module
|
||||
|
||||
include "library";
|
||||
|
||||
def onlyDeps:
|
||||
{ Name: .Name, Deps: .Deps | map(.Name) }
|
||||
;
|
||||
|
||||
def mergeDepsForSameModule:
|
||||
group_by(.Name) | map({Name: .[0].Name, Deps: map(.Deps) | flatten | unique | sort})
|
||||
;
|
||||
|
||||
def toMergeMap:
|
||||
map({key: .Name, value: .Deps}) | from_entries
|
||||
;
|
||||
|
||||
def moduleGraphNoVariants:
|
||||
map(onlyDeps) | mergeDepsForSameModule | toMergeMap
|
||||
;
|
||||
|
||||
def removeSelfEdges:
|
||||
to_entries |
|
||||
map(.key as $key | {key: .key, value: .value | [.[] | select(. != $key)]}) |
|
||||
from_entries
|
||||
;
|
||||
|
||||
def nextDepths($m):
|
||||
. as $old |
|
||||
to_entries |
|
||||
map({
|
||||
key: .key,
|
||||
value: (
|
||||
.key as $key |
|
||||
$m[.key] // [] |
|
||||
map($old[.]) |
|
||||
if any(. == -1) then -1 else (max // -1) + 1 end
|
||||
)
|
||||
}) |
|
||||
from_entries
|
||||
;
|
||||
|
||||
def maxDepths($m):
|
||||
map({key: ., value: -1}) | from_entries |
|
||||
{Prev: [], Next: .} |
|
||||
until (.Prev == .Next; {Prev: .Next, Next: .Next | nextDepths($m)}) |
|
||||
.Next
|
||||
;
|
||||
|
||||
def variantlessDistancesFromLeaves($root):
|
||||
(moduleGraphNoVariants | removeSelfEdges) as $m |
|
||||
[$root] |
|
||||
transitiveDeps($m) |
|
||||
maxDepths($m)
|
||||
;
|
||||
|
||||
variantlessDistancesFromLeaves($arg)
|
|
@ -0,0 +1,11 @@
|
|||
# CMD: Returns modules defined under the directory $arg
|
||||
|
||||
include "library";
|
||||
|
||||
def isBlueprint($p): .Blueprint | index($p) != null
|
||||
;
|
||||
|
||||
def isBlueprintPrefix($p): .Blueprint | startswith($p)
|
||||
;
|
||||
|
||||
[.[] | select(isBlueprintPrefix($arg))]
|
|
@ -0,0 +1,61 @@
|
|||
# CMD: Finds all modules whose input files cross package boundaries.
|
||||
|
||||
include "library";
|
||||
|
||||
def getBlueprintDirPaths:
|
||||
[.[] | .Blueprint | getDirPath] | sort_by(.) | unique | map({(.):""}) | add
|
||||
;
|
||||
|
||||
def getNonNullActionModules:
|
||||
[.[] | select(nonNullAction)]
|
||||
;
|
||||
|
||||
def getOutputsOfModule:
|
||||
[.Module.Actions | .[] | .Outputs | if . == null then [] else . end | .[]]
|
||||
;
|
||||
|
||||
def getOutputsOfModules($nonNullActionModules):
|
||||
$nonNullActionModules | map({(.Name):getOutputsOfModule}) | add
|
||||
;
|
||||
|
||||
def getDepOutputs($outputsOfModules):
|
||||
. as $depName |
|
||||
if in($outputsOfModules) then ($outputsOfModules | ."\($depName)")
|
||||
else [] end | .[]
|
||||
;
|
||||
|
||||
def getDepOutputsOfModule($outputsOfModules):
|
||||
[.Deps | .[] | .Name | getDepOutputs($outputsOfModules)]
|
||||
| map({(.):""}) | add
|
||||
;
|
||||
|
||||
def isDirPathMatch($blueprintDirPath; $allBlueprintDirPaths):
|
||||
def _isDirPathMatch($blueprintDirPath; $allBlueprintDirPaths):
|
||||
# True if there's a Blueprint file in the path and the path isn't
|
||||
# equal to $blueprintDirPath of the module.
|
||||
if in($allBlueprintDirPaths) and . != $blueprintDirPath then true
|
||||
# Stops checking if the current path is already the $blueprintDirPath.
|
||||
elif . == $blueprintDirPath then false
|
||||
# Usually it should not hit this logic as it stops when the path is
|
||||
# equal to $blueprintDirPath.
|
||||
elif (contains("/") | not) then false
|
||||
else (getDirPath | _isDirPathMatch($blueprintDirPath; $allBlueprintDirPaths))
|
||||
end
|
||||
;
|
||||
_isDirPathMatch($blueprintDirPath; $allBlueprintDirPaths)
|
||||
;
|
||||
|
||||
def isActionInputMatch($outputsOfModules; $allBlueprintDirPaths):
|
||||
. as $moduleVariant | .Blueprint | getDirPath as $blueprintDirPath |
|
||||
$moduleVariant | getDepOutputsOfModule($outputsOfModules) as $depOutputs |
|
||||
$moduleVariant | getActionInputs | select(in($depOutputs) | not) |
|
||||
select(startswith($blueprintDirPath)) | getDirPath |
|
||||
isDirPathMatch($blueprintDirPath; $allBlueprintDirPaths)
|
||||
;
|
||||
|
||||
getBlueprintDirPaths as $allBlueprintDirPaths |
|
||||
getNonNullActionModules as $nonNullActionModules |
|
||||
getOutputsOfModules($nonNullActionModules) as $outputsOfModules |
|
||||
[$nonNullActionModules | .[] |
|
||||
select(isActionInputMatch($outputsOfModules; $allBlueprintDirPaths)) |
|
||||
.Name] | sort_by(.) | unique
|
|
@ -0,0 +1,16 @@
|
|||
# CMD: Finds all modules whose name is equal to the name of one of its input
|
||||
# files.
|
||||
|
||||
include "library";
|
||||
|
||||
def isActionInputMatch($name; $blueprintDirPath): . as $actionInput |
|
||||
getDirPath as $inputDirPath | $actionInput | split("/") |
|
||||
last | . == $name and $inputDirPath == $blueprintDirPath
|
||||
;
|
||||
|
||||
def isActionInputsMatch($name; $blueprint): getActionInputs as $actionInputs |
|
||||
$blueprint | getDirPath as $blueprintDirPath | $actionInputs |
|
||||
isActionInputMatch($name; $blueprintDirPath)
|
||||
;
|
||||
|
||||
[.[] | select(nonNullAction) | select(isActionInputsMatch(.Name; .Blueprint)) | .Name] | sort_by(.) | unique
|
|
@ -0,0 +1,13 @@
|
|||
# CMD: Returns the modules of type $arg that have property $arg2
|
||||
|
||||
def hasPropertyWithName($a):
|
||||
map(select(.Name == $a)) |
|
||||
length |
|
||||
. > 0
|
||||
;
|
||||
|
||||
[.[] |
|
||||
select(.Type == $arg) |
|
||||
select(.Module.Android.SetProperties |
|
||||
hasPropertyWithName($arg2)) |
|
||||
.Name] | unique | sort | .[]
|
|
@ -0,0 +1,8 @@
|
|||
# CMD: Finds all modules whose input files contain the specific file type $arg.
|
||||
|
||||
include "library";
|
||||
|
||||
def isActionInputMatch($fileType): getActionInputs | split(".") | last | . == $fileType
|
||||
;
|
||||
|
||||
[.[] | select(nonNullAction) | select(isActionInputMatch($arg)) | .Name] | sort_by(.) | unique
|
|
@ -0,0 +1,7 @@
|
|||
# CMD: Returns the modules in the transitive closure of module $arg
|
||||
|
||||
include "library";
|
||||
|
||||
fullTransitiveDeps([$arg])
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# CMD: Returns the properties of module types in the transitive closure of module $arg
|
||||
|
||||
include "library";
|
||||
|
||||
[((moduleGraphNoVariants | removeSelfEdges) as $m |
|
||||
[$arg] |
|
||||
transitiveDeps($m)) as $names |
|
||||
.[] |
|
||||
select (IN(.Name; $names | .[]))] |
|
||||
group_by(.Type) |
|
||||
map({Type: .[0].Type,
|
||||
Props: map(.Module.Android.SetProperties) | flatten | map(.Name) | unique | sort }) |
|
||||
sort_by(.Type)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# CMD: Returns all modules of type $arg and all modules in their transitive closure.
|
||||
|
||||
include "library";
|
||||
|
||||
fullTransitiveDeps(modulesOfType($arg))
|
||||
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
# Applies "f" to all variation maps in modules and deps
|
||||
|
||||
def transformModule(f):
|
||||
.Variations = (.Variations | f) |
|
||||
.DependencyVariations = (.DependencyVariations | f)
|
||||
;
|
||||
|
||||
def transformModuleReferences(f):
|
||||
transformModule(f) |
|
||||
.Deps = [.Deps | .[] | transformModule(f)]
|
||||
;
|
||||
|
||||
|
||||
|
||||
# Utility functions for transforming modules
|
||||
|
||||
def deleteDependencyVariations:
|
||||
if .DependencyVariations == .Variations then del(.DependencyVariations) else . end
|
||||
;
|
||||
|
||||
|
||||
# Utility functions for transforming variation maps
|
||||
|
||||
def emptyIfNull: if . == null then {} else . end
|
||||
;
|
||||
|
||||
def flattenVariations:
|
||||
[. as $m | . | keys | sort | .[] | . + "=" + ($m[.] | tostring)] | join(", ")
|
||||
;
|
||||
|
||||
def removeLinkVariation:
|
||||
del(.link)
|
||||
;
|
||||
|
||||
def removeEmptyVariations:
|
||||
del(.[] | select(. == ""))
|
||||
;
|
||||
|
||||
# Computes the difference of two maps, returns it as a single string
|
||||
def mapDelta($outer; $inner):
|
||||
$outer | keys as $outerKeys |
|
||||
$inner | keys as $innerKeys |
|
||||
($outerKeys - $innerKeys) as $removed |
|
||||
($innerKeys - $outerKeys) as $added |
|
||||
[($removed | .[] | "-" + . + "=" + $outer[.]), ($added | .[] | "+" + . + "=" + $inner[.])] |
|
||||
join(", ")
|
||||
;
|
||||
|
||||
# Transforms the variation map of dependencies (as specified by f) to a delta
|
||||
# from the variation map of the module that depends on them
|
||||
def depDelta(f):
|
||||
f as $outer |
|
||||
(.Deps | .[] | f) |= (. | mapDelta($outer; .))
|
||||
;
|
||||
|
||||
# "filterMatchingDeps" filters deps that have different variations
|
||||
|
||||
def differentDep($od; $ov):
|
||||
(.DependencyVariations != $od or .Variations != $ov) and
|
||||
(.DependencyVariations != {} or .Variations != {})
|
||||
;
|
||||
|
||||
def filterMatchingDeps: .Variations as $ov |
|
||||
.DependencyVariations as $od |
|
||||
.Deps = [.Deps[] | select(differentDep($ov; $od))]
|
||||
;
|
||||
|
||||
|
||||
def groupDeps:
|
||||
group_by({Variations, DependencyVariations, Tag}) |
|
||||
map({
|
||||
DependencyVariations: .[0].DependencyVariations,
|
||||
Variations: .[0].Variations,
|
||||
Tag: .[0].Tag | sub(" {BaseDependencyTag:{}(?<g>.*)}"; "\(.g)"),
|
||||
Modules: map(.Name)
|
||||
} | del(if has("DependencyVariations") then .DependencyVariations else empty end))
|
||||
|
||||
;
|
||||
|
||||
# Utilities for filtering out interesting modules (deps remain untouched)
|
||||
|
||||
def onlyDeps:
|
||||
{ Name: .Name, Deps: .Deps | map(.Name) }
|
||||
;
|
||||
|
||||
def mergeDepsForSameModule:
|
||||
group_by(.Name) | map({Name: .[0].Name, Deps: map(.Deps) | flatten | unique | sort})
|
||||
;
|
||||
|
||||
def toMergeMap:
|
||||
map({key: .Name, value: .Deps}) | from_entries
|
||||
;
|
||||
|
||||
def moduleGraphNoVariants:
|
||||
map(onlyDeps) | mergeDepsForSameModule | toMergeMap
|
||||
;
|
||||
|
||||
def removeSelfEdges:
|
||||
to_entries |
|
||||
map(.key as $key | {key: .key, value: .value | [.[] | select(. != $key)]}) |
|
||||
from_entries
|
||||
;
|
||||
|
||||
def directDeps($m):
|
||||
map($m[.] // []) + [.] | flatten | unique
|
||||
;
|
||||
|
||||
def transitiveDeps($m):
|
||||
{Prev: [], Next: .} |
|
||||
until (.Prev == .Next; {Prev: .Next, Next: .Next | directDeps($m)}) |
|
||||
.Next
|
||||
;
|
||||
|
||||
def findEdge($from;$to):
|
||||
.[] | select(.Name == $from) |
|
||||
.Deps |= [.[] | select(.Name == $to)] |
|
||||
select((.Deps | length) > 0)
|
||||
;
|
||||
|
||||
def nonNullAction: .Module.Actions != null
|
||||
;
|
||||
|
||||
def getActionInputs: .Module.Actions | .[] |
|
||||
.Inputs | if . == null then [] else . end | .[]
|
||||
;
|
||||
|
||||
# Gets the directory path by the given file path.
|
||||
def getDirPath: sub("(?<p>.*)\\/.*"; "\(.p)")
|
||||
;
|
||||
|
||||
# Returns the names of modules of type $arg
|
||||
def modulesOfType($arg):
|
||||
[.[] | select(.Type == $arg) | .Name] | unique
|
||||
;
|
||||
|
||||
# Returns the modules in the transitive closure of $arg.
|
||||
# $arg must be an array of modules names
|
||||
def fullTransitiveDeps($arg):
|
||||
[((moduleGraphNoVariants | removeSelfEdges) as $m |
|
||||
$arg |
|
||||
transitiveDeps($m)) as $names |
|
||||
.[] |
|
||||
select (IN(.Name; $names | .[]))] |
|
||||
sort_by(.Name)
|
||||
;
|
|
@ -0,0 +1,15 @@
|
|||
# CMD: Returns a summary of the module types present on the input
|
||||
|
||||
include "library";
|
||||
|
||||
def moduleTypeStats($arg):
|
||||
group_by(.Type) |
|
||||
map({
|
||||
Type: .[0].Type,
|
||||
Count: map(.Name) | unique | length,
|
||||
VariantCount: length,
|
||||
}) |
|
||||
sort_by(.Count)
|
||||
;
|
||||
|
||||
moduleTypeStats($arg)
|
|
@ -0,0 +1,5 @@
|
|||
# CMD: Returns the names of modules of type $arg
|
||||
|
||||
include "library";
|
||||
|
||||
modulesOfType($arg)
|
|
@ -0,0 +1,15 @@
|
|||
# CMD: Prints the module named $arg in a slightly more concise way
|
||||
|
||||
include "library";
|
||||
|
||||
def printModule($mod):
|
||||
.[] | select(.Name == $mod) |
|
||||
transformModuleReferences(emptyIfNull | removeLinkVariation | removeEmptyVariations) |
|
||||
depDelta(.Variations) | depDelta(.DependencyVariations) |
|
||||
transformModule(flattenVariations) |
|
||||
deleteDependencyVariations |
|
||||
.Deps |= map(deleteDependencyVariations) |
|
||||
.Deps |= groupDeps
|
||||
;
|
||||
|
||||
printModule($arg)
|
|
@ -0,0 +1,7 @@
|
|||
# CMD: Returns the names of properties used by $arg
|
||||
|
||||
[.[] |
|
||||
select (.Name == $arg) |
|
||||
.Module.Android.SetProperties |
|
||||
map(.Name)] |
|
||||
flatten | unique | sort
|
|
@ -0,0 +1,54 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
LIBDIR="$(dirname "$(readlink -f "$0")")"
|
||||
|
||||
function print_usage() {
|
||||
echo "Usage: query.sh [-C] <command> <graph JSON> [argument]" 1>&2
|
||||
echo " -C: colorized output" 1>&2
|
||||
echo
|
||||
echo "Commands":
|
||||
for jq in "$LIBDIR"/*.jq; do
|
||||
if ! grep -q "^# CMD:" "$jq"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
local CMD="$(echo $(basename "$jq") | sed 's/\..*$//')"
|
||||
echo " $CMD": $(cat "$jq" | grep "^# CMD:" | head -n 1 | sed 's/^# CMD://')
|
||||
done
|
||||
exit 1
|
||||
}
|
||||
|
||||
JQARGS=""
|
||||
|
||||
while getopts "C" arg; do
|
||||
case "$arg" in
|
||||
C)
|
||||
JQARGS="$JQARGS -C"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
print_usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$#" -lt 2 ]]; then
|
||||
print_usage
|
||||
fi
|
||||
|
||||
COMMAND="$1"
|
||||
GRAPH="$2"
|
||||
|
||||
if [[ "$#" -gt 2 ]]; then
|
||||
ARG="$3"
|
||||
else
|
||||
ARG=""
|
||||
fi
|
||||
|
||||
if [[ "$#" -gt 3 ]]; then
|
||||
ARG2="$4"
|
||||
else
|
||||
ARG2=""
|
||||
fi
|
||||
|
||||
jq $JQARGS -L "$LIBDIR" -f "$LIBDIR/$COMMAND".jq "$GRAPH" --arg arg "$ARG" --arg arg2 "$ARG2"
|
|
@ -0,0 +1,7 @@
|
|||
# CMD: Returns the names of the transitive dependencies of the module named $arg
|
||||
|
||||
include "library";
|
||||
|
||||
(moduleGraphNoVariants | removeSelfEdges) as $m |
|
||||
[$arg] |
|
||||
transitiveDeps($m)
|
|
@ -0,0 +1,8 @@
|
|||
# CMD: Prints the set of variations and their values used in the input
|
||||
|
||||
[[.[] | .Variations | select(. != null) | to_entries] |
|
||||
flatten |
|
||||
group_by(.key) |
|
||||
.[] |
|
||||
{key: .[0].key, value: map(.value) | unique}] |
|
||||
from_entries
|
|
@ -0,0 +1,16 @@
|
|||
# CMD: Groups outgoing dependency edges by the differences in variants
|
||||
|
||||
include "library";
|
||||
|
||||
# This filters out modules with "interesting" deps
|
||||
def filterVariantTransitions:
|
||||
.[] | transformModuleReferences(emptyIfNull | removeLinkVariation | removeEmptyVariations) |
|
||||
filterMatchingDeps | select(.Deps | length > 0) |
|
||||
depDelta(.Variations) | depDelta(.DependencyVariations) |
|
||||
transformModule(flattenVariations) |
|
||||
deleteDependencyVariations |
|
||||
.Deps |= map(deleteDependencyVariations) |
|
||||
.Deps |= groupDeps
|
||||
;
|
||||
|
||||
[filterVariantTransitions] | sort_by(.Name) | sort_by(.Type) | .[]
|
|
@ -0,0 +1,10 @@
|
|||
import %workspace%/build/bazel/common.bazelrc
|
||||
|
||||
build --host_platform //build/bazel/platforms:linux_x86_64
|
||||
|
||||
# Workaround JVM segfault issue as suggested at
|
||||
# https://github.com/bazelbuild/bazel/issues/3236#issuecomment-310656266
|
||||
build --sandbox_tmpfs_path=/tmp/
|
||||
|
||||
# Create a build number that will be injected later.
|
||||
build --workspace_status_command=build/bazel/scripts/gen_build_number.sh
|
|
@ -0,0 +1,45 @@
|
|||
#! /bin/bash
|
||||
# Run given scripted change and commit the changes.
|
||||
#
|
||||
# Assumes that the current directory is the top-level directory of
|
||||
# the Android source code, created with 'repo init', and that 'repo'
|
||||
# tool is on the path.
|
||||
# For each of the given repo git repositories:
|
||||
# 1. Checks there are neither modified not untracked files in it.
|
||||
# 2. Runs the given script, which is supposed to change some files
|
||||
# 3. Creates a development branch if necessary
|
||||
# 4. Commits changed files. The commit message is extracted from the
|
||||
# script and contains all the lines in it starting with ##CL
|
||||
#
|
||||
# As an example, running
|
||||
# build/bazel/mk2rbc/apply_scripted_change.sh build/bazel/mk2rbc/replace_is_board_platform.sh hardware/qcom/media
|
||||
# replaces the old is-board-platform calls with the new is-board-platform2 calls.
|
||||
|
||||
set -eu
|
||||
|
||||
function die() { format=$1; shift; printf "$format\n" $@; exit 1; }
|
||||
function usage() { die "Usage: %s script git-repo ..." ${0##*/}; }
|
||||
|
||||
(($#>=2)) || usage
|
||||
declare -r script=$(realpath $1); shift
|
||||
rc=0
|
||||
|
||||
[[ -x $script ]] || die "%s is not an executable script" $script
|
||||
declare -r bugid="$(sed -nr 's/^##CL (Bug:|Fixes:) +([0-9]+)$/\2/p' $script)"
|
||||
[[ -n "$bugid" ]] || die "$script contains neither '##CL Bug: ' nor '##CL Fixes: 'tag"
|
||||
|
||||
|
||||
for gr in $@; do
|
||||
[[ -d $gr/.git ]] || { echo $gr is not a Git directory; rc=1; continue; }
|
||||
out=$(git -C $gr status --porcelain --untracked-files=no) || { die "so skipping $gr because of the above"; rc=1; continue; }
|
||||
[[ -z "$out" ]] || { echo $gr contains uncommitted changes:; echo "$out" >&2; rc=1; continue; }
|
||||
(cd $gr && $script)
|
||||
modified="$(git -C $gr status --porcelain | sed -nr 's/^ M (.*)/\1/p')"
|
||||
[[ -n "$modified" ]] || { echo no files changed in $gr; continue; }
|
||||
[[ -z "$(repo status -q $gr 2>/dev/null)" ]] || repo start b$bugid $gr
|
||||
git -C $gr add $modified
|
||||
git -C $gr commit -q \
|
||||
-F <(sed -nr 's/^##CL *//p' $script; echo -e '\nThis change has been generated by the following script:\n\n```'; grep -vP '^##CL' $script; echo '```')
|
||||
done
|
||||
|
||||
exit $rc
|
|
@ -0,0 +1,11 @@
|
|||
#! /bin/bash
|
||||
##CL Provide location hint for the dynamically calculated paths.
|
||||
##CL
|
||||
##CL For the paths using QC_PROP_PATH or QC_PROP_ROOT
|
||||
##CL Bug: 203582721
|
||||
##CL Test: treehugger
|
||||
declare -r files="$(grep -rlP '^ *(\$\(call inherit-product|-?include).*\$\(QC_PROP_(PATH|ROOT)\)' --include 'BoardConfig*.mk')"
|
||||
[[ -z "$files" ]] || sed -i -r -f <(cat <<"EOF"
|
||||
/^ *(\$\(call inherit-product|-?include).*\$\(QC_PROP_(PATH|ROOT)\)/i#RBC# include_top vendor/qcom
|
||||
EOF
|
||||
) $files
|
|
@ -0,0 +1,31 @@
|
|||
#! /bin/bash
|
||||
##CL Replace is-board-platform[-in-list] with is-board-platform[-in-list]2
|
||||
##CL
|
||||
##CL The regular is-board-platform[-in-list] functions are defined in
|
||||
##CL some product/board configuration makefiles, and sometimes also
|
||||
##CL used in Android.mk files. When the product/board configuration
|
||||
##CL is converted to starlark, the functions will no longer be defined
|
||||
##CL for the Android.mk files to use. Switch to using a version of
|
||||
##CL these functions that is defined inside the core build system
|
||||
##CL makefiles, so it will still be defined when the configuration
|
||||
##CL is in Starlark.
|
||||
##CL
|
||||
##CL The new function returns either an empty string or the matching
|
||||
##CL platform, while the old one returned either an empty string or true.
|
||||
##CL So now if statements are compared against an empty string instead of
|
||||
##CL true.
|
||||
##CL
|
||||
##CL Bug: 201477826
|
||||
##CL Test: treehugger
|
||||
declare -r files="$(grep -rlP '^[^#]*call +is-board-platform' --include '*.mk' --exclude 'utils_test.mk' --exclude 'utils_sample_usage.mk')"
|
||||
[[ -z "$files" ]] || sed -i -r -f <(cat <<"EOF"
|
||||
s/ifeq +\(\$\(call is-board-platform,(.*)\), *true\)/ifneq (,$(call is-board-platform2,\1))/
|
||||
s/ifeq +\(\$\(call is-board-platform,(.*)\), *\)/ifeq (,$(call is-board-platform2,\1))/
|
||||
s/ifneq +\(\$\(call is-board-platform,(.*)\), *true\)/ifeq (,$(call is-board-platform2,\1))/
|
||||
s/ifeq +\(\$\(call is-board-platform-in-list,(.*)\), *true\)/ifneq (,$(call is-board-platform-in-list2,\1))/
|
||||
s/ifeq +\(\$\(call is-board-platform-in-list,(.*)\), *\)/ifeq (,$(call is-board-platform-in-list2,\1))/
|
||||
s/ifeq +\(\$\(call is-board-platform-in-list,(.*)\), *false\)/ifeq (,T) # TODO: remove useless check/
|
||||
s/ifneq +\(\$\(call is-board-platform-in-list,(.*)\), *true\)/ifeq (,$(call is-board-platform-in-list2,\1))/
|
||||
s/\$\(call is-board-platform,(.*)\)/$(call is-board-platform2,\1)/
|
||||
EOF
|
||||
) $files
|
|
@ -0,0 +1,16 @@
|
|||
#! /bin/bash
|
||||
##CL Replace is-platform-sdk-version-at-least calls with checking IS_AT_LEAST_xxx.
|
||||
##CL
|
||||
##CL Bug: 201477826
|
||||
##CL Test: treehugger
|
||||
declare -r files="$(grep -rlP '^[^#]*call +is-platform-sdk-version-at-least' --include '*.mk')"
|
||||
[[ -z "$files" ]] || sed -i -r -f <(cat <<"EOF"
|
||||
s/^([^#]*ifn?eq) +\(\$\(call is-platform-sdk-version-at-least, *(16|17|18|19|20|21|22|23|24|25)\), *true\)/\1 \(T,T\) \# TODO: Obsolete, please remove/
|
||||
s/^([^#]*)if(n?)eq +\(\$\(call is-platform-sdk-version-at-least, *26\), *true\)/\1if\2def IS_AT_LEAST_OPR1/
|
||||
s/^([^#]*)if(n?)eq +\(\$\(call is-platform-sdk-version-at-least, *27\), *true\)/\1if\2def IS_AT_LEAST_OPM1/
|
||||
s/^([^#]*)if(n?)eq +\(\$\(call is-platform-sdk-version-at-least, *28\), *true\)/\1if\2def IS_AT_LEAST_PPR1/
|
||||
s/^([^#]*)if(n?)eq +\(\$\(call is-platform-sdk-version-at-least, *29\), *true\)/\1if\2def IS_AT_LEAST_QP1A/
|
||||
s/^([^#]*)if(n?)eq +\(\$\(call is-platform-sdk-version-at-least, *30\), *true\)/\1if\2def IS_AT_LEAST_RP1A/
|
||||
s/^([^#]*)if(n?)eq +\(\$\(call is-platform-sdk-version-at-least, *31\), *true\)/\1if\2def IS_AT_LEAST_SP1A/
|
||||
EOF
|
||||
) $files
|
|
@ -0,0 +1,11 @@
|
|||
#! /bin/bash
|
||||
##CL Replace is-vendor-board-platform with is-vendor-board-qcom.
|
||||
##CL
|
||||
##CL Bug: 201477826
|
||||
##CL Test: treehugger
|
||||
declare -r files="$(grep -rlP '^[^#]*call +is-vendor-board-platform' --include '*.mk')"
|
||||
[[ -z "$files" ]] || sed -i -r -f <(cat <<"EOF"
|
||||
s/ifeq \(\$\(call is-vendor-board-platform,QCOM\),true\)/ifneq (,$(call is-vendor-board-qcom))/
|
||||
s/ifneq \(\$\(call is-vendor-board-platform,QCOM\),true\)/ifeq (,$(call is-vendor-board-qcom))/
|
||||
EOF
|
||||
) $files
|
|
@ -0,0 +1,135 @@
|
|||
# Common target platforms for Android Platform builds.
|
||||
#
|
||||
# Platforms represent distinct hardware environments:
|
||||
#
|
||||
# - CPU architecture
|
||||
# - Hardware capabilities
|
||||
# - Firmware differences
|
||||
#
|
||||
# Platforms do NOT represent different software packages, that is the
|
||||
# reposibility of the top-level targets being built.
|
||||
#
|
||||
# These model after the arch and OS definitions in build/soong/android/arch.go.
|
||||
|
||||
load("@soong_injection//product_config:product_variables.bzl", "product_vars")
|
||||
load("//build/bazel/platforms:product_variables/product_platform.bzl", "android_platform", "product_variable_config")
|
||||
load("//build/bazel/platforms/arch/variants:constants.bzl", "constants")
|
||||
load(
|
||||
"//prebuilts/clang/host/linux-x86:cc_toolchain_constants.bzl",
|
||||
"arch_to_variants",
|
||||
"variant_constraints",
|
||||
"variant_name",
|
||||
)
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
product_variable_config(
|
||||
name = "android_target",
|
||||
product_config_vars = product_vars,
|
||||
)
|
||||
|
||||
# Linux is the OS
|
||||
# for the Linux kernel plus the glibc runtime.
|
||||
android_platform(
|
||||
name = "linux_x86",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86",
|
||||
"//build/bazel/platforms/os:linux",
|
||||
],
|
||||
product = ":android_target",
|
||||
)
|
||||
|
||||
android_platform(
|
||||
name = "linux_x86_64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:linux",
|
||||
],
|
||||
product = ":android_target",
|
||||
)
|
||||
|
||||
# linux_bionic is the OS for the Linux kernel plus the Bionic libc runtime, but
|
||||
# without the rest of Android.
|
||||
android_platform(
|
||||
name = "linux_bionic_arm64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:arm64",
|
||||
"//build/bazel/platforms/os:linux_bionic",
|
||||
],
|
||||
product = ":android_target",
|
||||
)
|
||||
|
||||
android_platform(
|
||||
name = "linux_bionic_x86_64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:linux_bionic",
|
||||
],
|
||||
product = ":android_target",
|
||||
)
|
||||
|
||||
# Darwin is the OS for MacOS host machines.
|
||||
android_platform(
|
||||
name = "darwin_arm64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:arm64",
|
||||
"//build/bazel/platforms/os:darwin",
|
||||
],
|
||||
product = ":android_target",
|
||||
)
|
||||
|
||||
android_platform(
|
||||
name = "darwin_x86_64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:darwin",
|
||||
],
|
||||
product = ":android_target",
|
||||
)
|
||||
|
||||
# Windows is the OS for Windows host machines.
|
||||
android_platform(
|
||||
name = "windows_x86",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86",
|
||||
"//build/bazel/platforms/os:windows",
|
||||
],
|
||||
product = ":android_target",
|
||||
)
|
||||
|
||||
android_platform(
|
||||
name = "windows_x86_64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:windows",
|
||||
],
|
||||
product = ":android_target",
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "android_arm",
|
||||
actual = ":android_arm_armv7-a-neon", # default to armv7-a-neon
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "android_arm64",
|
||||
actual = ":android_arm64_armv8-a", # default to armv8-a
|
||||
)
|
||||
|
||||
[
|
||||
[
|
||||
android_platform(
|
||||
name = "android_" + arch + variant_name(variant),
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:" + arch,
|
||||
"//build/bazel/platforms/os:android",
|
||||
] + variant_constraints(
|
||||
variant,
|
||||
constants.AndroidArchToVariantToFeatures[arch],
|
||||
),
|
||||
product = ":android_target",
|
||||
)
|
||||
for variant in variants
|
||||
]
|
||||
for arch, variants in arch_to_variants.items()
|
||||
]
|
|
@ -0,0 +1,29 @@
|
|||
# Standard cpu name constraint_setting and constraint_values
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "arm",
|
||||
constraint_setting = "@platforms//cpu:cpu",
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "arm64",
|
||||
constraint_setting = "@platforms//cpu:cpu",
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "x86",
|
||||
constraint_setting = "@platforms//cpu:cpu",
|
||||
)
|
||||
|
||||
# Alias to the local_jdk's toolchain constraint to make local_jdk resolve
|
||||
# correctly with --tool_java_runtime_version=local_jdk and the checked-in JDK.
|
||||
alias(
|
||||
name = "x86_64",
|
||||
actual = "@platforms//cpu:x86_64"
|
||||
)
|
|
@ -0,0 +1,89 @@
|
|||
# Cpu/Arch Variants and features
|
||||
|
||||
load("//build/bazel/product_variables:constants.bzl", _product_variable_constants = "constants")
|
||||
load(":constants.bzl", "constants")
|
||||
|
||||
constraint_setting(
|
||||
name = "arch_variant_constraint",
|
||||
)
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
[
|
||||
constraint_value(
|
||||
name = arch_variant,
|
||||
constraint_setting = "arch_variant_constraint",
|
||||
)
|
||||
for arch_variant in constants.AvailableArchVariants
|
||||
]
|
||||
|
||||
[
|
||||
[
|
||||
config_setting(
|
||||
name = variant + "-" + arch,
|
||||
constraint_values = [
|
||||
_product_variable_constants.ArchVariantToConstraints[arch],
|
||||
":" + variant,
|
||||
],
|
||||
)
|
||||
for variant in variants
|
||||
]
|
||||
for arch, variants in constants.ArchToVariants.items()
|
||||
]
|
||||
|
||||
constraint_setting(
|
||||
name = "cpu_variant_constraint",
|
||||
)
|
||||
|
||||
[
|
||||
constraint_value(
|
||||
name = cpu_variant,
|
||||
constraint_setting = "cpu_variant_constraint",
|
||||
)
|
||||
for cpu_variant in constants.AvailableCpuVariants
|
||||
]
|
||||
|
||||
[
|
||||
[
|
||||
config_setting(
|
||||
name = variant + "-" + arch,
|
||||
constraint_values = [
|
||||
_product_variable_constants.ArchVariantToConstraints[arch],
|
||||
":" + variant,
|
||||
],
|
||||
)
|
||||
for variant in variants
|
||||
]
|
||||
for arch, variants in constants.CpuToVariants.items()
|
||||
]
|
||||
|
||||
[
|
||||
(
|
||||
constraint_setting(
|
||||
name = "arch_feature_constraint_" + arch_feature,
|
||||
),
|
||||
constraint_value(
|
||||
name = arch_feature,
|
||||
constraint_setting = "arch_feature_constraint_" + arch_feature,
|
||||
),
|
||||
)
|
||||
for arch_feature in constants.AvailableArchFeatures
|
||||
]
|
||||
|
||||
[
|
||||
[
|
||||
config_setting(
|
||||
name = feature + "-" + arch,
|
||||
constraint_values = [
|
||||
_product_variable_constants.ArchVariantToConstraints[arch],
|
||||
":" + feature,
|
||||
],
|
||||
)
|
||||
for feature in features
|
||||
]
|
||||
for arch, features in constants.ArchToFeatures.items()
|
||||
]
|
|
@ -0,0 +1,44 @@
|
|||
"""Constants for arch/cpu variants/features."""
|
||||
|
||||
# Copyright (C) 2022 The Android Open Source Project
|
||||
#
|
||||
# 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.
|
||||
|
||||
load(
|
||||
"@soong_injection//product_config:arch_configuration.bzl",
|
||||
_android_arch_feature_for_arch_variant = "android_arch_feature_for_arch_variants",
|
||||
_arch_to_cpu_variants = "arch_to_cpu_variants",
|
||||
_arch_to_features = "arch_to_features",
|
||||
_arch_to_variants = "arch_to_variants",
|
||||
)
|
||||
|
||||
def _flatten_string_list_dict_to_set(string_list_dict):
|
||||
ret = {}
|
||||
for l in string_list_dict.values():
|
||||
for i in l:
|
||||
ret[i] = True
|
||||
return ret
|
||||
|
||||
_arch_variants = _flatten_string_list_dict_to_set(_arch_to_variants)
|
||||
_cpu_variants = _flatten_string_list_dict_to_set(_arch_to_cpu_variants)
|
||||
_arch_features = _flatten_string_list_dict_to_set(_arch_to_features)
|
||||
|
||||
constants = struct(
|
||||
AvailableArchVariants = _arch_variants,
|
||||
AvailableCpuVariants = _cpu_variants,
|
||||
AvailableArchFeatures = _arch_features,
|
||||
ArchToVariants = _arch_to_variants,
|
||||
CpuToVariants = _arch_to_cpu_variants,
|
||||
ArchToFeatures = _arch_to_features,
|
||||
AndroidArchToVariantToFeatures = _android_arch_feature_for_arch_variant,
|
||||
)
|
|
@ -0,0 +1,68 @@
|
|||
# Standard constraint_setting and constraint_values to be used in platforms.
|
||||
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "android",
|
||||
constraint_setting = "@platforms//os:os",
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "android_config_setting",
|
||||
constraint_values = [
|
||||
":android",
|
||||
],
|
||||
)
|
||||
|
||||
# Alias to the local_jdk's toolchain constraint to make local_jdk resolve
|
||||
# correctly with --tool_java_runtime_version=local_jdk and the checked-in JDK.
|
||||
alias(
|
||||
name = "linux",
|
||||
actual = "@platforms//os:linux",
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "linux_glibc",
|
||||
actual = "@platforms//os:linux",
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "linux_musl",
|
||||
constraint_setting = "@platforms//os:os",
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "linux_bionic",
|
||||
constraint_setting = "@platforms//os:os",
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "linux_bionic_config_setting",
|
||||
constraint_values = [
|
||||
":linux_bionic",
|
||||
],
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "windows",
|
||||
constraint_setting = "@platforms//os:os",
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "darwin",
|
||||
constraint_setting = "@platforms//os:os",
|
||||
)
|
||||
|
||||
selects.config_setting_group(
|
||||
name = "bionic",
|
||||
match_any = [
|
||||
":android_config_setting",
|
||||
":linux_bionic_config_setting",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,111 @@
|
|||
config_setting(
|
||||
name = "android_arm",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:arm",
|
||||
"//build/bazel/platforms/os:android",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "android_arm64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:arm64",
|
||||
"//build/bazel/platforms/os:android",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "android_x86",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86",
|
||||
"//build/bazel/platforms/os:android",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "android_x86_64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:android",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "darwin_arm64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:arm64",
|
||||
"//build/bazel/platforms/os:darwin",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "darwin_x86_64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:darwin",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "linux_glibc_x86",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86",
|
||||
"//build/bazel/platforms/os:linux_glibc",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "linux_glibc_x86_64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:linux_glibc",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "linux_bionic_arm64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:arm64",
|
||||
"//build/bazel/platforms/os:linux_bionic",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "linux_bionic_x86_64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:linux_bionic",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "linux_musl_x86",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86",
|
||||
"//build/bazel/platforms/os:linux_musl",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "linux_musl_x86_64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:linux_musl",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "windows_x86",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86",
|
||||
"//build/bazel/platforms/os:windows",
|
||||
],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "windows_x86_64",
|
||||
constraint_values = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:windows",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,148 @@
|
|||
"""Parallels variable.go to provide variables and create a platform based on converted config."""
|
||||
|
||||
load("//build/bazel/product_variables:constants.bzl", "constants")
|
||||
load("//prebuilts/clang/host/linux-x86:cc_toolchain_constants.bzl", "variant_name")
|
||||
|
||||
def _product_variables_providing_rule_impl(ctx):
|
||||
return [
|
||||
platform_common.TemplateVariableInfo(ctx.attr.product_vars),
|
||||
]
|
||||
|
||||
# Provides product variables for templated string replacement.
|
||||
product_variables_providing_rule = rule(
|
||||
implementation = _product_variables_providing_rule_impl,
|
||||
attrs = {
|
||||
"product_vars": attr.string_dict(),
|
||||
},
|
||||
)
|
||||
|
||||
_arch_os_only_suffix = "_arch_os"
|
||||
_product_only_suffix = "_product"
|
||||
|
||||
def add_providing_var(providing_vars, typ, var, value):
|
||||
if typ == "bool":
|
||||
providing_vars[var] = "1" if value else "0"
|
||||
elif typ == "list":
|
||||
providing_vars[var] = ",".join(value)
|
||||
elif typ == "int":
|
||||
providing_vars[var] = str(value)
|
||||
elif typ == "string":
|
||||
providing_vars[var] = value
|
||||
|
||||
def product_variable_config(name, product_config_vars):
|
||||
constraints = []
|
||||
|
||||
local_vars = dict(product_config_vars)
|
||||
|
||||
# Native_coverage is not set within soong.variables, but is hardcoded
|
||||
# within config.go NewConfig
|
||||
local_vars["Native_coverage"] = (
|
||||
local_vars.get("ClangCoverage", False) or
|
||||
local_vars.get("GcovCoverage", False)
|
||||
)
|
||||
|
||||
providing_vars = {}
|
||||
|
||||
# Generate constraints for Soong config variables (bool, value, string typed).
|
||||
vendor_vars = local_vars.pop("VendorVars", default = {})
|
||||
for (namespace, variables) in vendor_vars.items():
|
||||
for (var, value) in variables.items():
|
||||
# All vendor vars are Starlark string-typed, even though they may be
|
||||
# boxed bools/strings/arbitrary printf'd values, like numbers, so
|
||||
# we'll need to do some translation work here by referring to
|
||||
# soong_injection's generated data.
|
||||
|
||||
if value == "":
|
||||
# Variable is not set so skip adding this as a constraint.
|
||||
continue
|
||||
|
||||
# Create the identifier for the constraint var (or select key)
|
||||
config_var = namespace + "__" + var
|
||||
|
||||
# List of all soong_config_module_type variables.
|
||||
if not config_var in constants.SoongConfigVariables:
|
||||
continue
|
||||
|
||||
# Normalize all constraint vars (i.e. select keys) to be lowercased.
|
||||
constraint_var = config_var.lower()
|
||||
|
||||
if config_var in constants.SoongConfigBoolVariables:
|
||||
constraints.append("//build/bazel/product_variables:" + constraint_var)
|
||||
elif config_var in constants.SoongConfigStringVariables:
|
||||
# The string value is part of the the select key.
|
||||
constraints.append("//build/bazel/product_variables:" + constraint_var + "__" + value.lower())
|
||||
elif config_var in constants.SoongConfigValueVariables:
|
||||
# For value variables, providing_vars add support for substituting
|
||||
# the value using TemplateVariableInfo.
|
||||
constraints.append("//build/bazel/product_variables:" + constraint_var)
|
||||
add_providing_var(providing_vars, "string", constraint_var, value)
|
||||
|
||||
for (var, value) in local_vars.items():
|
||||
# TODO(b/187323817): determine how to handle remaining product
|
||||
# variables not used in product_variables
|
||||
constraint_var = var.lower()
|
||||
if not constants.ProductVariables.get(constraint_var):
|
||||
continue
|
||||
|
||||
# variable.go excludes nil values
|
||||
add_constraint = (value != None)
|
||||
add_providing_var(providing_vars, type(value), var, value)
|
||||
if type(value) == "bool":
|
||||
# variable.go special cases bools
|
||||
add_constraint = value
|
||||
|
||||
if add_constraint:
|
||||
constraints.append("//build/bazel/product_variables:" + constraint_var)
|
||||
|
||||
native.platform(
|
||||
name = name + _product_only_suffix,
|
||||
constraint_values = constraints,
|
||||
)
|
||||
|
||||
arch = local_vars.get("DeviceArch")
|
||||
arch_variant = local_vars.get("DeviceArchVariant")
|
||||
cpu_variant = local_vars.get("DeviceCpuVariant")
|
||||
|
||||
os = "android"
|
||||
|
||||
native.alias(
|
||||
name = name,
|
||||
actual = "{os}_{arch}{variant}".format(os = os, arch = arch, variant = _variant_name(arch, arch_variant, cpu_variant)),
|
||||
)
|
||||
|
||||
arch = local_vars.get("DeviceSecondaryArch")
|
||||
arch_variant = local_vars.get("DeviceSecondaryArchVariant")
|
||||
cpu_variant = local_vars.get("DeviceSecondaryCpuVariant")
|
||||
|
||||
if arch:
|
||||
native.alias(
|
||||
name = name + "_secondary",
|
||||
actual = "{os}_{arch}{variant}".format(os = os, arch = arch, variant = _variant_name(arch, arch_variant, cpu_variant)),
|
||||
)
|
||||
|
||||
product_variables_providing_rule(
|
||||
name = name + "_product_vars",
|
||||
product_vars = providing_vars,
|
||||
)
|
||||
|
||||
def _is_variant_default(arch, variant):
|
||||
return variant == None or variant in (arch, "generic")
|
||||
|
||||
def _variant_name(arch, arch_variant, cpu_variant):
|
||||
if _is_variant_default(arch, arch_variant):
|
||||
arch_variant = ""
|
||||
if _is_variant_default(arch, cpu_variant):
|
||||
cpu_variant = ""
|
||||
variant = struct(
|
||||
arch_variant = arch_variant,
|
||||
cpu_variant = cpu_variant,
|
||||
)
|
||||
return variant_name(variant)
|
||||
|
||||
def android_platform(name = None, constraint_values = [], product = None):
|
||||
""" android_platform creates a platform with the specified constraint_values and product constraints."""
|
||||
native.platform(
|
||||
name = name,
|
||||
constraint_values = constraint_values,
|
||||
parents = [product + _product_only_suffix],
|
||||
)
|
|
@ -0,0 +1,47 @@
|
|||
# Copyright (C) 2022 The Android Open Source Project
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Utilities for rule implementations to interact with platform definitions."""
|
||||
|
||||
# Merge ARCH_CONSTRAINT_ATTRS with the rule attrs to use get_arch(ctx).
|
||||
ARCH_CONSTRAINT_ATTRS = {
|
||||
"_x86_constraint": attr.label(default = Label("//build/bazel/platforms/arch:x86")),
|
||||
"_x86_64_constraint": attr.label(default = Label("//build/bazel/platforms/arch:x86_64")),
|
||||
"_arm_constraint": attr.label(default = Label("//build/bazel/platforms/arch:arm")),
|
||||
"_arm64_constraint": attr.label(default = Label("//build/bazel/platforms/arch:arm64")),
|
||||
}
|
||||
|
||||
# get_arch takes a rule context with ARCH_CONSTRAINT_ATTRS and returns the string representation
|
||||
# of the target platform by executing the target_platform_has_constraint boilerplate.
|
||||
def get_arch(ctx):
|
||||
if not hasattr(ctx.attr, "_x86_constraint") or \
|
||||
not hasattr(ctx.attr, "_x86_64_constraint") or \
|
||||
not hasattr(ctx.attr, "_arm_constraint") or \
|
||||
not hasattr(ctx.attr, "_arm64_constraint"):
|
||||
fail("Could not get the target architecture of this rule due to missing constraint attrs.",
|
||||
"Have you merged ARCH_CONSTRAINT_ATTRS into this rule's attributes?")
|
||||
|
||||
x86_constraint = ctx.attr._x86_constraint[platform_common.ConstraintValueInfo]
|
||||
x86_64_constraint = ctx.attr._x86_64_constraint[platform_common.ConstraintValueInfo]
|
||||
arm_constraint = ctx.attr._arm_constraint[platform_common.ConstraintValueInfo]
|
||||
arm64_constraint = ctx.attr._arm64_constraint[platform_common.ConstraintValueInfo]
|
||||
|
||||
if ctx.target_platform_has_constraint(x86_constraint):
|
||||
return "x86"
|
||||
elif ctx.target_platform_has_constraint(x86_64_constraint):
|
||||
return "x86_64"
|
||||
elif ctx.target_platform_has_constraint(arm_constraint):
|
||||
return "arm"
|
||||
elif ctx.target_platform_has_constraint(arm64_constraint):
|
||||
return "arm64"
|
|
@ -0,0 +1,78 @@
|
|||
"""Constraints corresponding to product variables."""
|
||||
|
||||
load(":constants.bzl", "constants")
|
||||
load(":settings.bzl", "soong_config_variables")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
# Unlike product config variables below, these are dynamically generated from
|
||||
# Soong, since the list of config variables are dynamically defined in
|
||||
# Android.bp files and not hardcoded into Soong.
|
||||
soong_config_variables(
|
||||
bool_vars = constants.SoongConfigBoolVariables,
|
||||
string_vars = constants.SoongConfigStringVariables,
|
||||
value_vars = constants.SoongConfigValueVariables,
|
||||
)
|
||||
|
||||
# Generate one constraint_value for each product_variable
|
||||
# The constraint_value for <var> can be within a select() to specify an
|
||||
# attribute value for the same conditions product_variable.<var>, for most
|
||||
# cases, that is when the value of <var> is true. For example,
|
||||
#
|
||||
# product_variables: {
|
||||
# debuggable: {
|
||||
# cflags: ["debug_flag1", "debug_flag2"],
|
||||
# },
|
||||
# }
|
||||
#
|
||||
# translates into:
|
||||
#
|
||||
# cflags = select({
|
||||
# "//build/bazel/product_variables:debuggable": ["debug_flag1", "debug_flag2"],
|
||||
# "//conditions:default": [],
|
||||
# }),
|
||||
[
|
||||
(
|
||||
constraint_setting(name = product_variable + "_constraint"),
|
||||
constraint_value(
|
||||
name = product_variable,
|
||||
constraint_setting = product_variable + "_constraint",
|
||||
),
|
||||
)
|
||||
for product_variable in constants.ProductVariables
|
||||
]
|
||||
|
||||
# Caution: do not use these arch-variant product variables directly.
|
||||
# If you have a complex combination of product variable and architecture/os/etc,
|
||||
# prefer instead to craft an appropriate configuration in your BUILD file.
|
||||
# See: https://docs.bazel.build/versions/master/configurable-attributes.html
|
||||
# Within bp2build, :safestack-android should be used when an attribute value is
|
||||
# conditional on both safestack:true and the os is android.
|
||||
#
|
||||
# e.g.
|
||||
# target: {
|
||||
# android: {
|
||||
# product_variables: {
|
||||
# safestack: {
|
||||
# cflags: ["-Dsafestack-android"],
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
#
|
||||
# would translate to:
|
||||
#
|
||||
# cflags = select({
|
||||
# "//build/bazel/product_variables:safestack-android": ["-Dsafestack-android"],
|
||||
# "//conditions:default": [],
|
||||
# }),
|
||||
[
|
||||
[config_setting(
|
||||
name = product_variable + "-" + variant,
|
||||
constraint_values = [
|
||||
":" + product_variable,
|
||||
variantConstraint,
|
||||
],
|
||||
) for variant, variantConstraint in constants.ArchVariantToConstraints.items()]
|
||||
for product_variable in constants.ArchVariantProductVariables
|
||||
]
|
|
@ -0,0 +1,49 @@
|
|||
"""Constants for product variables based on information in variable.go"""
|
||||
|
||||
load(
|
||||
"@soong_injection//product_config:soong_config_variables.bzl",
|
||||
_soong_config_bool_variables = "soong_config_bool_variables",
|
||||
_soong_config_string_variables = "soong_config_string_variables",
|
||||
_soong_config_value_variables = "soong_config_value_variables",
|
||||
)
|
||||
load(
|
||||
"@soong_injection//product_config:product_variables.bzl",
|
||||
_arch_variant_product_var_constraints = "arch_variant_product_var_constraints",
|
||||
_product_var_constraints = "product_var_constraints",
|
||||
)
|
||||
|
||||
_soong_config_variables = _soong_config_bool_variables.keys() + \
|
||||
_soong_config_string_variables.keys() + \
|
||||
_soong_config_value_variables.keys()
|
||||
|
||||
_product_variables = {
|
||||
var: True
|
||||
for var in _product_var_constraints
|
||||
}
|
||||
|
||||
_arch_variant_product_variables = {
|
||||
var: True
|
||||
for var in _arch_variant_product_var_constraints
|
||||
}
|
||||
|
||||
_arch_variant_to_constraints = {
|
||||
"arm": "//build/bazel/platforms/arch:arm",
|
||||
"arm64": "//build/bazel/platforms/arch:arm64",
|
||||
"x86": "//build/bazel/platforms/arch:x86",
|
||||
"x86_64": "//build/bazel/platforms/arch:x86_64",
|
||||
"android": "//build/bazel/platforms/os:android",
|
||||
"darwin": "//build/bazel/platforms/os:darwin",
|
||||
"linux": "//build/bazel/platforms/os:linux",
|
||||
"linux_bionic": "//build/bazel/platforms/os:linux_bionic",
|
||||
"windows": "//build/bazel/platforms/os:windows",
|
||||
}
|
||||
|
||||
constants = struct(
|
||||
SoongConfigVariables = _soong_config_variables,
|
||||
SoongConfigBoolVariables = _soong_config_bool_variables,
|
||||
SoongConfigStringVariables = _soong_config_string_variables,
|
||||
SoongConfigValueVariables = _soong_config_value_variables,
|
||||
ProductVariables = _product_variables,
|
||||
ArchVariantProductVariables = _arch_variant_product_variables,
|
||||
ArchVariantToConstraints = _arch_variant_to_constraints,
|
||||
)
|
|
@ -0,0 +1,22 @@
|
|||
"""Macros to generate constraint settings and values for Soong variables."""
|
||||
|
||||
def soong_config_variables(bool_vars, value_vars, string_vars):
|
||||
for variable in bool_vars.keys() + value_vars.keys():
|
||||
variable = variable.lower()
|
||||
native.constraint_setting(
|
||||
name = variable + "_constraint",
|
||||
)
|
||||
native.constraint_value(
|
||||
name = variable,
|
||||
constraint_setting = variable + "_constraint",
|
||||
)
|
||||
for variable, choices in string_vars.items():
|
||||
for choice in choices:
|
||||
var_with_choice = (variable + "__" + choice).lower()
|
||||
native.constraint_setting(
|
||||
name = var_with_choice + "_constraint",
|
||||
)
|
||||
native.constraint_value(
|
||||
name = var_with_choice,
|
||||
constraint_setting = var_with_choice + "_constraint",
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
exports_files(["lunch.bzl"])
|
|
@ -0,0 +1,17 @@
|
|||
# Bazel rules for Android Platform.
|
||||
|
||||
This directory contains Starlark extensions for building the Android Platform with Bazel.
|
||||
|
||||
## APEX
|
||||
|
||||
Run the following command to build a miminal APEX example.
|
||||
|
||||
```
|
||||
$ b build //build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal
|
||||
```
|
||||
|
||||
Verify the contents of the APEX with `zipinfo`:
|
||||
|
||||
```
|
||||
$ zipinfo bazel-bin/build/bazel/examples/apex/minimal/build.bazel.examples.apex.minimal.apex
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
"""
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
AndroidAppCertificateInfo = provider(
|
||||
"Info needed for Android app certificates",
|
||||
fields = {
|
||||
"pem": "Certificate .pem file",
|
||||
"pk8": "Certificate .pk8 file",
|
||||
},
|
||||
)
|
||||
|
||||
def _android_app_certificate_rule_impl(ctx):
|
||||
return [
|
||||
AndroidAppCertificateInfo(pem = ctx.file.pem, pk8 = ctx.file.pk8),
|
||||
]
|
||||
|
||||
_android_app_certificate = rule(
|
||||
implementation = _android_app_certificate_rule_impl,
|
||||
attrs = {
|
||||
"pem": attr.label(mandatory = True, allow_single_file = [".pem"]),
|
||||
"pk8": attr.label(mandatory = True, allow_single_file = [".pk8"]),
|
||||
},
|
||||
)
|
||||
|
||||
def android_app_certificate(
|
||||
name,
|
||||
certificate,
|
||||
**kwargs):
|
||||
"Bazel macro to correspond with the Android app certificate Soong module."
|
||||
|
||||
_android_app_certificate(
|
||||
name = name,
|
||||
pem = certificate + ".x509.pem",
|
||||
pk8 = certificate + ".pk8",
|
||||
**kwargs
|
||||
)
|
|
@ -0,0 +1,131 @@
|
|||
"""
|
||||
Copyright (C) 2022 The Android Open Source Project
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
load("@bazel_skylib//lib:paths.bzl", "paths")
|
||||
load("android_app_certificate.bzl", "AndroidAppCertificateInfo")
|
||||
|
||||
AndroidAppKeystoreInfo = provider(
|
||||
"Info needed for Android app keystores",
|
||||
fields = {
|
||||
"keystore": "JKS .keystore file housing certificate info",
|
||||
},
|
||||
)
|
||||
|
||||
def _pk8_to_private_pem(ctx, openssl, pk8_file, private_pem_file):
|
||||
"""Converts a .pk8 private key file in DER format to a .pem private key file in PEM format."""
|
||||
args = ctx.actions.args()
|
||||
args.add("pkcs8")
|
||||
args.add_all(["-in", pk8_file])
|
||||
args.add_all(["-inform", "DER"])
|
||||
args.add_all(["-outform", "PEM"])
|
||||
args.add_all(["-out", private_pem_file])
|
||||
args.add("-nocrypt") # don't bother encrypting this private key since it is just an intermediate file
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = [pk8_file],
|
||||
executable = openssl,
|
||||
outputs = [private_pem_file],
|
||||
arguments = [args],
|
||||
mnemonic = "CreatePrivPEM",
|
||||
)
|
||||
|
||||
def _pem_to_pk12(ctx, openssl, certificate_pem, private_key_pem, pk12_file):
|
||||
"""Converts an X.509 certificate and private key pair of PEM files to a single PKCS12 keystore file."""
|
||||
args = ctx.actions.args()
|
||||
args.add("pkcs12")
|
||||
args.add("-export")
|
||||
args.add_all(["-in", certificate_pem])
|
||||
args.add_all(["-inkey", private_key_pem])
|
||||
args.add_all(["-out", pk12_file])
|
||||
args.add_all(["-name", "android"])
|
||||
# openssl requires a password and will request a
|
||||
# password from STDIN if we don't supply one here
|
||||
args.add_all(["-passout", "pass:android"])
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = [
|
||||
certificate_pem,
|
||||
private_key_pem,
|
||||
],
|
||||
executable = openssl,
|
||||
outputs = [pk12_file],
|
||||
arguments = [args],
|
||||
mnemonic = "CreatePK12",
|
||||
)
|
||||
|
||||
def _pk12_to_keystore(ctx, keytool, pk12_file, keystore_file):
|
||||
"""Converts a PKCS12 keystore file to a JKS keystore file."""
|
||||
args = ctx.actions.args()
|
||||
args.add("-importkeystore")
|
||||
args.add_all(["-destkeystore", keystore_file])
|
||||
args.add_all(["-srckeystore", pk12_file])
|
||||
args.add_all(["-srcstoretype", "PKCS12"])
|
||||
args.add_all(["-srcstorepass", "android"])
|
||||
# apksigner expects keystores provided by the debug_signing_keys attribute
|
||||
# to be secured with the password "android"
|
||||
args.add_all(["-deststorepass", "android"])
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = [pk12_file],
|
||||
executable = keytool,
|
||||
outputs = [keystore_file],
|
||||
arguments = [args],
|
||||
mnemonic = "CreateKeystore",
|
||||
)
|
||||
|
||||
def _android_app_keystore_rule_impl(ctx):
|
||||
openssl = ctx.executable._openssl
|
||||
keytool = ctx.executable._keytool
|
||||
|
||||
private_pem = ctx.actions.declare_file(ctx.attr.name + ".priv.pem")
|
||||
pk12 = ctx.actions.declare_file(ctx.attr.name + ".pk12")
|
||||
keystore = ctx.actions.declare_file(ctx.attr.name + ".keystore")
|
||||
|
||||
pk8_file = ctx.attr.certificate[AndroidAppCertificateInfo].pk8
|
||||
pem_file = ctx.attr.certificate[AndroidAppCertificateInfo].pem
|
||||
_pk8_to_private_pem(ctx, openssl, pk8_file, private_pem)
|
||||
_pem_to_pk12(ctx, openssl, pem_file, private_pem, pk12)
|
||||
_pk12_to_keystore(ctx, keytool, pk12, keystore)
|
||||
|
||||
return [
|
||||
AndroidAppKeystoreInfo(
|
||||
keystore = keystore,
|
||||
),
|
||||
DefaultInfo(files = depset(direct = [keystore]))
|
||||
]
|
||||
|
||||
"""Converts an android_app_certificate (i.e. pem/pk8 pair) into a JKS keystore"""
|
||||
android_app_keystore = rule(
|
||||
implementation = _android_app_keystore_rule_impl,
|
||||
attrs = {
|
||||
"certificate": attr.label(mandatory = True, providers = [AndroidAppCertificateInfo]),
|
||||
"_openssl": attr.label(
|
||||
default = Label("//prebuilts/build-tools:linux-x86/bin/openssl"),
|
||||
allow_single_file = True,
|
||||
executable = True,
|
||||
cfg = "exec",
|
||||
doc = "An OpenSSL compatible tool."
|
||||
),
|
||||
"_keytool": attr.label(
|
||||
default = Label("//prebuilts/jdk/jdk11:linux-x86/bin/keytool"),
|
||||
allow_single_file = True,
|
||||
executable = True,
|
||||
cfg = "exec",
|
||||
doc = "The keytool binary."
|
||||
),
|
||||
},
|
||||
provides = [AndroidAppKeystoreInfo],
|
||||
)
|
|
@ -0,0 +1,99 @@
|
|||
"""
|
||||
Copyright (C) 2022 The Android Open Source Project
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
load("@bazel_skylib//lib:paths.bzl", "paths")
|
||||
load("@rules_android//rules:rules.bzl", _android_binary = "android_binary")
|
||||
load("@soong_injection//product_config:product_variables.bzl", "product_vars")
|
||||
|
||||
load("android_app_certificate.bzl", "android_app_certificate")
|
||||
load("android_app_keystore.bzl", "android_app_keystore")
|
||||
|
||||
|
||||
def _default_cert_prod_var():
|
||||
return product_vars["DefaultAppCertificate"]
|
||||
|
||||
def _default_app_certificate_package():
|
||||
default_cert = _default_cert_prod_var()
|
||||
if default_cert:
|
||||
return "//" + paths.dirname(default_cert)
|
||||
# if product variable is not set, default to Soong default:
|
||||
return "//build/make/target/product/security"
|
||||
|
||||
def _default_app_certificate():
|
||||
default_cert = _default_cert_prod_var()
|
||||
if default_cert:
|
||||
return default_cert
|
||||
return _default_app_certificate_package() + ":testkey"
|
||||
|
||||
def _android_app_certificate_with_default_cert(name, cert_name):
|
||||
|
||||
if cert_name:
|
||||
# if a specific certificate name is given, check the default directory
|
||||
# for that certificate
|
||||
certificate = _default_app_certificate_package() + ":" + cert_name
|
||||
else:
|
||||
certificate = _default_app_certificate()
|
||||
|
||||
android_app_certificate(
|
||||
name = name,
|
||||
certificate = certificate,
|
||||
)
|
||||
|
||||
def android_binary(
|
||||
name,
|
||||
certificate = None,
|
||||
certificate_name = None,
|
||||
**kwargs):
|
||||
"""Bazel macro to find and create a keystore to use for debug_signing_keys
|
||||
with @rules_android android_binary.
|
||||
|
||||
This module emulates the Soong behavior which allows a developer to specify
|
||||
a specific module name for the android_app_certificate or the name of a
|
||||
.pem/.pk8 certificate/key pair in a directory specified by the
|
||||
DefaultAppCertificate product variable. In either case, we convert the specified
|
||||
.pem/.pk8 certificate/key pair to a JKS .keystore file before passing it to the
|
||||
android_binary rule.
|
||||
|
||||
Arguments:
|
||||
certificate: Bazel target
|
||||
certificate_name: string, name of private key file in default certificate directory
|
||||
**kwargs: map, additional args to pass to android_binary
|
||||
"""
|
||||
|
||||
if certificate and certificate_name:
|
||||
fail("Cannot use both certificate_name and certificate attributes together. Use only one of them.")
|
||||
|
||||
debug_signing_keys = kwargs.pop("debug_signing_keys", [])
|
||||
|
||||
if certificate or certificate_name:
|
||||
if certificate_name:
|
||||
app_cert_name = name + "_app_certificate"
|
||||
_android_app_certificate_with_default_cert(app_cert_name, certificate_name)
|
||||
certificate = ":" + app_cert_name
|
||||
|
||||
app_keystore_name = name + "_keystore"
|
||||
android_app_keystore(
|
||||
name = app_keystore_name,
|
||||
certificate = certificate
|
||||
)
|
||||
|
||||
debug_signing_keys.append(app_keystore_name)
|
||||
|
||||
_android_binary(
|
||||
name = name,
|
||||
debug_signing_keys = debug_signing_keys,
|
||||
**kwargs
|
||||
)
|
|
@ -0,0 +1,432 @@
|
|||
"""
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
load(":apex_key.bzl", "ApexKeyInfo")
|
||||
load(":prebuilt_file.bzl", "PrebuiltFileInfo")
|
||||
load(":sh_binary.bzl", "ShBinaryInfo")
|
||||
load("//build/bazel/rules/cc:stripped_cc_common.bzl", "StrippedCcBinaryInfo")
|
||||
load("//build/bazel/rules/android:android_app_certificate.bzl", "AndroidAppCertificateInfo")
|
||||
load("//build/bazel/rules/apex:transition.bzl", "apex_transition", "shared_lib_transition_32", "shared_lib_transition_64")
|
||||
load("//build/bazel/rules/apex:cc.bzl", "ApexCcInfo", "apex_cc_aspect")
|
||||
|
||||
DIR_LIB = "lib"
|
||||
DIR_LIB64 = "lib64"
|
||||
|
||||
ApexInfo = provider(
|
||||
"ApexInfo has no field currently and is used by apex rule dependents to ensure an attribute is a target of apex rule.",
|
||||
fields = {},
|
||||
)
|
||||
|
||||
# Prepare the input files info for bazel_apexer_wrapper to generate APEX filesystem image.
|
||||
def _prepare_apexer_wrapper_inputs(ctx):
|
||||
# dictionary to return in the format:
|
||||
# apex_manifest[(image_file_dirname, image_file_basename)] = bazel_output_file
|
||||
apex_manifest = {}
|
||||
|
||||
x86_constraint = ctx.attr._x86_constraint[platform_common.ConstraintValueInfo]
|
||||
x86_64_constraint = ctx.attr._x86_64_constraint[platform_common.ConstraintValueInfo]
|
||||
arm_constraint = ctx.attr._arm_constraint[platform_common.ConstraintValueInfo]
|
||||
arm64_constraint = ctx.attr._arm64_constraint[platform_common.ConstraintValueInfo]
|
||||
|
||||
if ctx.target_platform_has_constraint(x86_constraint):
|
||||
_add_libs_32_target(ctx, "x86", apex_manifest)
|
||||
elif ctx.target_platform_has_constraint(x86_64_constraint):
|
||||
_add_libs_64_target(ctx, "x86", "x86_64", apex_manifest)
|
||||
elif ctx.target_platform_has_constraint(arm_constraint):
|
||||
_add_libs_32_target(ctx, "arm", apex_manifest)
|
||||
elif ctx.target_platform_has_constraint(arm64_constraint):
|
||||
_add_libs_64_target(ctx, "arm", "arm64", apex_manifest)
|
||||
|
||||
# Handle prebuilts
|
||||
for dep in ctx.attr.prebuilts:
|
||||
prebuilt_file_info = dep[PrebuiltFileInfo]
|
||||
if prebuilt_file_info.filename:
|
||||
filename = prebuilt_file_info.filename
|
||||
else:
|
||||
filename = dep.label.name
|
||||
apex_manifest[(prebuilt_file_info.dir, filename)] = prebuilt_file_info.src
|
||||
|
||||
# Handle binaries
|
||||
for dep in ctx.attr.binaries:
|
||||
if ShBinaryInfo in dep:
|
||||
# sh_binary requires special handling on directory/filename construction.
|
||||
sh_binary_info = dep[ShBinaryInfo]
|
||||
default_info = dep[DefaultInfo]
|
||||
if sh_binary_info != None:
|
||||
directory = "bin"
|
||||
if sh_binary_info.sub_dir != None and sh_binary_info.sub_dir != "":
|
||||
directory = "/".join([directory, sh_binary_info.sub_dir])
|
||||
|
||||
if sh_binary_info.filename != None and sh_binary_info.filename != "":
|
||||
filename = sh_binary_info.filename
|
||||
else:
|
||||
filename = dep.label.name
|
||||
|
||||
apex_manifest[(directory, filename)] = default_info.files_to_run.executable
|
||||
elif CcInfo in dep:
|
||||
# cc_binary just takes the final executable from the runfiles.
|
||||
apex_manifest[("bin", dep.label.name)] = dep[DefaultInfo].files_to_run.executable
|
||||
|
||||
apex_content_inputs = []
|
||||
|
||||
bazel_apexer_wrapper_manifest = ctx.actions.declare_file("%s_bazel_apexer_wrapper_manifest" % ctx.attr.name)
|
||||
file_lines = []
|
||||
|
||||
# Store the apex file target directory, file name and the path in the source tree in a file.
|
||||
# This file will be read by the bazel_apexer_wrapper to create the apex input directory.
|
||||
# Here is an example:
|
||||
# {etc/tz,tz_version,system/timezone/output_data/version/tz_version}
|
||||
for (apex_dirname, apex_basename), bazel_input_file in apex_manifest.items():
|
||||
apex_content_inputs.append(bazel_input_file)
|
||||
file_lines += [",".join([apex_dirname, apex_basename, bazel_input_file.path])]
|
||||
|
||||
ctx.actions.write(bazel_apexer_wrapper_manifest, "\n".join(file_lines))
|
||||
|
||||
return apex_content_inputs, bazel_apexer_wrapper_manifest
|
||||
|
||||
def _add_libs_32_target(ctx, key, apex_manifest):
|
||||
if len(ctx.split_attr.native_shared_libs_32.keys()) > 0:
|
||||
_add_lib_file(DIR_LIB, ctx.split_attr.native_shared_libs_32[key], apex_manifest)
|
||||
|
||||
def _add_libs_64_target(ctx, key_32, key_64, apex_manifest):
|
||||
_add_libs_32_target(ctx, key_32, apex_manifest)
|
||||
if len(ctx.split_attr.native_shared_libs_64.keys()) > 0:
|
||||
_add_lib_file(DIR_LIB64, ctx.split_attr.native_shared_libs_64[key_64], apex_manifest)
|
||||
|
||||
def _add_lib_file(dir, libs, apex_manifest):
|
||||
for dep in libs:
|
||||
apex_cc_info = dep[ApexCcInfo]
|
||||
for lib_file in apex_cc_info.transitive_shared_libs.to_list():
|
||||
apex_manifest[(dir, lib_file.basename)] = lib_file
|
||||
|
||||
# conv_apex_manifest - Convert the JSON APEX manifest to protobuf, which is needed by apexer.
|
||||
def _convert_apex_manifest_json_to_pb(ctx, apex_toolchain):
|
||||
apex_manifest_json = ctx.file.manifest
|
||||
apex_manifest_pb = ctx.actions.declare_file("apex_manifest.pb")
|
||||
|
||||
ctx.actions.run(
|
||||
outputs = [apex_manifest_pb],
|
||||
inputs = [ctx.file.manifest],
|
||||
executable = apex_toolchain.conv_apex_manifest,
|
||||
arguments = [
|
||||
"proto",
|
||||
apex_manifest_json.path,
|
||||
"-o",
|
||||
apex_manifest_pb.path,
|
||||
],
|
||||
mnemonic = "ConvApexManifest",
|
||||
)
|
||||
|
||||
return apex_manifest_pb
|
||||
|
||||
# apexer - generate the APEX file.
|
||||
def _run_apexer(ctx, apex_toolchain, apex_content_inputs, bazel_apexer_wrapper_manifest, apex_manifest_pb):
|
||||
# Inputs
|
||||
file_contexts = ctx.file.file_contexts
|
||||
apex_key_info = ctx.attr.key[ApexKeyInfo]
|
||||
privkey = apex_key_info.private_key
|
||||
pubkey = apex_key_info.public_key
|
||||
android_jar = apex_toolchain.android_jar
|
||||
android_manifest = ctx.file.android_manifest
|
||||
|
||||
# Outputs
|
||||
apex_output_file = ctx.actions.declare_file(ctx.attr.name + ".apex.unsigned")
|
||||
|
||||
# Arguments
|
||||
args = ctx.actions.args()
|
||||
args.add_all(["--manifest", apex_manifest_pb.path])
|
||||
args.add_all(["--file_contexts", file_contexts.path])
|
||||
args.add_all(["--key", privkey.path])
|
||||
args.add_all(["--pubkey", pubkey.path])
|
||||
min_sdk_version = ctx.attr.min_sdk_version
|
||||
|
||||
# TODO(b/215339575): This is a super rudimentary way to convert "current" to a numerical number.
|
||||
# Generalize this to API level handling logic in a separate Starlark utility, preferably using
|
||||
# API level maps dumped from api_levels.go
|
||||
if min_sdk_version == "current":
|
||||
min_sdk_version = "10000"
|
||||
args.add_all(["--min_sdk_version", min_sdk_version])
|
||||
args.add_all(["--bazel_apexer_wrapper_manifest", bazel_apexer_wrapper_manifest])
|
||||
args.add_all(["--apexer_path", apex_toolchain.apexer])
|
||||
|
||||
# apexer needs the list of directories containing all auxilliary tools invoked during
|
||||
# the creation of an apex
|
||||
avbtool_files = apex_toolchain.avbtool[DefaultInfo].files_to_run
|
||||
e2fsdroid_files = apex_toolchain.e2fsdroid[DefaultInfo].files_to_run
|
||||
mke2fs_files = apex_toolchain.mke2fs[DefaultInfo].files_to_run
|
||||
resize2fs_files = apex_toolchain.resize2fs[DefaultInfo].files_to_run
|
||||
apexer_tool_paths = [
|
||||
# These are built by make_injection
|
||||
apex_toolchain.apexer.dirname,
|
||||
|
||||
# These are real Bazel targets
|
||||
apex_toolchain.aapt2.dirname,
|
||||
avbtool_files.executable.dirname,
|
||||
e2fsdroid_files.executable.dirname,
|
||||
mke2fs_files.executable.dirname,
|
||||
resize2fs_files.executable.dirname,
|
||||
]
|
||||
|
||||
args.add_all(["--apexer_tool_path", ":".join(apexer_tool_paths)])
|
||||
args.add_all(["--apex_output_file", apex_output_file])
|
||||
|
||||
if android_manifest != None:
|
||||
args.add_all(["--android_manifest", android_manifest.path])
|
||||
|
||||
inputs = apex_content_inputs + [
|
||||
bazel_apexer_wrapper_manifest,
|
||||
apex_manifest_pb,
|
||||
file_contexts,
|
||||
privkey,
|
||||
pubkey,
|
||||
android_jar,
|
||||
]
|
||||
|
||||
tools = [
|
||||
avbtool_files,
|
||||
e2fsdroid_files,
|
||||
mke2fs_files,
|
||||
resize2fs_files,
|
||||
apex_toolchain.aapt2,
|
||||
|
||||
apex_toolchain.apexer,
|
||||
apex_toolchain.sefcontext_compile,
|
||||
]
|
||||
|
||||
if android_manifest != None:
|
||||
inputs.append(android_manifest)
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = inputs,
|
||||
tools = tools,
|
||||
outputs = [apex_output_file],
|
||||
executable = ctx.executable._bazel_apexer_wrapper,
|
||||
arguments = [args],
|
||||
mnemonic = "BazelApexerWrapper",
|
||||
)
|
||||
|
||||
return apex_output_file
|
||||
|
||||
# Sign a file with signapk.
|
||||
def _run_signapk(ctx, unsigned_file, signed_file, private_key, public_key, mnemonic):
|
||||
# Inputs
|
||||
inputs = [
|
||||
unsigned_file,
|
||||
private_key,
|
||||
public_key,
|
||||
ctx.executable._signapk,
|
||||
]
|
||||
|
||||
# Outputs
|
||||
outputs = [signed_file]
|
||||
|
||||
# Arguments
|
||||
args = ctx.actions.args()
|
||||
args.add_all(["-a", 4096])
|
||||
args.add_all(["--align-file-size"])
|
||||
args.add_all([public_key, private_key])
|
||||
args.add_all([unsigned_file, signed_file])
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = inputs,
|
||||
outputs = outputs,
|
||||
executable = ctx.executable._signapk,
|
||||
arguments = [args],
|
||||
mnemonic = mnemonic,
|
||||
)
|
||||
|
||||
return signed_file
|
||||
|
||||
# Compress a file with apex_compression_tool.
|
||||
def _run_apex_compression_tool(ctx, apex_toolchain, input_file, output_file_name):
|
||||
# Inputs
|
||||
inputs = [
|
||||
input_file,
|
||||
]
|
||||
|
||||
avbtool_files = apex_toolchain.avbtool[DefaultInfo].files_to_run
|
||||
tools = [
|
||||
avbtool_files,
|
||||
apex_toolchain.apex_compression_tool,
|
||||
apex_toolchain.soong_zip,
|
||||
]
|
||||
|
||||
# Outputs
|
||||
compressed_file = ctx.actions.declare_file(output_file_name)
|
||||
outputs = [compressed_file]
|
||||
|
||||
# Arguments
|
||||
args = ctx.actions.args()
|
||||
args.add_all(["compress"])
|
||||
tool_dirs = [apex_toolchain.soong_zip.dirname, avbtool_files.executable.dirname]
|
||||
args.add_all(["--apex_compression_tool", ":".join(tool_dirs)])
|
||||
args.add_all(["--input", input_file])
|
||||
args.add_all(["--output", compressed_file])
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = inputs,
|
||||
tools = tools,
|
||||
outputs = outputs,
|
||||
executable = apex_toolchain.apex_compression_tool,
|
||||
arguments = [args],
|
||||
mnemonic = "BazelApexCompressing",
|
||||
)
|
||||
return compressed_file
|
||||
|
||||
# See the APEX section in the README on how to use this rule.
|
||||
def _apex_rule_impl(ctx):
|
||||
apex_toolchain = ctx.toolchains["//build/bazel/rules/apex:apex_toolchain_type"].toolchain_info
|
||||
|
||||
apex_content_inputs, bazel_apexer_wrapper_manifest = _prepare_apexer_wrapper_inputs(ctx)
|
||||
apex_manifest_pb = _convert_apex_manifest_json_to_pb(ctx, apex_toolchain)
|
||||
|
||||
unsigned_apex_output_file = _run_apexer(ctx, apex_toolchain, apex_content_inputs, bazel_apexer_wrapper_manifest, apex_manifest_pb)
|
||||
|
||||
apex_cert_info = ctx.attr.certificate[AndroidAppCertificateInfo]
|
||||
private_key = apex_cert_info.pk8
|
||||
public_key = apex_cert_info.pem
|
||||
|
||||
signed_apex = ctx.outputs.apex_output
|
||||
_run_signapk(ctx, unsigned_apex_output_file, signed_apex, private_key, public_key, "BazelApexSigning")
|
||||
output_file = signed_apex
|
||||
|
||||
if ctx.attr.compressible:
|
||||
compressed_apex_output_file = _run_apex_compression_tool(ctx, apex_toolchain, signed_apex, ctx.attr.name + ".capex.unsigned")
|
||||
signed_capex = ctx.outputs.capex_output
|
||||
_run_signapk(ctx, compressed_apex_output_file, signed_capex, private_key, public_key, "BazelCompressedApexSigning")
|
||||
|
||||
files_to_build = depset([output_file])
|
||||
return [DefaultInfo(files = files_to_build), ApexInfo()]
|
||||
|
||||
_apex = rule(
|
||||
implementation = _apex_rule_impl,
|
||||
attrs = {
|
||||
"manifest": attr.label(allow_single_file = [".json"]),
|
||||
"android_manifest": attr.label(allow_single_file = [".xml"]),
|
||||
"file_contexts": attr.label(allow_single_file = True, mandatory = True),
|
||||
"key": attr.label(providers = [ApexKeyInfo]),
|
||||
"certificate": attr.label(providers = [AndroidAppCertificateInfo]),
|
||||
"min_sdk_version": attr.string(default = "current"),
|
||||
"updatable": attr.bool(default = True),
|
||||
"installable": attr.bool(default = True),
|
||||
"compressible": attr.bool(default = False),
|
||||
"native_shared_libs_32": attr.label_list(
|
||||
providers = [ApexCcInfo],
|
||||
aspects = [apex_cc_aspect],
|
||||
cfg = shared_lib_transition_32,
|
||||
doc = "The libs compiled for 32-bit",
|
||||
),
|
||||
"native_shared_libs_64": attr.label_list(
|
||||
providers = [ApexCcInfo],
|
||||
aspects = [apex_cc_aspect],
|
||||
cfg = shared_lib_transition_64,
|
||||
doc = "The libs compiled for 64-bit",
|
||||
),
|
||||
"binaries": attr.label_list(
|
||||
providers = [
|
||||
# The dependency must produce _all_ of the providers in _one_ of these lists.
|
||||
[ShBinaryInfo], # sh_binary
|
||||
[StrippedCcBinaryInfo, CcInfo], # cc_binary (stripped)
|
||||
],
|
||||
cfg = apex_transition,
|
||||
),
|
||||
"prebuilts": attr.label_list(providers = [PrebuiltFileInfo], cfg = apex_transition),
|
||||
"apex_output": attr.output(doc = "signed .apex output"),
|
||||
"capex_output": attr.output(doc = "signed .capex output"),
|
||||
|
||||
# Required to use apex_transition. This is an acknowledgement to the risks of memory bloat when using transitions.
|
||||
"_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"),
|
||||
"_bazel_apexer_wrapper": attr.label(
|
||||
cfg = "host",
|
||||
doc = "The apexer wrapper to avoid the problem where symlinks are created inside apex image.",
|
||||
executable = True,
|
||||
default = "//build/bazel/rules/apex:bazel_apexer_wrapper",
|
||||
),
|
||||
"_signapk": attr.label(
|
||||
cfg = "host",
|
||||
doc = "The signapk tool.",
|
||||
executable = True,
|
||||
default = "//build/make/tools/signapk",
|
||||
),
|
||||
"_x86_constraint": attr.label(
|
||||
default = Label("//build/bazel/platforms/arch:x86"),
|
||||
),
|
||||
"_x86_64_constraint": attr.label(
|
||||
default = Label("//build/bazel/platforms/arch:x86_64"),
|
||||
),
|
||||
"_arm_constraint": attr.label(
|
||||
default = Label("//build/bazel/platforms/arch:arm"),
|
||||
),
|
||||
"_arm64_constraint": attr.label(
|
||||
default = Label("//build/bazel/platforms/arch:arm64"),
|
||||
),
|
||||
},
|
||||
toolchains = ["//build/bazel/rules/apex:apex_toolchain_type"],
|
||||
fragments = ["platform"],
|
||||
)
|
||||
|
||||
def apex(
|
||||
name,
|
||||
manifest = "apex_manifest.json",
|
||||
android_manifest = None,
|
||||
file_contexts = None,
|
||||
key = None,
|
||||
certificate = None,
|
||||
min_sdk_version = None,
|
||||
updatable = True,
|
||||
installable = True,
|
||||
compressible = False,
|
||||
native_shared_libs_32 = [],
|
||||
native_shared_libs_64 = [],
|
||||
binaries = [],
|
||||
prebuilts = [],
|
||||
**kwargs):
|
||||
"Bazel macro to correspond with the APEX bundle Soong module."
|
||||
|
||||
# If file_contexts is not specified, then use the default from //system/sepolicy/apex.
|
||||
# https://cs.android.com/android/platform/superproject/+/master:build/soong/apex/builder.go;l=259-263;drc=b02043b84d86fe1007afef1ff012a2155172215c
|
||||
if file_contexts == None:
|
||||
file_contexts = "//system/sepolicy/apex:" + name + "-file_contexts"
|
||||
|
||||
apex_output = name + ".apex"
|
||||
capex_output = None
|
||||
if compressible:
|
||||
capex_output = name + ".capex"
|
||||
|
||||
_apex(
|
||||
name = name,
|
||||
manifest = manifest,
|
||||
android_manifest = android_manifest,
|
||||
file_contexts = file_contexts,
|
||||
key = key,
|
||||
certificate = certificate,
|
||||
min_sdk_version = min_sdk_version,
|
||||
updatable = updatable,
|
||||
installable = installable,
|
||||
compressible = compressible,
|
||||
native_shared_libs_32 = native_shared_libs_32,
|
||||
native_shared_libs_64 = native_shared_libs_64,
|
||||
binaries = binaries,
|
||||
prebuilts = prebuilts,
|
||||
|
||||
# Enables predeclared output builds from command line directly, e.g.
|
||||
#
|
||||
# $ bazel build //path/to/module:com.android.module.apex
|
||||
# $ bazel build //path/to/module:com.android.module.capex
|
||||
apex_output = apex_output,
|
||||
capex_output = capex_output,
|
||||
**kwargs
|
||||
)
|
|
@ -0,0 +1,79 @@
|
|||
load("//build/bazel/rules/apex:toolchain.bzl", "apex_toolchain")
|
||||
load("@bazel_skylib//rules:common_settings.bzl", "string_setting", "string_list_setting")
|
||||
|
||||
string_setting(
|
||||
name = "apex_name",
|
||||
build_setting_default = "",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
string_setting(
|
||||
name = "min_sdk_version",
|
||||
build_setting_default = "",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
string_list_setting(
|
||||
name = "apex_direct_deps",
|
||||
build_setting_default = [],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
toolchain_type(name = "apex_toolchain_type")
|
||||
|
||||
apex_toolchain(
|
||||
name = "prebuilt_apex_toolchain",
|
||||
aapt2 = "//prebuilts/sdk/tools:linux/bin/aapt2",
|
||||
avbtool = "//external/avb:avbtool",
|
||||
apexer = "@make_injection//:host/linux-x86/bin/apexer",
|
||||
mke2fs = "//external/e2fsprogs/misc:mke2fs",
|
||||
resize2fs = "//external/e2fsprogs/resize:resize2fs",
|
||||
e2fsdroid = "//external/e2fsprogs/contrib/android:e2fsdroid",
|
||||
sefcontext_compile = "@make_injection//:host/linux-x86/bin/sefcontext_compile",
|
||||
conv_apex_manifest = "@make_injection//:host/linux-x86/bin/conv_apex_manifest",
|
||||
android_jar = "//prebuilts/sdk/current:public/android.jar",
|
||||
apex_compression_tool = "@make_injection//:host/linux-x86/bin/apex_compression_tool",
|
||||
soong_zip = "//prebuilts/build-tools:linux-x86/bin/soong_zip",
|
||||
)
|
||||
|
||||
toolchain(
|
||||
name = "prebuilt_apex_toolchain_def",
|
||||
exec_compatible_with = [
|
||||
"//build/bazel/platforms/arch:x86_64",
|
||||
"//build/bazel/platforms/os:linux",
|
||||
],
|
||||
target_compatible_with = [
|
||||
"//build/bazel/platforms/os:android",
|
||||
],
|
||||
toolchain = ":prebuilt_apex_toolchain",
|
||||
toolchain_type = "//build/bazel/rules/apex:apex_toolchain_type",
|
||||
)
|
||||
|
||||
py_binary(
|
||||
name = "bazel_apexer_wrapper",
|
||||
srcs = ["bazel_apexer_wrapper.py"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
sh_test(
|
||||
name = "bazel_apexer_wrapper_test",
|
||||
srcs = ["bazel_apexer_wrapper_test.sh"],
|
||||
deps = ["@bazel_tools//tools/bash/runfiles"],
|
||||
data = [
|
||||
":bazel_apexer_wrapper",
|
||||
"test.pem",
|
||||
"//external/avb:avbtool",
|
||||
"//external/e2fsprogs/contrib/android:e2fsdroid",
|
||||
"//external/e2fsprogs/misc:mke2fs",
|
||||
"//external/e2fsprogs/resize:resize2fs",
|
||||
"//external/e2fsprogs/debugfs:debugfs",
|
||||
"//prebuilts/build-tools:linux-x86/bin/soong_zip",
|
||||
"//prebuilts/sdk/tools:linux/bin/aapt2",
|
||||
"@make_injection//:host/linux-x86/bin/apex_compression_tool",
|
||||
"@make_injection//:host/linux-x86/bin/apexer",
|
||||
"@make_injection//:host/linux-x86/bin/conv_apex_manifest",
|
||||
"@make_injection//:host/linux-x86/bin/deapexer",
|
||||
"@make_injection//:host/linux-x86/bin/sefcontext_compile",
|
||||
"//prebuilts/sdk/current:public/android.jar",
|
||||
]
|
||||
)
|
|
@ -0,0 +1,207 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2021 The Android Open Source Project
|
||||
#
|
||||
# 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.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
def _create_apex(args, work_dir):
|
||||
|
||||
image_apex_dir = "image.apex"
|
||||
|
||||
# Used for creating canned_fs_config, since every file and dir in the APEX are represented
|
||||
# by an entry in the fs_config.
|
||||
apex_subdirs = []
|
||||
apex_filepaths = []
|
||||
|
||||
input_dir = os.path.join(work_dir, image_apex_dir)
|
||||
os.makedirs(input_dir, exist_ok=True)
|
||||
bazel_apexer_wrapper_manifest = open(args.bazel_apexer_wrapper_manifest, 'r')
|
||||
file_lines = bazel_apexer_wrapper_manifest.readlines()
|
||||
for line in file_lines:
|
||||
line = line.strip()
|
||||
if (len(line) == 0):
|
||||
continue
|
||||
apex_dirname, apex_filename, bazel_input_file = line.split(",")
|
||||
full_apex_dirname = "/".join([input_dir, apex_dirname])
|
||||
os.makedirs(full_apex_dirname, exist_ok=True)
|
||||
|
||||
apex_filepath = "/".join([apex_dirname, apex_filename])
|
||||
apex_filepaths.append(apex_filepath)
|
||||
apex_subdirs.append(apex_dirname)
|
||||
|
||||
full_apex_filepath = "/".join([input_dir, apex_filepath])
|
||||
# Because Bazel execution root is a symlink forest, all the input files are symlinks, these
|
||||
# include the dependency files declared in the BUILD files as well as the files declared
|
||||
# and created in the bzl files. For sandbox runs the former are two or more level symlinks and
|
||||
# latter are one level symlinks. For non-sandbox runs, the former are one level symlinks
|
||||
# and the latter are actual files. Here are some examples:
|
||||
#
|
||||
# Two level symlinks:
|
||||
# system/timezone/output_data/version/tz_version ->
|
||||
# /usr/local/google/home/...out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/
|
||||
# execroot/__main__/system/timezone/output_data/version/tz_version ->
|
||||
# /usr/local/google/home/.../system/timezone/output_data/version/tz_version
|
||||
#
|
||||
# Three level symlinks:
|
||||
# bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/libcrypto.so ->
|
||||
# /usr/local/google/home/yudiliu/android/aosp/master/out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/
|
||||
# execroot/__main__/bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/libcrypto.so ->
|
||||
# /usr/local/google/home/yudiliu/android/aosp/master/out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/
|
||||
# execroot/__main__/bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/
|
||||
# liblibcrypto_stripped.so ->
|
||||
# /usr/local/google/home/yudiliu/android/aosp/master/out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/
|
||||
# execroot/__main__/bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/
|
||||
# liblibcrypto_unstripped.so
|
||||
#
|
||||
# One level symlinks:
|
||||
# bazel-out/android_target-fastbuild/bin/system/timezone/apex/apex_manifest.pb ->
|
||||
# /usr/local/google/home/.../out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/
|
||||
# execroot/__main__/bazel-out/android_target-fastbuild/bin/system/timezone/apex/
|
||||
# apex_manifest.pb
|
||||
|
||||
if os.path.islink(bazel_input_file):
|
||||
bazel_input_file = os.readlink(bazel_input_file)
|
||||
|
||||
# For sandbox run these are the 2nd level symlinks and we need to resolve
|
||||
while os.path.islink(bazel_input_file) and 'execroot/__main__' in bazel_input_file:
|
||||
bazel_input_file = os.readlink(bazel_input_file)
|
||||
|
||||
shutil.copyfile(bazel_input_file, full_apex_filepath, follow_symlinks=False)
|
||||
|
||||
# Make sure subdirs are unique
|
||||
apex_subdirs_set = set()
|
||||
for d in apex_subdirs:
|
||||
apex_subdirs_set.add(d)
|
||||
|
||||
# Make sure all the parent dirs of the current subdir are in the set, too
|
||||
dirs = d.split("/")
|
||||
for i in range(0, len(dirs)):
|
||||
apex_subdirs_set.add("/".join(dirs[:i]))
|
||||
|
||||
canned_fs_config = _generate_canned_fs_config(work_dir, apex_subdirs_set, apex_filepaths)
|
||||
|
||||
# Construct the main apexer command.
|
||||
cmd = [args.apexer_path]
|
||||
cmd.append('--verbose')
|
||||
cmd.append('--force')
|
||||
cmd.append('--include_build_info')
|
||||
cmd.extend(['--file_contexts', args.file_contexts])
|
||||
cmd.extend(['--canned_fs_config', canned_fs_config])
|
||||
cmd.extend(['--key', args.key])
|
||||
cmd.extend(['--payload_type', 'image'])
|
||||
cmd.extend(['--target_sdk_version', '10000'])
|
||||
cmd.extend(['--payload_fs_type', 'ext4'])
|
||||
cmd.extend(['--apexer_tool_path', args.apexer_tool_paths])
|
||||
|
||||
if args.android_manifest != None:
|
||||
cmd.extend(['--android_manifest', args.android_manifest])
|
||||
|
||||
if args.pubkey != None:
|
||||
cmd.extend(['--pubkey', args.pubkey])
|
||||
|
||||
if args.manifest != None:
|
||||
cmd.extend(['--manifest', args.manifest])
|
||||
|
||||
if args.min_sdk_version != None:
|
||||
cmd.extend(['--min_sdk_version', args.min_sdk_version])
|
||||
|
||||
if args.android_jar_path != None:
|
||||
cmd.extend(['--android_jar_path', args.android_jar_path])
|
||||
|
||||
cmd.append(input_dir)
|
||||
cmd.append(args.apex_output_file)
|
||||
|
||||
popen = subprocess.Popen(cmd)
|
||||
popen.wait()
|
||||
|
||||
return True
|
||||
|
||||
# Generate filesystem config. This encodes the filemode, uid, and gid of each
|
||||
# file in the APEX, including apex_manifest.json and apex_manifest.pb.
|
||||
#
|
||||
# NOTE: every file must have an entry.
|
||||
def _generate_canned_fs_config(work_dir, dirs, filepaths):
|
||||
with tempfile.NamedTemporaryFile(mode = 'w+', dir=work_dir, delete=False) as canned_fs_config:
|
||||
config_lines = []
|
||||
config_lines += ["/ 1000 1000 0755"]
|
||||
config_lines += ["/apex_manifest.json 1000 1000 0644"]
|
||||
config_lines += ["/apex_manifest.pb 1000 1000 0644"]
|
||||
config_lines += ["/" + filepath + " 1000 1000 0644" for filepath in filepaths]
|
||||
config_lines += ["/" + d + " 0 2000 0755" for d in dirs]
|
||||
canned_fs_config.write("\n".join(config_lines))
|
||||
|
||||
return canned_fs_config.name
|
||||
|
||||
def _parse_args(argv):
|
||||
parser = argparse.ArgumentParser(description='Build an APEX file')
|
||||
|
||||
parser.add_argument(
|
||||
'--manifest',
|
||||
help='path to the APEX manifest file (.pb)')
|
||||
parser.add_argument(
|
||||
'--apex_output_file',
|
||||
required=True,
|
||||
help='path to the APEX image file')
|
||||
parser.add_argument(
|
||||
'--bazel_apexer_wrapper_manifest',
|
||||
required=True,
|
||||
help='path to the manifest file that stores the info about the files to be packaged by apexer')
|
||||
parser.add_argument(
|
||||
'--android_manifest',
|
||||
help='path to the AndroidManifest file. If omitted, a default one is created and used')
|
||||
parser.add_argument(
|
||||
'--file_contexts',
|
||||
required=True,
|
||||
help='selinux file contexts file.')
|
||||
parser.add_argument(
|
||||
'--key',
|
||||
required=True,
|
||||
help='path to the private key file.')
|
||||
parser.add_argument(
|
||||
'--pubkey',
|
||||
help='path to the public key file. Used to bundle the public key in APEX for testing.')
|
||||
parser.add_argument(
|
||||
'--apexer_path',
|
||||
required=True,
|
||||
help='Path to the apexer binary.')
|
||||
parser.add_argument(
|
||||
'--apexer_tool_paths',
|
||||
required=True,
|
||||
help='Directories containing all the tools used by apexer, separated by ":" character.')
|
||||
parser.add_argument(
|
||||
'--min_sdk_version',
|
||||
help='Default Min SDK version to use for AndroidManifest.xml')
|
||||
parser.add_argument(
|
||||
'--android_jar_path',
|
||||
help='path to use as the source of the android API.')
|
||||
|
||||
return parser.parse_args(argv)
|
||||
|
||||
def main(argv):
|
||||
args = _parse_args(argv)
|
||||
|
||||
with tempfile.TemporaryDirectory() as work_dir:
|
||||
success = _create_apex(args, work_dir)
|
||||
|
||||
if not success:
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
|
@ -0,0 +1,141 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright (C) 2021 The Android Open Source Project
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set -xeuo pipefail
|
||||
|
||||
apexer_tool_path="${RUNFILES_DIR}/__main__/external/make_injection/host/linux-x86/bin"
|
||||
avb_tool_path="${RUNFILES_DIR}/__main__/external/avb"
|
||||
android_jar="${RUNFILES_DIR}/__main__/prebuilts/sdk/current/public/android.jar"
|
||||
|
||||
input_dir=$(mktemp -d)
|
||||
output_dir=$(mktemp -d)
|
||||
|
||||
function cleanup {
|
||||
rm -rf ${input_dir}
|
||||
rm -rf ${output_dir}
|
||||
}
|
||||
|
||||
trap cleanup ERR
|
||||
#############################################
|
||||
# prepare the inputs
|
||||
#############################################
|
||||
# Create the input directory with
|
||||
# 1. a file with random bits
|
||||
# 2. a file installed sub dir with random bits
|
||||
# 3. a one-level symlink
|
||||
# 4. a two-level symlink with "execroot/__main__" in the path
|
||||
# 5. a two-level sumlink without "execroot/__main__" in the path
|
||||
# 6. a three-level symlink with "execroot/__main__" in the path
|
||||
echo "test file1" > "${input_dir}/file1"
|
||||
echo "test file2" > "${input_dir}/file2"
|
||||
mkdir -p "${input_dir}/execroot/__main__"
|
||||
ln -s "${input_dir}/file1" "${input_dir}/one_level_sym"
|
||||
ln -s "${input_dir}/file2" "${input_dir}/execroot/__main__/middle_sym"
|
||||
ln -s "${input_dir}/execroot/__main__/middle_sym" "${input_dir}/two_level_sym_in_execroot"
|
||||
ln -s "${input_dir}/one_level_sym" "${input_dir}/two_level_sym_not_in_execroot"
|
||||
ln -s "${input_dir}/two_level_sym_in_execroot" "${input_dir}/three_level_sym_in_execroot"
|
||||
|
||||
# Create the APEX manifest file
|
||||
manifest_dir=$(mktemp -d)
|
||||
manifest_file="${manifest_dir}/apex_manifest.pb"
|
||||
echo '{"name": "com.android.example.apex", "version": 1}' > "${manifest_dir}/apex_manifest.json"
|
||||
"${apexer_tool_path}/conv_apex_manifest" proto "${manifest_dir}/apex_manifest.json" -o ${manifest_file}
|
||||
|
||||
# Create the file_contexts file
|
||||
file_contexts_file=$(mktemp)
|
||||
echo '
|
||||
(/.*)? u:object_r:root_file:s0
|
||||
/execroot(/.*)? u:object_r:execroot_file:s0
|
||||
' > ${file_contexts_file}
|
||||
|
||||
output_file="${output_dir}/test.apex"
|
||||
|
||||
# Create the wrapper manifest file
|
||||
bazel_apexer_wrapper_manifest_file=$(mktemp)
|
||||
echo "
|
||||
dir1,file1,"${input_dir}/file1"
|
||||
dir2/dir3,file2,"${input_dir}/file2"
|
||||
dir4,one_level_sym,"${input_dir}/one_level_sym"
|
||||
dir5,two_level_sym_in_execroot,"${input_dir}/two_level_sym_in_execroot"
|
||||
dir6,two_level_sym_not_in_execroot,"${input_dir}/two_level_sym_not_in_execroot"
|
||||
dir7,three_level_sym_in_execroot,"${input_dir}/three_level_sym_in_execroot"
|
||||
" > ${bazel_apexer_wrapper_manifest_file}
|
||||
|
||||
#############################################
|
||||
# run bazel_apexer_wrapper
|
||||
#############################################
|
||||
"${RUNFILES_DIR}/__main__/build/bazel/rules/apex/bazel_apexer_wrapper" \
|
||||
--manifest ${manifest_file} \
|
||||
--file_contexts ${file_contexts_file} \
|
||||
--key "${RUNFILES_DIR}/__main__/build/bazel/rules/apex/test.pem" \
|
||||
--apexer_path ${apexer_tool_path} \
|
||||
--apexer_tool_paths ${apexer_tool_path}:${avb_tool_path} \
|
||||
--apex_output_file ${output_file} \
|
||||
--bazel_apexer_wrapper_manifest ${bazel_apexer_wrapper_manifest_file} \
|
||||
--android_jar_path ${android_jar}
|
||||
|
||||
#############################################
|
||||
# check the result
|
||||
#############################################
|
||||
"${apexer_tool_path}/deapexer" --debugfs_path="${apexer_tool_path}/debugfs" extract ${output_file} ${output_dir}
|
||||
|
||||
# The expected mounted tree should be something like this:
|
||||
# /tmp/tmp.9u7ViPlMr7
|
||||
# ├── apex_manifest.pb
|
||||
# ├── apex_payload.img
|
||||
# ├── mnt
|
||||
# │ ├── apex_manifest.pb
|
||||
# │ ├── dir1
|
||||
# │ │ └── file1
|
||||
# │ ├── dir2
|
||||
# │ │ └── dir3
|
||||
# │ │ └── file2
|
||||
# │ ├── dir4
|
||||
# │ │ └── one_level_sym
|
||||
# (one level symlinks always resolve)
|
||||
# │ ├── dir5
|
||||
# │ │ └── two_level_sym_in_execroot
|
||||
# (two level symlink resolve if the path contains execroot/__main__)
|
||||
# │ ├── dir6
|
||||
# │ │ └── two_level_sym_not_in_execroot -> /tmp/tmp.evJh21oYGG/file1
|
||||
# (two level symlink resolve only one level otherwise)
|
||||
# │ ├── dir7
|
||||
# │ │ └── three_level_sym_in_execroot
|
||||
# (three level symlink resolve if the path contains execroot/__main__)
|
||||
# └── test.apex
|
||||
|
||||
# b/215129834:
|
||||
# https://android-review.googlesource.com/c/platform/system/apex/+/1944264 made
|
||||
# it such that the hash of non-payload files in the APEX (like
|
||||
# AndroidManifest.xml) will be included as part of the apex_manifest.pb via the
|
||||
# apexContainerFilesHash string to ensure that changes to AndroidManifest.xml
|
||||
# results in changes in content hash for the apex_payload.img. Since this is
|
||||
# potentially fragile, we skip diffing the apex_manifest.pb, and just check that
|
||||
# it exists.
|
||||
test -f "${output_dir}/apex_manifest.pb" || echo "expected apex_manifest.pb to exist"
|
||||
|
||||
# check the contents with diff for the rest of the files
|
||||
diff ${input_dir}/file1 ${output_dir}/dir1/file1
|
||||
diff ${input_dir}/file2 ${output_dir}/dir2/dir3/file2
|
||||
diff ${input_dir}/file1 ${output_dir}/dir4/one_level_sym
|
||||
diff ${input_dir}/file2 ${output_dir}/dir5/two_level_sym_in_execroot
|
||||
[ `readlink ${output_dir}/dir6/two_level_sym_not_in_execroot` = "${input_dir}/file1" ]
|
||||
diff ${input_dir}/file2 ${output_dir}/dir7/three_level_sym_in_execroot
|
||||
|
||||
cleanup
|
||||
|
||||
echo "Passed for all test cases"
|
|
@ -0,0 +1,130 @@
|
|||
"""
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
load("//build/bazel/rules/cc:cc_library_shared.bzl", "CcStubLibrariesInfo")
|
||||
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
|
||||
|
||||
ApexCcInfo = provider(
|
||||
"Info needed to use CC targets in APEXes",
|
||||
fields = {
|
||||
"transitive_shared_libs": "File references to transitive .so libs produced by the CC targets and should be included in the APEX.",
|
||||
},
|
||||
)
|
||||
|
||||
# Return True if this target provides stubs that is equal to, or below, the
|
||||
# APEX's min_sdk_level.
|
||||
#
|
||||
# These stable ABI libraries are intentionally omitted from APEXes as they are
|
||||
# provided from another APEX or the platform. By omitting them from APEXes, we
|
||||
# ensure that there are no multiple copies of such libraries on a device.
|
||||
def has_cc_stubs(target, ctx):
|
||||
if ctx.rule.kind != "_cc_library_shared_proxy":
|
||||
# only _cc_library_shared_proxy contains merged CcStubLibrariesInfo providers
|
||||
# (a provider aggregating CcStubInfo and CcSharedLibraryInfo)
|
||||
return False
|
||||
|
||||
if len(target[CcStubLibrariesInfo].infos) == 0:
|
||||
# Not all shared library targets have stubs
|
||||
return False
|
||||
|
||||
# Minimum SDK version supported by the APEX that transitively depends on
|
||||
# this target.
|
||||
min_sdk_version = ctx.attr._min_sdk_version[BuildSettingInfo].value
|
||||
apex_name = ctx.attr._apex_name[BuildSettingInfo].value
|
||||
|
||||
available_versions = []
|
||||
|
||||
# Check that the shared library has stubs built for (at least) the
|
||||
# min_sdk_version of the APEX
|
||||
for stub_info in target[CcStubLibrariesInfo].infos:
|
||||
stub_version = stub_info["CcStubInfo"].version
|
||||
available_versions.append(stub_version)
|
||||
if stub_version <= min_sdk_version:
|
||||
return True
|
||||
|
||||
fail("cannot find a stub lib version for min_sdk_level %s (%s apex)\navailable versions: %s (%s)" %
|
||||
(min_sdk_version, apex_name, available_versions, target.label))
|
||||
|
||||
# Check if this target is specified as a direct dependency of the APEX,
|
||||
# as opposed to a transitive dependency, as the transitivity impacts
|
||||
# the files that go into an APEX.
|
||||
def is_apex_direct_dep(target, ctx):
|
||||
apex_direct_deps = ctx.attr._apex_direct_deps[BuildSettingInfo].value
|
||||
return str(target.label) in apex_direct_deps
|
||||
|
||||
def _apex_cc_aspect_impl(target, ctx):
|
||||
# Whether this dep is a direct dep of an APEX or makes a difference in dependency
|
||||
# traversal, and aggregation of libs that are required from the platform/other APEXes,
|
||||
# and libs that this APEX will provide to others.
|
||||
is_direct_dep = is_apex_direct_dep(target, ctx)
|
||||
|
||||
if has_cc_stubs(target, ctx):
|
||||
if is_direct_dep:
|
||||
# TODO(b/215500321): Mark these libraries as "stub-providing" exports
|
||||
# of this APEX, which the system and other APEXes can depend on,
|
||||
# and propagate this list.
|
||||
pass
|
||||
else:
|
||||
# If this is not a direct dep, and stubs are available, don't propagate
|
||||
# the libraries.
|
||||
#
|
||||
# TODO(b/215500321): In a bundled build, ensure that these libraries are
|
||||
# available on the system either via the system partition, or another APEX
|
||||
# and propagate this list.
|
||||
return [ApexCcInfo(transitive_shared_libs = depset())]
|
||||
|
||||
shared_object_files = []
|
||||
|
||||
# Transitive deps containing shared libraries to be propagated the apex.
|
||||
transitive_deps = []
|
||||
rules_propagate_src = ["_bssl_hash_injection", "stripped_shared_library", "versioned_shared_library"]
|
||||
|
||||
# Exclude the stripped and unstripped so files
|
||||
if ctx.rule.kind == "_cc_library_shared_proxy":
|
||||
for output_file in target[DefaultInfo].files.to_list():
|
||||
if output_file.extension == "so":
|
||||
shared_object_files.append(output_file)
|
||||
if hasattr(ctx.rule.attr, "shared"):
|
||||
transitive_deps.append(ctx.rule.attr.shared)
|
||||
elif ctx.rule.kind == "cc_shared_library" and hasattr(ctx.rule.attr, "dynamic_deps"):
|
||||
# Propagate along the dynamic_deps edge
|
||||
for dep in ctx.rule.attr.dynamic_deps:
|
||||
transitive_deps.append(dep)
|
||||
elif ctx.rule.kind in rules_propagate_src and hasattr(ctx.rule.attr, "src"):
|
||||
# Propagate along the src edge
|
||||
transitive_deps.append(ctx.rule.attr.src)
|
||||
|
||||
return [
|
||||
ApexCcInfo(
|
||||
# TODO: Rely on a split transition across arches to happen earlier
|
||||
transitive_shared_libs = depset(
|
||||
shared_object_files,
|
||||
transitive = [dep[ApexCcInfo].transitive_shared_libs for dep in transitive_deps],
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
# This aspect is intended to be applied on a apex.native_shared_libs attribute
|
||||
apex_cc_aspect = aspect(
|
||||
implementation = _apex_cc_aspect_impl,
|
||||
attrs = {
|
||||
"_min_sdk_version": attr.label(default = "//build/bazel/rules/apex:min_sdk_version"),
|
||||
"_apex_name": attr.label(default = "//build/bazel/rules/apex:apex_name"),
|
||||
"_apex_direct_deps": attr.label(default = "//build/bazel/rules/apex:apex_direct_deps"),
|
||||
},
|
||||
attr_aspects = ["dynamic_deps", "shared", "src"],
|
||||
# TODO: Have this aspect also propagate along attributes of native_shared_libs?
|
||||
)
|
|
@ -0,0 +1,260 @@
|
|||
"""
|
||||
Copyright (C) 2022 The Android Open Source Project
|
||||
|
||||
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.
|
||||
"""
|
||||
load("//build/bazel/rules:apex.bzl", "ApexInfo")
|
||||
|
||||
def _arch_transition_impl(settings, attr):
|
||||
"""Implementation of arch_transition.
|
||||
Four archs are included for mainline modules: x86, x86_64, arm and arm64.
|
||||
"""
|
||||
return {
|
||||
"x86": {
|
||||
"//command_line_option:platforms": "//build/bazel/platforms:android_x86",
|
||||
},
|
||||
"x86_64": {
|
||||
"//command_line_option:platforms": "//build/bazel/platforms:android_x86_64",
|
||||
},
|
||||
"arm": {
|
||||
"//command_line_option:platforms": "//build/bazel/platforms:android_arm",
|
||||
},
|
||||
"arm64": {
|
||||
"//command_line_option:platforms": "//build/bazel/platforms:android_arm64",
|
||||
},
|
||||
}
|
||||
|
||||
# Multi-arch transition.
|
||||
arch_transition = transition(
|
||||
implementation = _arch_transition_impl,
|
||||
inputs = [],
|
||||
outputs = [
|
||||
"//command_line_option:platforms",
|
||||
],
|
||||
)
|
||||
|
||||
# Arch to ABI map
|
||||
_arch_abi_map = {
|
||||
"arm64": "arm64-v8a",
|
||||
"arm": "armeabi-v7a",
|
||||
"x86_64": "x86_64",
|
||||
"x86": "x86",
|
||||
}
|
||||
|
||||
def _apex_proto_convert(ctx, arch, module_name, apex_file):
|
||||
"""Run 'aapt2 convert' to convert resource files to protobuf format."""
|
||||
# Inputs
|
||||
inputs = [
|
||||
apex_file,
|
||||
ctx.executable._aapt2,
|
||||
]
|
||||
|
||||
# Outputs
|
||||
filename = apex_file.basename
|
||||
pos_dot = filename.rindex(".")
|
||||
proto_convert_file = ctx.actions.declare_file("/".join([
|
||||
module_name,
|
||||
arch,
|
||||
filename[:pos_dot] + ".pb" + filename[pos_dot:]]))
|
||||
outputs = [proto_convert_file]
|
||||
|
||||
# Arguments
|
||||
args = ctx.actions.args()
|
||||
args.add_all(["convert"])
|
||||
args.add_all(["--output-format", "proto"])
|
||||
args.add_all([apex_file])
|
||||
args.add_all(["-o", proto_convert_file.path])
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = inputs,
|
||||
outputs = outputs,
|
||||
executable = ctx.executable._aapt2,
|
||||
arguments = [args],
|
||||
mnemonic = "ApexProtoConvert",
|
||||
)
|
||||
return proto_convert_file
|
||||
|
||||
def _apex_base_file(ctx, arch, module_name, apex_proto_file):
|
||||
"""Run zip2zip to transform the apex file the expected directory structure
|
||||
with all files that will be included in the base module of aab file."""
|
||||
|
||||
# Inputs
|
||||
inputs = [
|
||||
apex_proto_file,
|
||||
ctx.executable._zip2zip,
|
||||
]
|
||||
|
||||
# Outputs
|
||||
base_file = ctx.actions.declare_file("/".join([module_name, arch, module_name + ".base"]))
|
||||
outputs = [base_file]
|
||||
|
||||
# Arguments
|
||||
args = ctx.actions.args()
|
||||
args.add_all(["-i", apex_proto_file])
|
||||
args.add_all(["-o", base_file])
|
||||
abi = _arch_abi_map[arch]
|
||||
args.add_all([
|
||||
"apex_payload.img:apex/%s.img" % abi,
|
||||
"apex_build_info.pb:apex/%s.build_info.pb" % abi,
|
||||
"apex_manifest.json:root/apex_manifest.json",
|
||||
"apex_manifest.pb:root/apex_manifest.pb",
|
||||
"AndroidManifest.xml:manifest/AndroidManifest.xml",
|
||||
"assets/NOTICE.html.gz:assets/NOTICE.html.gz",
|
||||
])
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = inputs,
|
||||
outputs = outputs,
|
||||
executable = ctx.executable._zip2zip,
|
||||
arguments = [args],
|
||||
mnemonic = "ApexBaseFile",
|
||||
)
|
||||
return base_file
|
||||
|
||||
def _build_bundle_config(ctx, arch, module_name):
|
||||
"""Create bundle_config.json as configuration for running bundletool."""
|
||||
file_content = {
|
||||
"compression": {
|
||||
"uncompressed_glob": [
|
||||
"apex_payload.img",
|
||||
"apex_manifest.*",
|
||||
],
|
||||
},
|
||||
"apex_config": {},
|
||||
}
|
||||
bundle_config_file = ctx.actions.declare_file("/".join([module_name, "bundle_config.json"]))
|
||||
ctx.actions.write(bundle_config_file, json.encode(file_content))
|
||||
|
||||
return bundle_config_file
|
||||
|
||||
def _merge_base_files(ctx, module_name, base_files):
|
||||
"""Run merge_zips to merge all files created for each arch by _apex_base_file."""
|
||||
|
||||
# Inputs
|
||||
inputs = base_files + [ctx.executable._merge_zips]
|
||||
|
||||
# Outputs
|
||||
merged_base_file = ctx.actions.declare_file(module_name + "/" + module_name + ".zip")
|
||||
outputs = [merged_base_file]
|
||||
|
||||
# Arguments
|
||||
args = ctx.actions.args()
|
||||
args.add_all(["--ignore-duplicates"])
|
||||
args.add_all([merged_base_file])
|
||||
args.add_all(base_files)
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = inputs,
|
||||
outputs = outputs,
|
||||
executable = ctx.executable._merge_zips,
|
||||
arguments = [args],
|
||||
mnemonic = "ApexMergeBaseFiles",
|
||||
)
|
||||
return merged_base_file
|
||||
|
||||
def _apex_bundle(ctx, module_name, merged_base_file, bundle_config_file):
|
||||
"""Run bundletool to create the aab file."""
|
||||
|
||||
# Inputs
|
||||
inputs = [
|
||||
bundle_config_file,
|
||||
merged_base_file,
|
||||
ctx.executable._bundletool,
|
||||
]
|
||||
|
||||
# Outputs
|
||||
bundle_file = ctx.actions.declare_file(module_name + "/" + module_name + ".aab")
|
||||
outputs = [bundle_file]
|
||||
|
||||
# Arguments
|
||||
args = ctx.actions.args()
|
||||
args.add_all(["build-bundle"])
|
||||
args.add_all(["--config", bundle_config_file])
|
||||
args.add_all(["--modules", merged_base_file])
|
||||
args.add_all(["--output", bundle_file])
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = inputs,
|
||||
outputs = outputs,
|
||||
executable = ctx.executable._bundletool,
|
||||
arguments = [args],
|
||||
mnemonic = "ApexBundleFile",
|
||||
)
|
||||
return bundle_file
|
||||
|
||||
def _apex_aab_impl(ctx):
|
||||
"""Implementation of apex_aab rule, which drives the process of creating aab
|
||||
file from apex files created for each arch."""
|
||||
apex_base_files = []
|
||||
bundle_config_file = None
|
||||
module_name = ctx.attr.mainline_module[0].label.name
|
||||
for arch in ctx.split_attr.mainline_module:
|
||||
apex_file = ctx.split_attr.mainline_module[arch].files.to_list()[0]
|
||||
proto_convert_file = _apex_proto_convert(ctx, arch, module_name, apex_file)
|
||||
base_file = _apex_base_file(ctx, arch, module_name, proto_convert_file)
|
||||
apex_base_files.append(base_file)
|
||||
# It is assumed that the bundle config is the same for all products.
|
||||
if bundle_config_file == None:
|
||||
bundle_config_file = _build_bundle_config(ctx, arch, module_name)
|
||||
|
||||
merged_base_file = _merge_base_files(ctx, module_name, apex_base_files)
|
||||
bundle_file = _apex_bundle(ctx, module_name, merged_base_file, bundle_config_file)
|
||||
|
||||
return [DefaultInfo(files = depset([bundle_file]))]
|
||||
|
||||
# apex_aab rule creates Android Apk Bundle (.aab) file of the APEX specified in mainline_module.
|
||||
# There is no equivalent Soong module, and it is currently done in shell script by
|
||||
# invoking Soong multiple times.
|
||||
apex_aab = rule(
|
||||
implementation = _apex_aab_impl,
|
||||
attrs = {
|
||||
"mainline_module": attr.label(
|
||||
mandatory = True,
|
||||
cfg = arch_transition,
|
||||
providers = [ApexInfo],
|
||||
doc = "The label of a mainline module target",
|
||||
),
|
||||
"_allowlist_function_transition": attr.label(
|
||||
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
|
||||
doc = "Allow transition.",
|
||||
),
|
||||
"_zipper": attr.label(
|
||||
cfg = "host",
|
||||
executable = True,
|
||||
default = "@bazel_tools//tools/zip:zipper",
|
||||
),
|
||||
"_aapt2": attr.label(
|
||||
allow_single_file = True,
|
||||
cfg = "host",
|
||||
executable = True,
|
||||
default = "//prebuilts/sdk/tools:linux/bin/aapt2",
|
||||
),
|
||||
"_merge_zips": attr.label(
|
||||
allow_single_file = True,
|
||||
cfg = "host",
|
||||
executable = True,
|
||||
default = "//prebuilts/build-tools:linux-x86/bin/merge_zips",
|
||||
),
|
||||
"_zip2zip": attr.label(
|
||||
allow_single_file = True,
|
||||
cfg = "host",
|
||||
executable = True,
|
||||
default = "//prebuilts/build-tools:linux-x86/bin/zip2zip",
|
||||
),
|
||||
"_bundletool": attr.label(
|
||||
cfg = "host",
|
||||
executable = True,
|
||||
default = "//prebuilts/bundletool",
|
||||
),
|
||||
},
|
||||
)
|
|
@ -0,0 +1,51 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIJKgIBAAKCAgEAt4iSfTF+e2khGQf0bUzTMwWFsgaiQbwQB3cvyBlE9XekFXUt
|
||||
GdOEhC2J0p+930UoF6gjjRRrgGF+8K5iV1m3oEbB3qGz6UUOurvVkt4tq96e/Q5a
|
||||
ogCOZEuWHjZfs2tQUVNJJtptIp9+0cM768vdf+qnK2JNFIhBqSY0FhjVljKevMcM
|
||||
w2tWFRZnKPQ3JoRnWqi5CIauQtBcWRFKIApyf41uHGMjpQRd8aTGeLXBRTi/yD73
|
||||
HltuKwSF2SXpj1F+9j4stqskQvipjQnid/Wb+nN3CNgyrGuRrtGvz71WWYcK3DLM
|
||||
jvGLOl06QrN6a7ZfLUN4qQjJ6Is5SLTSw/sfFE7Fpcbg6/Geh+jSvChuo6EUtzoX
|
||||
Qu42HsVXhrJLQ9/AVTWNmGc9IDr4PMtDiQc4FN8MOpUtR6V/zwrZFoeR3PHl9Z7v
|
||||
uTxLIcQLIott0mAjPhbNgbFBs5HP1Z8TfFcyZWpShlx+aM1V2mzYQ7sgsWjFKMSQ
|
||||
wIUk/YZ9QK/H5WKjC5M0yxueCU0ocvWFaAZ4RyS/r/SUyQpvyNXNwUsdp1a8sNxp
|
||||
LP9U7FG64C+T791yoQJ0sKVbts5SEu/Tojw6miYbH6Fspdo2xxfCbrv6SAbkjlct
|
||||
afOnEepgTlHet0G+y0N7OZRJ9WRGyLJNgGjmmDy9XSYGAykwwe4Fv348D0cCAwEA
|
||||
AQKCAgBuFra/78NNpXbb++CK+20oCqTyb3Y+dd8rizuXDElH8Fb1JA9EkZLIckRc
|
||||
mcMbvPDal9mTU29UV6b8Ga4VdVRnCGpb76TqRKkcK3Vlnm3IzUWSx1xoFmtTD9/h
|
||||
CX6IMdPApHOZoaWbAg7hJfm4a9XWV9ukc1eG/GBeZPMTWhwr9vsugztNsQG2rnR8
|
||||
pVi7eupAADrVOWwn2bG7H1rWM04Q4rXswy7rWd48BzmhyGxA6FRpehNjGzbPCOx8
|
||||
n3gkpp7Ad/T8MVYT8fJKDmbQy/ue1EnPfVeQAwok0dRiiNDV7OH/yVzYVVzNSoSa
|
||||
4+uH1qHqlbE3u3TZT0GyMfzG38f4scsbvG/AhH1fuPsy4QcWyLlMV6KUnk3KPc3Q
|
||||
yOeRR82qndQMTYQ5/PFiilk7cNbTU0OBjuNpu/t1LIE2J2gGZ5Jw+g2NGtM/xsgC
|
||||
jOahpRYvZB8fZ/bSjirwwmSSU+v0ZoPDHtt75R/QxqwPG2jai8kaGr7GEXWJfrfv
|
||||
CktMnb6LoCyNiiiZSMUgdDHOQEkVNmt9fxiVaxsaIL4BygropwlD4WbuyRMevfYz
|
||||
EffvvmaqC24zJi8WzDszCNLgP/piNhXDyxZX+KaQXj0Do/tzWBBkO0OO6mVGOkX2
|
||||
6dadXfhOIggWO8K2lKCUKwWMO9LaKwSwZ4gzcc1a+U9rpE8kUQKCAQEA8lBGLzOL
|
||||
Ht8+d13SY+NdPbL6qGvoqsKd5BfIhaNbH04Cp2zQs2TWySxmV47df03pGUpQOCKn
|
||||
tFRxoczUrf1gfFDCCC95+A/crls8QJHG+MScTBH5U8Q0s9ReUo/0xaa55u77x5uS
|
||||
0fAtdnOdqP8/pf1fSXUJvyLW85LWdkge1c7jk7I5MnWVO2Ak9/GkuRgITSSgVdBa
|
||||
kr8nU1BCzDY0gOTWo5J1+NqqVH2eYfEI621iD4SAE3n2JrCC4K/Nt2enEJwup2TR
|
||||
ym15g9nClicUQP5Y67eDfqTZu1d0I0Ezl1tL8UPxcLI+ucN4V6KL8RvqTVMnGX/R
|
||||
s1FwkPVMQ6dKaQKCAQEAweZeggcSFukr+tTbnzDAHxg4YqiR+30wo7i8NadGu6W/
|
||||
EiAdcCdmZYMI9KKc+B/N3cuFqBnaSd7VM7XvINdwZRanRj56Ya8LvQMi0S9YPiRn
|
||||
T4TXC3EeewN5+SSO0Dkw83tW1PLqgSINy5ijBs5lGoIYMCC+GSA2DuRBiPpcfhqJ
|
||||
kmC9uFQvrsge8CC8Sb1wHCr0Wz34qhPoTff6ZV8wm11Jkb5+tT7PMS5Ft0sEBsxV
|
||||
R1JFtLNs0k/YpMb4/OrZFZZSIFCTUVPvHQ1/5BwumVnolBC4LORCaSk1xUOydU9h
|
||||
bZd4qzIpFteGLGGRT6nEWC1YejLAvcFHVJiKs1F2LwKCAQEAzgnwA8bCLvgIt5rx
|
||||
gLod2I7NkFRhPIHLm92VRf0HSHEe1Jo0Q7Yk5F56j00NjmgDItwLpg/hpfZ/wOLY
|
||||
nTFrz4kj0636+jESprcxXn4WQAV+GTjXVqDpZ1fW9EEwEriYLoNbV/kzOIwPPD9G
|
||||
+iJATrZJRb7dEMdhGy/qaB0fCxKmdDoBZKSSxjAUfzfbpv+GX4IbS5ykx07+81q1
|
||||
0crtjgQHdoLdCUN1ve4qtIEt4nHaBfPWq7jy0ycXwlH6jE74wajsCq4xrPy1bKXH
|
||||
TcHg+PrNRXF/wDoQYboVKL0ST0r0IixxqjAGIhLRy0KN1/CypBlmj8od12oSW1AZ
|
||||
DxW6sQKCAQEAtIMW8M5MVO/2dam8XFMySMBvncl5PjuqEIFnFjwIaaFAZEtpnIPR
|
||||
nCeFKtpIb+aL7TQP1hNbWPIOYfm6CUUH6dRRHeAEZvRjZS+KNlxxNkkFtM3itVA2
|
||||
JCd0YjFakxbrL4FfsRgEoPtnBGexPiDflvIOOqAA2btXGD3/lNofSXbDJHbTqMsX
|
||||
KQw9YSfYon2t5UtH+bmTyiKGXi/B+KXJxpnuZ7SEmY9DrHF7jcxUj0+jBKbfJf70
|
||||
DEcxVRW3rx2jw6kSA+t/enM9ZDqxGVfzOeit0UpPa9uEyAoJeQAxH20rMq+VMyub
|
||||
fRxgWOjsMtHFbKGqgPjG3uEU2vi4B4CLGQKCAQEA2Mr5f2AXPR8jca1+Id+CxZpU
|
||||
bgMML7gW31L4lGX9Teo9z+zSdN7sIwqe42Zla1N9wda8p5ribnJxwRdxcPL8bid5
|
||||
LLlls4xXD/jQCQCFL90X59Tm6VD6tm1VyCjL44nRwAqP4vJObSB5rTqJYtkfVmnp
|
||||
KERF5P0i5yv4Oox0ZOsThou9jtyl1dS50Td0Urhp4LhPdmpDPUq25K1sDDfnGFm6
|
||||
IcMPkVznRPUoKQCG9DSQcQqttkSV9Po+qfLa3aHtdndfe88Gd9uom8bsAMTZAfSZ
|
||||
D4YhqBHSLWrxvtQ8GxkaPITJv7hocwssdFRUj5/UJKJBgUXPBXEXh+fxlDaGQQ==
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1,70 @@
|
|||
"""
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
ApexToolchainInfo = provider(
|
||||
doc = "APEX toolchain",
|
||||
fields = [
|
||||
"aapt2",
|
||||
"avbtool",
|
||||
"apexer",
|
||||
"mke2fs",
|
||||
"resize2fs",
|
||||
"e2fsdroid",
|
||||
"sefcontext_compile",
|
||||
"conv_apex_manifest",
|
||||
"android_jar",
|
||||
"apex_compression_tool",
|
||||
"soong_zip",
|
||||
],
|
||||
)
|
||||
|
||||
def _apex_toolchain_impl(ctx):
|
||||
toolchain_info = platform_common.ToolchainInfo(
|
||||
toolchain_info = ApexToolchainInfo(
|
||||
aapt2 = ctx.file.aapt2,
|
||||
avbtool = ctx.attr.avbtool,
|
||||
apexer = ctx.file.apexer,
|
||||
mke2fs = ctx.attr.mke2fs,
|
||||
resize2fs = ctx.attr.resize2fs,
|
||||
e2fsdroid = ctx.attr.e2fsdroid,
|
||||
sefcontext_compile = ctx.file.sefcontext_compile,
|
||||
conv_apex_manifest = ctx.file.conv_apex_manifest,
|
||||
android_jar = ctx.file.android_jar,
|
||||
apex_compression_tool = ctx.file.apex_compression_tool,
|
||||
soong_zip = ctx.file.soong_zip,
|
||||
),
|
||||
)
|
||||
return [toolchain_info]
|
||||
|
||||
apex_toolchain = rule(
|
||||
implementation = _apex_toolchain_impl,
|
||||
attrs = {
|
||||
"aapt2": attr.label(allow_single_file = True, cfg = "host", executable = True),
|
||||
"avbtool": attr.label(cfg = "host", executable = True),
|
||||
"apexer": attr.label(allow_single_file = True, cfg = "host", executable = True),
|
||||
"mke2fs": attr.label(cfg = "host", executable = True),
|
||||
"resize2fs": attr.label(cfg = "host", executable = True),
|
||||
"e2fsdroid": attr.label(cfg = "host", executable = True),
|
||||
"sefcontext_compile": attr.label(allow_single_file = True, cfg = "host", executable = True),
|
||||
"conv_apex_manifest": attr.label(allow_single_file = True, cfg = "host", executable = True),
|
||||
"android_jar": attr.label(allow_single_file = True, cfg = "host"),
|
||||
"apex_compression_tool": attr.label(allow_single_file = True, cfg = "host", executable = True),
|
||||
# soong_zip is added as a dependency of apex_compression_tool which uses
|
||||
# soong_zip to compress APEX files. avbtool is also used in apex_compression tool
|
||||
# and has been added to apex toolchain previously.
|
||||
"soong_zip": attr.label(allow_single_file = True, cfg = "host", executable = True),
|
||||
},
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue