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.