Add scripts to mount/unmount the Runtime APEX under ART's chroot dir.

These scripts (`tools/mount-buildbot-apexes.sh` and
`tools/unmount-buildbot-apexes.sh`) emulate the role of `apexd` under
the chroot directory for chroot-based on-device testing.

They currently only handle the Runtime APEX (com.android.runtime), but
we plan to use them to also activate/deactivate other packages
(required by ART's standalone test setup) in the future.

Also:
- Provide an `/apex' tmpfs under the choot directory as part of the
  device set-up.
- Build and push `unzip` during (chroot-based) on-device testing, as
  it is needed to extract payload (ext4 images) from APEX(ex).

Test: Manual local testing.
Bug: 121117762
Bug: 113373927
Bug: 34729697
Change-Id: Id1a7b3378ea5822c511d6cc74f784fa38ddd4968
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index da463d5..ce1a246 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -73,7 +73,7 @@
     exit 1
   fi
   make_command="make $j_arg $extra_args $showcommands build-art-target-tests $common_targets"
-  make_command+=" libjavacrypto-target libnetd_client-target linker toybox toolbox sh"
+  make_command+=" libjavacrypto-target libnetd_client-target linker toybox toolbox sh unzip"
   make_command+=" debuggerd su"
   make_command+=" libstdc++ "
   make_command+=" ${ANDROID_PRODUCT_OUT#"${ANDROID_BUILD_TOP}/"}/system/etc/public.libraries.txt"
@@ -81,8 +81,8 @@
     # These targets are needed for the chroot environment.
     make_command+=" crash_dump event-log-tags"
   fi
-  # Build the Runtime APEX.
-  make_command+=" com.android.runtime"
+  # Build the Debug Runtime APEX (which is a superset of the Release Runtime APEX).
+  make_command+=" com.android.runtime.debug"
   mode_suffix="-target"
 fi
 
diff --git a/tools/mount-buildbot-apexes.sh b/tools/mount-buildbot-apexes.sh
new file mode 100755
index 0000000..778d634
--- /dev/null
+++ b/tools/mount-buildbot-apexes.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 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.
+
+# Mount Android Runtime and Core Libraries APEX packages required in the chroot directory.
+# This script emulates some the actions performed by `apexd`.
+
+green='\033[0;32m'
+nc='\033[0m'
+
+# Setup as root, as some actions performed here require it.
+adb root
+adb wait-for-device
+
+# Exit early if there is no chroot.
+[[ -n "$ART_TEST_CHROOT" ]] || exit
+
+# Check that ART_TEST_CHROOT is correctly defined.
+[[ "$ART_TEST_CHROOT" = /* ]] || { echo "$ART_TEST_CHROOT is not an absolute path"; exit 1; }
+
+# Check that the "$ART_TEST_CHROOT/apex" directory exists.
+adb shell test -d "$ART_TEST_CHROOT/apex" \
+  || { echo "$ART_TEST_CHROOT/apex does not exist or is not a directory"; exit 1; }
+
+# Create a directory where we extract APEX packages' payloads (ext4 images)
+# under the chroot directory.
+apex_image_dir="/tmp/apex"
+adb shell mkdir -p "$ART_TEST_CHROOT$apex_image_dir"
+
+# activate_system_package APEX_PACKAGE APEX_NAME
+# ----------------------------------------------
+# Extract payload (ext4 image) from system APEX_PACKAGE and mount it as
+# APEX_NAME in `/apex` under the chroot directory.
+activate_system_package() {
+  local apex_package=$1
+  local apex_name=$2
+  local apex_package_path="/system/apex/$apex_package"
+  local abs_mount_point="$ART_TEST_CHROOT/apex/$apex_name"
+  local abs_image_filename="$ART_TEST_CHROOT$apex_image_dir/$apex_name.img"
+
+  # Make sure that the (absolute) path to the mounted ext4 image is less than
+  # 64 characters, which is a hard limit set in the kernel for loop device
+  # filenames (otherwise, we would get an error message from `losetup`, used
+  # by `mount` to manage the loop device).
+  [[ "${#abs_image_filename}" -ge 64 ]] \
+    && { echo "Filename $abs_image_filename is too long to be used with a loop device"; exit 1; }
+
+  echo -e "${green}Activating package $apex_package as $apex_name${nc}"
+
+  # Extract payload (ext4 image). As standard Android builds do not contain
+  # `unzip`, we use the one we built and sync'd to the chroot directory instead.
+  local payload_filename="apex_payload.img"
+  adb shell chroot "$ART_TEST_CHROOT" \
+    /system/bin/unzip -q "$apex_package_path" "$payload_filename" -d "$apex_image_dir"
+  # Rename the extracted payload to have its name match the APEX's name.
+  adb shell mv "$ART_TEST_CHROOT$apex_image_dir/$payload_filename" "$abs_image_filename"
+  # Check that the mount point is available.
+  adb shell mount | grep -q " on $abs_mount_point" && \
+    { echo "$abs_mount_point is already used as mount point"; exit 1; }
+  # Mount the ext4 image.
+  adb shell mkdir -p "$abs_mount_point"
+  adb shell mount -o loop,ro "$abs_image_filename" "$abs_mount_point"
+}
+
+# Activate the Android Runtime APEX.
+# Note: We use the Debug Runtime APEX (which is a superset of the Release Runtime APEX).
+activate_system_package com.android.runtime.debug.apex com.android.runtime
diff --git a/tools/setup-buildbot-device.sh b/tools/setup-buildbot-device.sh
index ef958d6..92b3672 100755
--- a/tools/setup-buildbot-device.sh
+++ b/tools/setup-buildbot-device.sh
@@ -165,4 +165,9 @@
   adb shell mkdir -p "$ART_TEST_CHROOT/dev"
   adb shell mount | grep -q "^tmpfs on $ART_TEST_CHROOT/dev type tmpfs " \
     || adb shell mount -o bind /dev "$ART_TEST_CHROOT/dev"
+
+  # Create /apex tmpfs in chroot.
+  adb shell mkdir -p "$ART_TEST_CHROOT/apex"
+  adb shell mount | grep -q "^tmpfs on $ART_TEST_CHROOT/apex type tmpfs " \
+    || adb shell mount -t tmpfs -o nodev,noexec,nosuid tmpfs "$ART_TEST_CHROOT/apex"
 fi
diff --git a/tools/teardown-buildbot-device.sh b/tools/teardown-buildbot-device.sh
index 6634fb4..7eb5cc3 100755
--- a/tools/teardown-buildbot-device.sh
+++ b/tools/teardown-buildbot-device.sh
@@ -89,6 +89,9 @@
            fi
     }
 
+    # Remove /apex from chroot.
+    remove_filesystem_from_chroot apex tmpfs true
+
     # Remove /dev from chroot.
     remove_filesystem_from_chroot dev tmpfs true
 
diff --git a/tools/unmount-buildbot-apexes.sh b/tools/unmount-buildbot-apexes.sh
new file mode 100755
index 0000000..8f0ad5f
--- /dev/null
+++ b/tools/unmount-buildbot-apexes.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 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.
+
+# Unmount Android Runtime and Core Libraries APEX packages required in the chroot directory.
+# This script emulates some the actions performed by `apexd`.
+
+# This script undoes the work done by tools/mount-buildbot-apexes.sh.
+# Make sure to keep these files in sync.
+
+green='\033[0;32m'
+nc='\033[0m'
+
+# Setup as root, as some actions performed here require it.
+adb root
+adb wait-for-device
+
+# Exit early if there is no chroot.
+[[ -n "$ART_TEST_CHROOT" ]] || exit
+
+# Check that ART_TEST_CHROOT is correctly defined.
+[[ "$ART_TEST_CHROOT" = /* ]] || { echo "$ART_TEST_CHROOT is not an absolute path"; exit 1; }
+
+# Directory containing extracted APEX packages' payloads (ext4 images) under
+# the chroot directory.
+apex_image_dir="/tmp/apex"
+
+# deactivate_system_package APEX_NAME
+# -----------------------------------
+# Unmount APEX_NAME in `/apex` under the chroot directory and delete the
+# corresponding APEX package payload (ext4 image).
+deactivate_system_package() {
+  local apex_name=$1
+  local abs_image_filename="$ART_TEST_CHROOT$apex_image_dir/$apex_name.img"
+  local abs_mount_point="$ART_TEST_CHROOT/apex/$apex_name"
+
+  echo -e "${green}Deactivating package $apex_name${nc}"
+
+  # Unmount the package's payload (ext4 image).
+  if adb shell mount | grep -q "^/dev/block/loop[0-9]\+ on $abs_mount_point type ext4"; then
+    adb shell umount "$abs_mount_point"
+    adb shell rmdir "$abs_mount_point"
+    # Delete the ext4 image.
+    adb shell rm "$abs_image_filename"
+  fi
+}
+
+# Deactivate the Android Runtime APEX.
+deactivate_system_package com.android.runtime
+
+# Delete the image's directory.
+adb shell rmdir "$ART_TEST_CHROOT$apex_image_dir"