Introduce link_type in AOSP build system
The Makefile in the AOSP 8.1 source code top directory, will include the build/core/main.mk:
### DO NOT EDIT THIS FILE ###
include build/core/main.mk
### DO NOT EDIT THIS FILE ###
And in build/core/main.mk, there is a verify script snippet:
$(foreach lt,$(ALL_LINK_TYPES),\
$(foreach d,$($(lt).DEPS),\
$(if $($(d).TYPE),\
$(call verify-link-type,$(lt),$(d)),\
$(call link-type-missing,$(lt),$(d)))))
The definition of verify-link-type is also in the build/core/main.mk:
# Verify that $(1) can link against $(2)
# Both $(1) and $(2) are the link type prefix defined above
define verify-link-type
$(foreach t,$($(2).TYPE),\
$(if $(filter-out $($(1).ALLOWED),$(t)),\
$(if $(filter $(t),$($(1).WARN)),\
$(call link-type-warning,$(1),$(2),$(t)),\
$(call link-type-error,$(1),$(2),$(t)))))
endef
ifdef link_type_error
$(error exiting from previous errors)
endif
a. If the module dependency TYPE is in the module’s TYPE allowed linked type list, it will pass the verify.
b. If the module dependency TYPE is not in the module’s TYPE allowed linked type, but it is in the WARN linked type list, it will print the warning info.
c. If the module dependency TYPE is not in the above both list, it will print the error info, and exit the building.
The ALLOWED, TYPE, WARN are initialized by build/make/core/link_type.mk:
# Inputs:
# LOCAL_MODULE_CLASS, LOCAL_MODULE, LOCAL_MODULE_MAKEFILE, LOCAL_BUILT_MODULE
# from base_rules.mk: my_kind, my_host_cross
# my_common: empty or COMMON, like the argument to intermediates-dir-for
# my_2nd_arch_prefix: usually LOCAL_2ND_ARCH_VAR_PREFIX, separate for JNI installation
#
# my_link_type: the tags to apply to this module
# my_warn_types: the tags to warn about in our dependencies
# my_allowed_types: the tags to allow in our dependencies
# my_link_deps: the dependencies, in the form of <MODULE_CLASS>:<name>
#
my_link_prefix := LINK_TYPE:$(call find-idf-prefix,$(my_kind),$(my_host_cross))$(if $(filter AUX,$(my_kind)),-$(AUX_OS_VARIANT)):$(if $(my_common),$(my_common):_,_:$(if $(my_2nd_arch_prefix),$(my_2nd_arch_prefix),_))
link_type := $(my_link_prefix):$(LOCAL_MODULE_CLASS):$(LOCAL_MODULE)
ALL_LINK_TYPES := $(ALL_LINK_TYPES) $(link_type)
$(link_type).TYPE := $(my_link_type)
$(link_type).MAKEFILE := $(LOCAL_MODULE_MAKEFILE)
$(link_type).WARN := $(my_warn_types)
$(link_type).ALLOWED := $(my_allowed_types)
$(link_type).DEPS := $(addprefix $(my_link_prefix):,$(my_link_deps))
$(link_type).BUILT := $(LOCAL_BUILT_MODULE)
link_type :=
my_allowed_types :=
my_link_prefix :=
my_link_type :=
my_warn_types :=
It’s very simple. The invoker should assign the my_link_type, my_warn_types, my_allowed_types,
and then include link_type.mk. For java module, the build/core/java_common.mk will do
the assign work:
ifndef LOCAL_IS_HOST_MODULE
ifeq ($(LOCAL_SDK_VERSION),system_current)
my_link_type := java:system
my_warn_types := java:platform
my_allowed_types := java:sdk java:system
else ifneq ($(LOCAL_SDK_VERSION),)
my_link_type := java:sdk
my_warn_types := java:system java:platform
my_allowed_types := java:sdk
else
my_link_type := java:platform
my_warn_types :=
my_allowed_types := java:sdk java:system java:platform
endif
my_link_deps := $(addprefix JAVA_LIBRARIES:,$(LOCAL_STATIC_JAVA_LIBRARIES))
my_link_deps += $(addprefix APPS:,$(apk_libraries))
my_2nd_arch_prefix := $(LOCAL_2ND_ARCH_VAR_PREFIX)
my_common := COMMON
include $(BUILD_SYSTEM)/link_type.mk
If the module is not host module, it will assign the link type to
the module based on the LOCAL_SDK_VERSION value.
a. If the LOCAL_SDK_VERSION is system_current, the module link type is java:system, and it can link to java:sdk and java:system without warning info. And it also can link to java:platform with warning info.
b. If the LOCAL_SDK_VERSION is other non-empty value, the module link type is java:sdk, and it can link to java:sdk without warning info. And it also can link to java:system and java:platform with warning info.
c. If the LOCAL_SDK_VERSION is empty or not defined, the module linke type is java:platform, and it can link to java:sdk, java:system and java:platform without warning info.
In the AOSP 9.0 source code, there are more restricted rules:
###########################################################
# Verify that all libraries are safe to use
###########################################################
ifndef LOCAL_IS_HOST_MODULE
ifeq ($(LOCAL_SDK_VERSION),system_current)
my_link_type := java:system
my_warn_types :=
my_allowed_types := java:sdk java:system java:core
else ifneq (,$(call has-system-sdk-version,$(LOCAL_SDK_VERSION)))
my_link_type := java:system
my_warn_types :=
my_allowed_types := java:sdk java:system java:core
else ifeq ($(LOCAL_SDK_VERSION),core_current)
my_link_type := java:core
my_warn_types :=
my_allowed_types := java:core
else ifneq ($(LOCAL_SDK_VERSION),)
my_link_type := java:sdk
my_warn_types :=
my_allowed_types := java:sdk java:core
else
my_link_type := java:platform
my_warn_types :=
my_allowed_types := java:sdk java:system java:platform java:core
endif
ifdef LOCAL_AAPT2_ONLY
my_link_type += aapt2_only
endif
ifdef LOCAL_USE_AAPT2
my_allowed_types += aapt2_only
endif
my_link_deps := $(addprefix JAVA_LIBRARIES:,$(LOCAL_STATIC_JAVA_LIBRARIES) $(LOCAL_JAVA_LIBRARIES))
my_link_deps += $(addprefix APPS:,$(apk_libraries))
my_2nd_arch_prefix := $(LOCAL_2ND_ARCH_VAR_PREFIX)
my_common := COMMON
include $(BUILD_SYSTEM)/link_type.mk
endif # !LOCAL_IS_HOST_MODULE
From the preceding code snippet, we can find AOSP 9.0 remove the warning type list,
so a java module only can link to module with the link type in its allowed type list.
Also it add a new link type called java:core and aapt2_only.
Okay, every build, the build system will ensure every module can only link to dependency
with the allowed link type. It will help to separate the system module and normal module.
For example, if an apk module assigns the LOCAL_SDK_VERSION with current, it should
be built with Android SDK without error, and it can’t link to system module with link
type java:platform to use the (hidden) system API. The app with link type java:sdk can
used to many AOSP code base have different version, such AOSP 8.1, AOSP 9.0, and
etc. It looks like a normal app, it just needs to process the Android SDK behavior change.
But for system app, it uses the system API, not exposed by Android SDK, so it should
evolve with the AOSP code base, what has more changes than Android SDK.
For system app developer, we should use less non-exposed system API to implement the
function, and use standard Android SDK API to implement. We can use
LOCAL_SDK_VERSION := current to check our API usage. It will reduce the difficulty
when porting system app to new AOSP version.