From 09f3b97f4b488cd3a7b7d72038b173575b02c162 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Fri, 23 Mar 2018 21:57:02 -0700 Subject: [PATCH] Add support for preopt with uses-libraries Required libraries are specified with LOCAL_USES_LIBRARIES Optional libraries are specified with LOCAL_OPTIONAL_USES_LIBRARIES The make rule cross references the libraries against what's stored in the manifest. Verification is enabled if LOCAL_ENFORCE_USES_LIBRARIES is true. This defaults to true if either of LOCAL_USES_LIBRARIES or LOCAL_OPTIONAL_USES_LIBRARIES are specified. Bug: 70934104 Bug: 67345922 Test: manual Change-Id: Ifca7d1a993620e9d0e42dc497a4a5d7a6c3f4172 --- core/clear_vars.mk | 3 ++ core/config.mk | 4 ++ core/construct_context.sh | 54 +++++++++++++++++++++++ core/dex_preopt_libart.mk | 18 +++++++- core/setup_one_odex.mk | 80 +++++++++++++++++++++++++++++++++-- core/verify_uses_libraries.sh | 45 ++++++++++++++++++++ 6 files changed, 198 insertions(+), 6 deletions(-) create mode 100755 core/construct_context.sh create mode 100755 core/verify_uses_libraries.sh diff --git a/core/clear_vars.mk b/core/clear_vars.mk index 1226e3a0d4..95a6553620 100644 --- a/core/clear_vars.mk +++ b/core/clear_vars.mk @@ -77,6 +77,7 @@ LOCAL_DROIDDOC_USE_STANDARD_DOCLET:= LOCAL_DX_FLAGS:= LOCAL_EMMA_COVERAGE_FILTER:= LOCAL_EMMA_INSTRUMENT:= +LOCAL_ENFORCE_USES_LIBRARIES:= LOCAL_ERROR_PRONE_FLAGS:= LOCAL_EXPORT_CFLAGS:= LOCAL_EXPORT_C_INCLUDE_DEPS:= @@ -183,6 +184,7 @@ LOCAL_NO_STATIC_ANALYZER:= LOCAL_NOTICE_FILE:= LOCAL_ODM_MODULE:= LOCAL_OEM_MODULE:= +LOCAL_OPTIONAL_USES_LIBRARIES:= LOCAL_OVERRIDES_PACKAGES:= LOCAL_OVERRIDES_MODULES:= LOCAL_PACKAGE_NAME:= @@ -271,6 +273,7 @@ LOCAL_UNINSTALLABLE_MODULE:= LOCAL_UNSTRIPPED_PATH:= LOCAL_USE_AAPT2:=$(USE_AAPT2) LOCAL_USE_VNDK:= +LOCAL_USES_LIBRARIES:= LOCAL_VENDOR_MODULE:= LOCAL_VTSC_FLAGS:= LOCAL_VTS_INCLUDES:= diff --git a/core/config.mk b/core/config.mk index 8a3e1f1267..20dbddc0e8 100644 --- a/core/config.mk +++ b/core/config.mk @@ -1026,6 +1026,10 @@ INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST := $(TARGET_OUT_COMMON_INTERMEDIATES) INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/hiddenapi-dark-greylist.txt INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/hiddenapi-blacklist.txt +# Missing optional uses-libraries so that the platform doesn't create build rules that depend on +# them. See setup_one_odex.mk. +INTERNAL_PLATFORM_MISSING_USES_LIBRARIES := com.google.android.ble com.google.android.wearable + # This is the standard way to name a directory containing prebuilt target # objects. E.g., prebuilt/$(TARGET_PREBUILT_TAG)/libc.so TARGET_PREBUILT_TAG := android-$(TARGET_ARCH) diff --git a/core/construct_context.sh b/core/construct_context.sh new file mode 100755 index 0000000000..b4ae519942 --- /dev/null +++ b/core/construct_context.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# +# Copyright (C) 2018 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 -e + +# inputs: +# $1 is PRIVATE_CONDITIONAL_USES_LIBRARIES_HOST +# $2 is PRIVATE_CONDITIONAL_USES_LIBRARIES_TARGET + +# class_loader_context: library paths on the host +# stored_class_loader_context_libs: library paths on device +# these are both comma separated paths, example: lib1.jar:lib2.jar or /system/framework/lib1.jar:/system/framework/lib2.jar + +# target_sdk_version: parsed from manifest +# my_conditional_host_libs: libraries conditionally added for non P +# my_conditional_target_libs: target libraries conditionally added for non P +# +# outputs +# class_loader_context_arg: final class loader conext arg +# stored_class_loader_context_arg: final stored class loader context arg + +my_conditional_host_libs=$1 +my_conditional_target_libs=$2 + +# Note that SDK 28 is P. +if [[ "${target_sdk_version}" -lt "28" ]]; then + if [[ -z "${class_loader_context}" ]]; then + export class_loader_context="${my_conditional_host_libs}" + else + export class_loader_context="${my_conditional_host_libs}:${class_loader_context}" + fi + if [[ -z "${stored_class_loader_context_libs}" ]]; then + export stored_class_loader_context_libs="${my_conditional_target_libs}"; + else + export stored_class_loader_context_libs="${my_conditional_target_libs}:${stored_class_loader_context_libs}"; + fi +fi + +# Generate the actual context string. +export class_loader_context_arg="--class-loader-context=PCL[${class_loader_context}]" +export stored_class_loader_context_arg="--stored-class-loader-context=PCL[${stored_class_loader_context_libs}]" diff --git a/core/dex_preopt_libart.mk b/core/dex_preopt_libart.mk index 572aa91f68..9c4d55de77 100644 --- a/core/dex_preopt_libart.mk +++ b/core/dex_preopt_libart.mk @@ -167,12 +167,26 @@ my_2nd_arch_prefix := # $(1): the input .jar or .apk file # $(2): the output .odex file +# In the case where LOCAL_ENFORCE_USES_LIBRARIES is true, PRIVATE_DEX2OAT_CLASS_LOADER_CONTEXT +# contains the normalized path list of the libraries. This makes it easier to conditionally prepend +# org.apache.http.legacy.boot based on the SDK level if required. define dex2oat-one-file $(hide) rm -f $(2) $(hide) mkdir -p $(dir $(2)) -$(hide) ANDROID_LOG_TAGS="*:e" $(DEX2OAT) \ +stored_class_loader_context_libs=$(PRIVATE_DEX2OAT_STORED_CLASS_LOADER_CONTEXT_LIBS) && \ +class_loader_context_arg=--class-loader-context=$(PRIVATE_DEX2OAT_CLASS_LOADER_CONTEXT) && \ +class_loader_context=$(PRIVATE_DEX2OAT_CLASS_LOADER_CONTEXT) && \ +stored_class_loader_context_arg="" && \ +uses_library_names="$(PRIVATE_USES_LIBRARY_NAMES)" && \ +optional_uses_library_names="$(PRIVATE_OPTIONAL_USES_LIBRARY_NAMES)" && \ +$(if $(PRIVATE_ENFORCE_USES_LIBRARIES), \ +source build/make/core/verify_uses_libraries.sh "$(1)" && \ +source build/make/core/construct_context.sh "$(PRIVATE_CONDITIONAL_USES_LIBRARIES_HOST)" "$(PRIVATE_CONDITIONAL_USES_LIBRARIES_TARGET)" && \ +,) \ +ANDROID_LOG_TAGS="*:e" $(DEX2OAT) \ --runtime-arg -Xms$(DEX2OAT_XMS) --runtime-arg -Xmx$(DEX2OAT_XMX) \ - --class-loader-context=$(PRIVATE_DEX2OAT_CLASS_LOADER_CONTEXT) \ + $${class_loader_context_arg} \ + $${stored_class_loader_context_arg} \ --boot-image=$(PRIVATE_DEX_PREOPT_IMAGE_LOCATION) \ --dex-file=$(1) \ --dex-location=$(PRIVATE_DEX_LOCATION) \ diff --git a/core/setup_one_odex.mk b/core/setup_one_odex.mk index e0d99264f0..51df43e34b 100644 --- a/core/setup_one_odex.mk +++ b/core/setup_one_odex.mk @@ -25,17 +25,89 @@ else my_dex_preopt_image_location := $($(my_2nd_arch_prefix)DEFAULT_DEX_PREOPT_BUILT_IMAGE_LOCATION) endif my_dex_preopt_image_filename := $(call get-image-file-path,$($(my_2nd_arch_prefix)DEX2OAT_TARGET_ARCH),$(my_dex_preopt_image_location)) + +# If LOCAL_ENFORCE_USES_LIBRARIES is not set, default to true if either of LOCAL_USES_LIBRARIES or +# LOCAL_OPTIONAL_USES_LIBRARIES are specified. +ifeq (,$(LOCAL_ENFORCE_USES_LIBRARIES)) +# Will change the default to true unconditionally in the future. +ifneq (,$(LOCAL_OPTIONAL_USES_LIBRARIES)) +LOCAL_ENFORCE_USES_LIBRARIES := true +endif +ifneq (,$(LOCAL_USES_LIBRARIES)) +LOCAL_ENFORCE_USES_LIBRARIES := true +endif +endif + +my_uses_libraries := $(LOCAL_USES_LIBRARIES) +my_optional_uses_libraries := $(LOCAL_OPTIONAL_USES_LIBRARIES) +my_missing_uses_libraries := $(INTERNAL_PLATFORM_MISSING_USES_LIBRARIES) + +# If we have either optional or required uses-libraries, set up the class loader context +# accordingly. +my_lib_names := +my_optional_lib_names := +my_filtered_optional_uses_libraries := +my_system_dependencies := +my_stored_preopt_class_loader_context_libs := +my_conditional_uses_libraries_host := +my_conditional_uses_libraries_target := + +ifneq (true,$(LOCAL_ENFORCE_USES_LIBRARIES)) + # Pass special class loader context to skip the classpath and collision check. + # This will get removed once LOCAL_USES_LIBRARIES is enforced. + # Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default + # to the &. + my_dex_preopt_class_loader_context := \& +else + # Compute the filtered optional uses libraries by removing ones that are not supposed to exist. + my_filtered_optional_uses_libraries := \ + $(filter-out $(my_missing_uses_libraries), $(my_optional_uses_libraries)) + my_filtered_uses_libraries := $(my_uses_libraries) $(my_filtered_optional_uses_libraries) + + # These are the ones we are verifying in the make rule, use the unfiltered libraries. + my_lib_names := $(my_uses_libraries) + my_optional_lib_names := $(my_optional_uses_libraries) + + # Calculate system build dependencies based on the filtered libraries. + my_intermediate_libs := $(foreach lib_name, $(my_lib_names) $(my_filtered_optional_uses_libraries), \ + $(call intermediates-dir-for,JAVA_LIBRARIES,$(lib_name),,COMMON)/javalib.jar) + my_dex_preopt_system_dependencies := $(my_intermediate_libs) + my_dex_preopt_class_loader_context := $(call normalize-path-list,$(my_intermediate_libs)) + + # The class loader context checksums are filled in by dex2oat. + my_stored_preopt_class_loader_context_libs := $(call normalize-path-list, \ + $(foreach lib_name,$(my_filtered_uses_libraries),/system/framework/$(lib_name).jar)) + + # Fix up org.apache.http.legacy.boot since it should be org.apache.http.legacy in the manifest. + my_lib_names := $(patsubst org.apache.http.legacy.boot,org.apache.http.legacy,$(my_lib_names)) + my_optional_lib_names := $(patsubst org.apache.http.legacy.boot,org.apache.http.legacy,$(my_optional_lib_names)) + ifeq (,$(filter org.apache.http.legacy,$(my_lib_names) $(my_optional_lib_names))) + my_conditional_uses_libraries_host := $(call intermediates-dir-for,JAVA_LIBRARIES,org.apache.http.legacy.boot,,COMMON)/javalib.jar + my_conditional_uses_libraries_target := /system/framework/org.apache.http.legacy.boot.jar + endif +endif + +# Always depend on org.apache.http.legacy.boot since it may get used by dex2oat-one-file for apps +# targetting