Experimental script for compiling after a module update
Adds an experimental script to run on device to recompile jars in the
boot class path and system server class path that are not in APEXes.
Bug: 160683548
Test: adb root; adb shell \
"set enforce 0; cd /data/local/tmp; /apex/com.android.art/bin/compile_bcp.sh"
Change-Id: I29d6a61508170e4f9fdc04fc384148b4b1f48870
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index b99742b..3639e13 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -118,12 +118,14 @@
// Tools exclusively for the device APEX derived from art-tools in art/Android.mk.
art_tools_device_only_binaries = [
+ "compile_bcp.sh",
// oatdump cannot link with host linux_bionic due to not using clang lld;
// TODO: Make it work with clang lld.
"oatdump",
]
// Same, but for only for debug packages.
art_tools_debug_device_only_binaries = [
+ "compile_bcp.sh",
// oatdumpd cannot link with host linux_bionic due to not using clang lld;
// TODO: Make it work with clang lld.
"oatdumpd",
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
index 2c40244..d959d3f 100755
--- a/build/apex/art_apex_test.py
+++ b/build/apex/art_apex_test.py
@@ -519,6 +519,7 @@
self._checker.check_file('apex_manifest.pb')
# Check binaries for ART.
+ self._checker.check_executable("compile_bcp.sh")
self._checker.check_first_executable('dex2oat')
self._checker.check_executable('dexdump')
self._checker.check_executable('dexlist')
@@ -613,6 +614,7 @@
# removed in Android R.
# Check binaries for ART.
+ self._checker.check_executable("compile_bcp.sh")
self._checker.check_executable('oatdump')
self._checker.check_multilib_executable('dex2oat')
diff --git a/tools/Android.bp b/tools/Android.bp
index 042eb19..f6733ce 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -74,3 +74,13 @@
},
},
}
+
+cc_prebuilt_binary {
+ name: "compile_bcp.sh",
+ host_supported: false,
+ srcs: ["compile_bcp.sh"],
+ apex_available: [
+ "com.android.art.debug",
+ "com.android.art.release",
+ ],
+}
diff --git a/tools/compile_bcp.sh b/tools/compile_bcp.sh
new file mode 100755
index 0000000..397456b
--- /dev/null
+++ b/tools/compile_bcp.sh
@@ -0,0 +1,178 @@
+#!/system/bin/sh
+#
+# 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.
+
+# Script to recompile the non-APEX jars in the boot class path and
+# system server jars for on-device signing following an ART Module
+# update.
+#
+# For testing purposes, prepare Android device using:
+#
+# $ adb root
+# $ adb shell setenforce 0
+#
+# TODO: this is script is currently for proof-of-concept. It does not
+# respect many of the available dalvik.vm properties, e.g. affinity,
+# threads, etc nor dalvik.vm.dex2oat-resolve-startup-strings.
+#
+# TODO: some of the system server jars seem to be installed on device
+# for 32-bit and 64-bit, but services.jar artifacts are just one arch.
+# Not sure why both flavors are present. Does this script need to generate
+# both?
+#
+# TODO: Logging failure / error handling.
+
+# Output directory for generated files. Real location is TBD.
+output=$PWD/out
+
+function mkdir_clean() {
+ # mkdir_clean <dir_path>
+ local dir_path=$1
+ rm -rf "${dir_path}"
+ mkdir -p "${dir_path}"
+}
+
+# Determine candidate architectures for this device.
+case `getprop ro.product.cpu.abi` in
+ arm*)
+ arch32=arm
+ arch64=arm64
+ ;;
+ x86*)
+ arch32=x86
+ arch64=x86_64
+ ;;
+ *)
+ echo "Unknown abi"
+ exit -1
+esac
+
+# Determine architectures to use for Zygote. system_server runs under the primary
+# architecture. Prefer dex2oat64 if device supports 64-bits.
+case $(getprop ro.zygote) in
+ zygote32)
+ # The primary architecture is 32-bits.
+ archs="$arch32"
+ systemserver_arch="$arch32"
+ dex2oat=/apex/com.android.art/bin/dex2oat32
+ ;;
+ zygote32_64)
+ # The primary architecture is 32-bits and the secondary is 64-bits.
+ archs="$arch32 $arch64"
+ systemserver_arch="$arch32"
+ dex2oat=/apex/com.android.art/bin/dex2oat64
+ ;;
+ zygote64_32)
+ # The primary architecture is 64-bits and the secondary is 32-bits.
+ archs="$arch32 $arch64"
+ systemserver_arch="$arch64"
+ dex2oat=/apex/com.android.art/bin/dex2oat64
+ ;;
+ zygote64)
+ # Primary architecture is 64-bits.
+ archs="$arch64"
+ systemserver_arch="$arch64"
+ dex2oat=/apex/com.android.art/bin/dex2oat64
+ ;;
+ *)
+ echo "Unknown ro.zygote value"
+ exit -1
+ ;;
+esac
+
+# Determine which boot class path jars to compile.
+device_bcp_list=""
+device_bcp_dex_files=""
+for jar in ${DEX2OATBOOTCLASSPATH//:/ }; do
+ if [[ ${jar} = *com.android.art* ]]; then
+ continue
+ fi
+ device_bcp_list="${device_bcp_list}${device_bcp_list:+:}${jar}"
+ device_bcp_dex_files="$device_bcp_dex_files --dex-file=${jar}"
+done
+
+# Compile the boot class path elements that are present on device.
+for arch in ${archs}; do
+ arch_output="${output}/$arch"
+ mkdir_clean "${arch_output}"
+
+ invocation_dir="${output}/$arch"
+ mkdir_clean "${invocation_dir}"
+
+ echo "Compiling ${device_bcp_list} ($arch)"
+ ${dex2oat} --avoid-storing-invocation \
+ --compiler-filter=speed-profile \
+ --profile-file=/system/etc/boot-image.prof \
+ --dirty-image-objects=/system/etc/dirty-image-objects \
+ --runtime-arg -Xbootclasspath:${DEX2OATBOOTCLASSPATH} \
+ --boot-image=/apex/com.android.art/javalib/boot.art \
+ ${device_bcp_dex_files} \
+ --generate-debug-info \
+ --image-format=lz4hc \
+ --strip \
+ --oat-file=${arch_output}/boot.oat \
+ --image=${arch_output}/boot.art \
+ --android-root=out/empty \
+ --abort-on-hard-verifier-error \
+ --instruction-set=$arch \
+ --generate-mini-debug-info
+done
+
+# Compile system_server and related jars.
+classloader_context=""
+for jar in ${SYSTEMSERVERCLASSPATH//:/ }; do
+ # Skip class path components in APEXes
+ if [[ ${jar} = "/apex"* ]]; then
+ continue
+ fi
+
+ # Add profile if it exists. Only services.jar has a profile in AOSP.
+ stem=$(basename $jar .jar)
+ profile_file=/system/framework/${stem}.jar.prof
+ if [ -f "${profile_file}" ] ; then
+ profile_arg=--profile-file=${profile_file}
+ filter=speed-profile
+ else
+ profile_arg=""
+ filter=speed
+ fi
+
+ # Add updatable boot class path packages file if there is a property for it.
+ updatable_bcp_file=$(getprop dalvik.vm.dex2oat-updatable-bcp-packages-file)
+ if [ "${updatable_bcp_file}" -a -f "${updatable_bcp_file}" ] ; then
+ updatable_bcp_file_arg="--updatable-bcp-packages-file=${updatable_bcp_file}"
+ fi
+
+ echo "Compiling ${jar} (${systemserver_arch} ${filter} PCL[${classloader_context}])"
+ $dex2oat --avoid-storing-invocation \
+ --runtime-arg -Xbootclasspath:${DEX2OATBOOTCLASSPATH} \
+ --class-loader-context=PCL[${classloader_context}] \
+ --boot-image=/apex/com.android.art/javalib/boot.art:${output}/boot-framework.art \
+ --dex-file=${jar} \
+ --oat-file=${arch_output}/${stem}.odex \
+ --app-image-file=${oat_file_dir}/${stem}.art \
+ --android-root=out/empty \
+ --instruction-set=${systemserver_arch} \
+ --abort-on-hard-verifier-error \
+ --compiler-filter=$filter \
+ --generate-mini-debug-info \
+ --compilation-reason=prebuilt \
+ --image-format=lz4 \
+ --resolve-startup-const-strings=true \
+ ${profile_arg} \
+ ${updatable_bcp_file_arg}
+
+ classloader_context=${classloader_context}${classloader_context:+:}${jar}
+done