Full treble?
To make a device treble-compatible, just set PRODUCT_FULL_TREBLE_OVERRIDE := true and be done? But what does that even mean?
For treble requirements, see build/make/core/config.mk:
PRODUCT_TREBLE_LINKER_NAMESPACES
PRODUCT_SEPOLICY_SPLIT
PRODUCT_ENFORCE_VINTF_MANIFEST
PRODUCT_NOTICE_SPLIT
(PRODUCT_NOTICE_SPLIT is always true and cannot be altered)
Further requirements for devices launching on Oreo and up:
TARGET_COPY_OUT_VENDOR := vendor
BOARD_PROPERTY_OVERRIDES_SPLIT_ENABLED := true
BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
BOARD_USES_RECOVERY_AS_BOOT := true
BOARD_AVB_ENABLE := true
VNDK - Vendor Native Development Kit
Defining BOARD_VNDK_VERSION means the generated build will restrict access to
libraries to only those explicitly made available to vendor programs.
Usually you’d set it to current, meaning the latest VNDK version will be used.
You can test building with VNDK but disable it at runtime:
BOARD_VNDK_RUNTIME_DISABLE := false
There is much more to to it, read about the VNDK at source.android.com.
Linker namespaces
Example full-treble config:
BOARD_VNDK_VERSION := current
# BOARD_VNDK_VERSION obsoletes TREBLE_LINKER_NAMESPACES
PRODUCT_TREBLE_LINKER_NAMESPACES := false
c.f. system/core/rootdir/Android.mk:
_enforce_vndk_at_runtime := false
ifdef BOARD_VNDK_VERSION
ifneq ($(BOARD_VNDK_RUNTIME_DISABLE),true)
_enforce_vndk_at_runtime := true
endif
endif
[...]
ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt
_enforce_vndk_lite_at_runtime := false
ifeq ($(_enforce_vndk_at_runtime),false)
ifeq ($(PRODUCT_TREBLE_LINKER_NAMESPACES)|$(SANITIZE_TARGET),true|)
_enforce_vndk_lite_at_runtime := true
endif
endif
[...]
ld_config_template := $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt
# for legacy non-treblized devices
LOCAL_SRC_FILES := etc/ld.config.legacy.txt
So, to conclude linker paths stuff:
- Setting
BOARD_VNDK_VERSIONenforces usage of the latestld.config.txt(ld.config.28.txtfor Pie), unlessBOARD_VNDK_RUNTIME_DISABLEis set. This means_enforce_vndk_at_runtimeis set internally. - If
_enforce_vndk_at_runtimeis not set,PRODUCT_TREBLE_LINKER_NAMESPACESenforces usage ofld.config.vndk_lite.txt, which is less restrictive. - Not setting any of these props means
ld.config.legacy.txtis used, which is meant for pre-treble devices and very permissive.
More on linker namespaces at source.android.com.
vintf - Vendor Interface Manifest
After creating the device manifest, define DEVICE_MANIFEST_FILE and set
PRODUCT_ENFORCE_VINTF_MANIFEST_OVERRIDE := true as explained in
vintf: develop for a new device. This will alert you if you
a mismatch between HALs defined in the Device Manifest(DM) and those defined
in your Device Compatibility Matrix.
You can also be alerted if you have defined HALs in your manifest but not told
the framework about them in your Compatibility Matrix with
VINTF_ENFORCE_NO_UNUSED_HALS := true. This invokes assemble_vintf in strict
mode when checking at build time.
c.f. AssembleVintf.cpp(simplified here):
// If -c is provided, check it.
bool checkDualFile(const HalManifest& manifest, const CompatibilityMatrix& matrix) {
if (getBooleanFlag("PRODUCT_ENFORCE_VINTF_MANIFEST")) {
if (!manifest.checkCompatibility(matrix, &error)) {
std::cerr << "Not compatible: " << error << std::endl;
// Check HALs in device manifest that are not in framework matrix.
if (getBooleanFlag("VINTF_ENFORCE_NO_UNUSED_HALS")) {
auto unused = manifest.checkUnusedHals(matrix);
if (!unused.empty()) {
std::cerr << "Error: The following instances are in the device manifest but "
<< "not specified in framework compatibility matrix: " << std::endl
<< " " << android::base::Join(unused, "\n ") << std::endl
The other place PRODUCT_ENFORCE_VINTF_MANIFEST has an effect is with the
Android HIDL service manager (configured via
transport/Android.bp).
If ENFORCE_VINTF_MANIFEST is defined, bool vintfLegacy = false;
applies.
getRawServiceInternal(descriptor, instance, bool retry, bool getStub) {
[...]
#ifdef ENFORCE_VINTF_MANIFEST
bool vintfLegacy = false;
#else
bool vintfLegacy = (transport == Transport::EMPTY);
#endif
bool vintfHwbinder = (transport == Transport::HWBINDER);
bool vintfPassthru = (transport == Transport::PASSTHROUGH);
for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) {
if (getStub || vintfPassthru || vintfLegacy) {
Return<sp<IBase>> ret = sm->get(descriptor, instance);
[...]
waiter->done(); // exit loop
}
}
if (getStub || vintfPassthru || vintfLegacy) {
sp<IServiceManager> pm = getPassthroughServiceManager();
}
ENFORCE_VINTF_MANIFEST closes a loophole in getRawServiceInternal which
means libhidltransport will no longer fetch services which are not hwbinder
or passthrough, i.e. EMPTY transports will no longer be fetched.
To list all HALs and HAL services activity on-device, use the lshal command.
More on vintf at source.android.com.
Split SELinux policy
Pre-treble, the policy files for SElinux were situated on the ramdisk of the
boot partition1. They consisted of an sepolicy binary and file_contexts
files in the root directory ramdisk.
With PRODUCT_SEPOLICY_SPLIT_OVERRIDE set, the sepolicy binary will be split
up into platform(system) and vendor policy files. They policy is also no
longer a binary file but rather uses the new .cil plain-text format.
The platform .cil policy and context files will be pushed to
/system/etc/selinux/, while the vendor .cil policy and context files will
be pushed to /vendor/etc/selinux/.
Another change in behaviour when enabling the split is the effect of
not_full_treble() macros: With SEPOLICY_SPLIT set,
target_full_treble is set to true and the macros are now
simply ignored, i.e. all the policy that you inclosed in
not_full_treble(allow ...) statements is ignored.
There are also a lot of new neverallows introduced, so your policies might
need updating. Finally, three violator` attributes are now
banned:
binder_in_vendor_violatorssocket_between_core_and_vendor_violatorsvendor_executes_system_violators
More on implementing SELinux on source.android.com.
Compatible Properties
PRODUCT_COMPATIBLE_PROPERTY enables the whitelist for “compatible” properties,
meaning vendor services only get access to vendor-namespaced properties (with
some expections).
Manual override in device.mk:
PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE := true
Enabled by default for SHIPPING_API_LEVEL >= 28.
Side effects:
- service
ril-daemon->vendor.ril-daemon(see hardware/ril/rild/Android.mk: rild.legacy.rc withservice ril-daemonwhen non-compatible, rild.rc withservice vendor.ril-daemonwhen using compatible) - prop
rild.libpath->vendor.rild.libpath(see rild/rild.c) - prop
rild.libargs->vendor.rild.libargs compatible_property_only()andnot_compatible_property()sepolicy macros
In init, only whitelisted properties are “actionable”,
meaning they are allowed as triggers for e.g. on property:vendor.prop=1.
The whitelist - for init only - can be disabled at runtime by setting:
PRODUCT_ACTIONABLE_COMPATIBLE_PROPERTY_DISABLE := true
The whitelist resides in system/core/init/stable_properties.h and consists of a list of allowed prefixes and a list of allowed full property names.
Allowed prefixes(kPartnerPrefixes):
init.svc.vendor.ro.vendor.persist.vendor.vendor.init.svc.odm.ro.odm.persist.odm.odm.ro.boot.
Allowed exported actionable properties(kExportedActionableProperties):
dev.bootcompleteinit.svc.consoleinit.svc.mediadrminit.svc.surfaceflingerinit.svc.zygotepersist.bluetooth.btsnoopenablepersist.sys.crash_rcupersist.sys.usb.usbradio.configpersist.sys.zram_enabledro.board.platformro.bootmodero.build.typero.crypto.statero.crypto.typero.debuggablesys.boot_completedsys.boot_from_charger_modesys.retaildemo.enabledsys.shutdown.requestedsys.usb.configsys.usb.configfssys.usb.ffs.mtp.readysys.usb.ffs.readysys.user.0.ce_availablesys.vdsovold.decryptvold.post_fs_data_donevts.native_server.onwlan.driver.status
-
Exception: When using
system-as-root, thesepolicybinary was not on the boot ramdisk but rather on the root of thesystempartition. For more, see Gotcha: sepolicy for system-as-root devices. ↩︎