Android Q Changes

Mainly to the build system

sepolicy

sepolicy has new neverallows.

ccache

ccache is no longer supported by default, the prebuilt ccache exec has been removed.

See build/core/ccache.mk:

We no longer provide a ccache prebuilt.

Ours was old, and had a number of issues that triggered non-reproducible results and other failures. Newer ccache versions may fix some of those issues, but at the large scale of our build servers, we weren’t seeing significant performance gains from using ccache – you end up needing very good locality and/or very large caches if you’re building many different configurations.

Local no-change full rebuilds were showing better results, but why not just use incremental builds at that point?

So if you still want to use ccache, continue setting USE_CCACHE, but also set the CCACHE_EXEC environment variable to the path to your ccache executable.

Install ccache and set export CCACHE_EXEC=/usr/bin/ccache in your ~/.bashrc.

Recovery needed for packaging OTAs

FAILED: ninja: unknown target 'otapackage'

To get OTA packaging for legacy devices to work via make otapackage, the target device needs to enable building a recovery image explicitly now.

PRODUCT_BUILD_RECOVERY_IMAGE := true

Since Android Pie/Q, certain OTA parameters are extracted from an intermediate recovery image.

Devices are now supposed to use BOARD_USES_RECOVERY_AS_BOOT and as such the build process - even for legacy devices that do not use recovery-as-boot - is now structured such that it creates the boot image by first contructing a recovery image and patching that.

On Pie, the recovery image was built if it wasn’t disabled explicitly:

# build/make/core/Makefile
ifeq (,$(filter true, $(TARGET_NO_KERNEL) $(TARGET_NO_RECOVERY)))
[... build recoveryimage]

On Q, building a recovery image must now be enabled since the recovery buildvars, including $(recovery_fstab), are guarded by BUILDING_RECOVERY_IMAGE.
See AOSP Gerrit: Add BUILD_RECOVERY_IMAGE and BUILD_BOOT_IMAGE flags.

# build/make/core/board_config.mk
ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
  BUILDING_RECOVERY_IMAGE := true
else ifeq ($(PRODUCT_BUILD_RECOVERY_IMAGE),)
  ifdef BOARD_RECOVERYIMAGE_PARTITION_SIZE
    ifeq (,$(filter true, $(TARGET_NO_KERNEL) $(TARGET_NO_RECOVERY)))
      BUILDING_RECOVERY_IMAGE := true
    endif
  endif
else ifeq ($(PRODUCT_BUILD_RECOVERY_IMAGE),true)
  BUILDING_RECOVERY_IMAGE := true
endif
# build/make/core/Makefile
[...]
ifdef BUILDING_RECOVERY_IMAGE
  [...]
  ifdef TARGET_RECOVERY_FSTAB
    recovery_fstab := $(TARGET_RECOVERY_FSTAB)
  else
    recovery_fstab := $(strip $(wildcard $(TARGET_DEVICE_DIR)/recovery.fstab))
  endif
  [...]
endif # BUILDING_RECOVERY_IMAGE

Since $(recovery_fstab) is needed by build_otatools_package, failing to enable the recovery image leads to the loss of the otapackage target. Simplified code:

# build/make/core/Makefile
[...]
build_ota_package := true
ifeq ($(recovery_fstab),)
  build_ota_package := false
endif
[...]
ifeq ($(build_ota_package),true)
  [...]
  .PHONY: otapackage
  otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)
[...]
endif # build_ota_package

PATH restrictions

If some of your makefiles call make, perl, gcc or some other host-installed tool directly, you will run into an error quite like this one:

Disallowed PATH tool "make" used: \
  []string{"make", "-j4", "-j8", "-C", "/home/[...]/kernel/", \
  "O=../../../../out/target/product/mydevice/obj/kernel/msm-4.9", \
  "ARCH=arm64", "CROSS_COMPILE=/home/[...]/aarch64-linux-android-", \
  "KCFLAGS=-mno-android"}
See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.

The stopgap solution is to set export TEMPORARY_DISABLE_PATH_RESTRICTIONS=true in your build environment, but it is worth exploring the reasons behind this.

Beginning to dig further, not even inspecting the PATH works:

builder@android:~/android$ get_build_var PATH

build/make/core/dumpvar.mk:29: error: PATH is obsolete. Do not use PATH directly.
See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH.
22:32:12 dumpvars failed with: exit status 1

One can modify build/make/core/config.mk to temporarily allow using PATH by commenting out this line:

$(KATI_obsolete_var PATH,Do not use PATH directly. See $(CHANGES_URL)#PATH)

So, why all this?

Reasons

With Android Q, Google has restricted the usage of tools in $PATH, ostensibly to cut down on too much variance in build environments. Now, usage of “host tools” 1 which are not shipped as checked-in prebuilts is heavily discouraged.

The $PATH that is visible to the makefiles inside the Android build system is now set via build/soong/ui/build/path.go and only consists of: prebuilts/build-tools/path/linux-x86:out/.path.

prebuilts/build-tools/path/linux-x86 is made up of symlinks to prebuilt common coreutils etc. such as awk, cat, cp, python and tar, some of which are provided via a host toybox.

.out/path/ is a bit more complicated. It only contains symlinks that all point to a go binary named path_interposer. This path_interposer - source here - checks whether the program the symlink points to is an allowed PATH tool. Which host tools are allowed is specified in soong/build/paths/config.go: They’re either Allowed, Forbidden, or allowed-but-logged(Log) (or some other obscure options).

Measures

As suggested in the Build System Changes advisory, one should stop relying on $PATH in makefiles directly, but if needed, commands can still be invoked with one-off environment variables:

$(OUT)/my-bin: $(MY_INTERMEDIATE)
	PATH=$$(cd device/ti/beagle_x15/hostcc; pwd):$$PATH \
	create-my-out-bin

As for invoking make, especially for kernels, using the full path to a prebuilt make binary instead of relying on the host /usr/bin/make fixes the issue. Google ships a prebuilt make in prebuilts/build-tools/.

# my-kernel.mk
MY_MAKE := \
	PATH="$(PWD)/prebuilts/my-prebuilts/bin:$$PATH" \
	$(PWD)/prebuilts/build-tools/linux-x86/bin/make
[...]
# Stop using $(MAKE) directly. Instead of:
#$(MAKE) -C $(OUT)/my-dir ...
# Use:
$(MY_MAKE) -C $(OUT)/my-dir ...

For more kernel-specific information, including how you can switch to clang, have a look at Android Q: Compiling Kernels in-tree.

More background info

See Google’s Dan Willemsen in answer to some MediaTek guys:

It’s easy to use prebuilt tools from the source directory (or built tools) from your own rules that need them, either just refer to them by name, or you may be able to set up your own directory to be added to PATH inside a rule:
beagle-x15 uboot.mk, beagle-x15 hostcc dir

We’re not going to add an extension that allows modifying the environment of every build command – that causes problems with the attempts to build common system images that aren’t influenced by the device. The common build commands should not need anything except our standard tools – if you’ve modified them, it should be easy enough to also add the dependency to the new tools as well.

On tools:

  • We’ve deprecated GCC during Android builds, we recommend clang for compilation.
  • We do have prebuilts of make and some other common tools in prebuilts/build-tools/linux-x86/bin
  • ccache is not something that we provide anymore – we’ve found it’s generally better to use incremental builds, as ccache can slow down your builds with extra I/O, and incremental builds should have relatively few cache hits (unless you’re sharing the ccache dir; which runs into even more I/O issues).

Perl is not something supported at Google, so we don’t provide that either – we do have built in support for python and the ability to use python packages from the source tree (or checked in as a prebuilt, when using embedded_launcher, it’s a self-contained binary): python_binary_host

GCC deprecation

GCC 4.9 is being ever more aggressively deprecated. A delay is added to every call to the prebuilt GCC and a warning is shown - Google cheekily calls this a “Sleep Constructor” 2.

Current plans: See GCC_4_9_DEPRECATION.md

  • January 2019
    • Move GCC binary to new file name.
    • Create shell wrapper with old GCC binary name that calls new binary name.
    • Shell wrapper print deprecation warning to stdout, with a link to more info.
  • April 2019
    • Move GCC binary name.
    • Add 1s sleep to wrapper.
  • July 2019
    • Move GCC binary name.
    • Total 3s sleep.
  • October 2019
    • Move GCC binary name.
    • Total 10s sleep.
  • January 2020
    • Remove GCC from Android.

New HALs

See: hardware/interfaces, system/hardware/interfaces, hardware/google/interfaces, frameworks/hardware/interfaces.


  1. “Host tools” meaning tools found in /usr/bin/* and other host $PATH locations. [return]
  2. See Compiling Android userspace and Linux Kernel with LLVM [return]

Published by