1. 错误Pattern
编译错误原因:
/bin/bash -c "(mkdir -p out/target/common/obj/JAVA_LIBRARIES/TSWheelService_intermediates/classes.jack.tmpjill.res ) &&
(unzip -qo vendor/test/scripts/static_jar/./../../prebuilt/java/static_jar/TSWheelService.jar -d out/target/common/obj/JAVA_LIBRARIES/TSWheelService_intermediates/classes.jack.tmpjill.res ) &&
(find out/target/common/obj/JAVA_LIBRARIES/TSWheelService_intermediates/classes.jack.tmpjill.res -iname \"*.class\" -delete ) && (JACK_VERSION=4.32.CANDIDATE out/host/linux-x86/bin/jack @build/core/jack-default.args
-D jack.import.resource.policy=keep-first -D jack.import.type.policy=keep-first -D jack.android.min-api-level=1
--import vendor/chinatsp/scripts/static_jar/./../../prebuilt/java/static_jar/TSWheelService.jar --import-resource out/target/common/obj/JAVA_LIBRARIES/TSWheelService_intermediates/classes.jack.tmpjill.res --output-jack out/target/common/obj/JAVA_LIBRARIES/TSWheelService_intermediates/classes.jack ) && (rm -rf out/target/common/obj/JAVA_LIBRARIES/TSWheelService_intermediates/classes.jack.tmpjill.res )"
ERROR: src/com/test/proxy/test/TestManager.java:214: Default method void onPlayChange(int mode) not supported in Android API level less than 24
错误的位置是一个interface,使用了java1.8的default,报错是sdk小于24
@TestManager.java
public interface PlayStateChangedListener{
default void onPlayChange(int mode) {}
}
2. 错误原理
通过上面log有发现 jack.android.min-api-level=1 而这里要求jack api level要24
源码里搜索: jack.android.min-api-level
结果发现都是来自于PRIVATE_JACK_MIN_SDK_VERSION
build/make/core/definitions.mk
2329 -D jack.android.min-api-level=$(PRIVATE_JACK_MIN_SDK_VERSION) \
2377 -D jack.android.min-api-level=$(PRIVATE_JACK_MIN_SDK_VERSION) \
2397 -D jack.android.min-api-level=$(PRIVATE_JACK_MIN_SDK_VERSION) \
2515 -D jack.android.min-api-level=$(PRIVATE_JACK_MIN_SDK_VERSION) \
搜索: PRIVATE_JACK_MIN_SDK_VERSION
从下面结果看,赋值分为了两个,一个是java.mk 一个是prebuilt_internal.mk,分别对应源码编译static java library和prebuilt java lirary,这里的区别就导致了源码编译不会报错,预编译会报错问题
@build/make/core/
host_dalvik_java_library.mk
173 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_JACK_MIN_SDK_VERSION := $(PLATFORM_JACK_MIN_SDK_VERSION) macro
prebuilt_internal.mk
630 $(intermediates.COMMON)/classes.jack : PRIVATE_JACK_MIN_SDK_VERSION := $(if $(strip $(LOCAL_MIN_SDK_VERSION)),$(LOCAL_MIN_SDK_VERSION),1) macro
java.mk
409 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_JACK_MIN_SDK_VERSION := $(my_jack_min_sdk_version) macro
definitions.mk
2329 -D jack.android.min-api-level=$(PRIVATE_JACK_MIN_SDK_VERSION) \
2377 -D jack.android.min-api-level=$(PRIVATE_JACK_MIN_SDK_VERSION) \
2397 -D jack.android.min-api-level=$(PRIVATE_JACK_MIN_SDK_VERSION) \
2515 -D jack.android.min-api-level=$(PRIVATE_JACK_MIN_SDK_VERSION) \
从源码里看,LOCAL_MIN_SDK_VERSION不指定的话,PRIVATE_JACK_MIN_SDK_VERSION就为1,就导致jack.android.min-api-level=1 ,因此修改方法是在预编译时候把LOCAL_MIN_SDK_VERSION改为24就可以
ifdef LOCAL_JACK_ENABLED
//add log
$(warning william PRIVATE_JACK_MIN_SDK_VERSION LOCAL_MIN_SDK_VERSION $(LOCAL_MIN_SDK_VERSION))
# We may be building classes.jack from a host jar for host dalvik Java library.
$(intermediates.COMMON)/classes.jack : PRIVATE_JACK_FLAGS:=$(LOCAL_JACK_FLAGS)
$(intermediates.COMMON)/classes.jack : PRIVATE_JACK_MIN_SDK_VERSION := $(if $(strip $(LOCAL_MIN_SDK_VERSION)),$(LOCAL_MIN_SDK_VERSION),1)
$(intermediates.COMMON)/classes.jack : PRIVATE_JACK_PLUGIN_PATH := $(LOCAL_JACK_PLUGIN_PATH)
$(intermediates.COMMON)/classes.jack : PRIVATE_JACK_PLUGIN := $(LOCAL_JACK_PLUGIN)
$(intermediates.COMMON)/classes.jack : $(LOCAL_JACK_PLUGIN_PATH) $(my_src_jar) \
$(LOCAL_ADDITIONAL_DEPENDENCIES) $(JACK_DEFAULT_ARGS) $(JACK) \
| setup-jack-server
$(transform-jar-to-jack)
@echo "william Building with Jack PRIVATE_JACK_MIN_SDK_VERSION : $(PRIVATE_JACK_MIN_SDK_VERSION) -$(LOCAL_MIN_SDK_VERSION)-"
3. 修改方法
首先在预编译里面添加 LOCAL_MIN_SDK_VERSION := 24 结果还是报错
include $(CLEAR_VARS)
LOCAL_CERTIFICATE := platform
LOCAL_MIN_SDK_VERSION := 24
LOCAL_MODULE_TAGS := optional
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := SWheelService:./SWheelService.jack
include $(BUILD_MULTI_PREBUILT)
查看log,发现prebuilt_internal.mk里面LOCAL_MIN_SDK_VERSION是null,导致没有赋值成功
BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
auto-prebuilt-boilerplate方法中的第一步,就是执行CLEAR_VARS,就把LOCAL_MIN_SDK_VERSION清空了,后面的参数没有sdk,因此BUILD_MULTI_PREBUILT就失效,不起作用
@build/make/core/prebuilt_internal.mk
# $(1): file list
# $(2): IS_HOST_MODULE
# $(3): MODULE_CLASS
# $(4): MODULE_TAGS
# $(5): OVERRIDE_BUILT_MODULE_PATH
# $(6): UNINSTALLABLE_MODULE
# $(7): BUILT_MODULE_STEM
# $(8): LOCAL_STRIP_MODULE
#
# Elements in the file list may be bare filenames,
# or of the form "<modulename>:<filename>".
# If the module name is not specified, the module
# name will be the filename with the suffix removed.
#
define auto-prebuilt-boilerplate
$(if $(filter %: :%,$(1)), \
$(error $(LOCAL_PATH): Leading or trailing colons in "$(1)")) \
$(foreach t,$(1), \
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_IS_HOST_MODULE := $(2)) \
$(eval LOCAL_MODULE_CLASS := $(3)) \
$(eval LOCAL_MODULE_TAGS := $(4)) \
$(eval OVERRIDE_BUILT_MODULE_PATH := $(5)) \
$(eval LOCAL_UNINSTALLABLE_MODULE := $(6)) \
$(eval tw := $(subst :, ,$(strip $(t)))) \
$(if $(word 3,$(tw)),$(error $(LOCAL_PATH): Bad prebuilt filename '$(t)')) \
$(if $(word 2,$(tw)), \
$(eval LOCAL_MODULE := $(word 1,$(tw))) \
$(eval LOCAL_SRC_FILES := $(word 2,$(tw))) \
, \
$(eval LOCAL_MODULE := $(basename $(notdir $(t)))) \
$(eval LOCAL_SRC_FILES := $(t)) \
) \
$(if $(7), \
$(eval LOCAL_BUILT_MODULE_STEM := $(7)) \
, \
$(if $(word 2,$(tw)), \
$(eval LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)$(suffix $(LOCAL_SRC_FILES))) \
, \
$(eval LOCAL_BUILT_MODULE_STEM := $(notdir $(LOCAL_SRC_FILES))) \
) \
) \
$(eval LOCAL_MODULE_SUFFIX := $(suffix $(LOCAL_SRC_FILES))) \
$(eval LOCAL_STRIP_MODULE := $(8)) \
$(eval include $(BUILD_PREBUILT)) \
)
endef
最终写法是把BUILD_MULTI_PREBUILT改为BUILD_PREBUILT,从上面代码看,BUILD_MULTI_PREBUILT也是循环使用BUILD_PREBUILT的,使用BUILD_PREBUILTlog就显示为24,可以编译通过
include $(CLEAR_VARS)
LOCAL_MODULE := TSWheelService
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE_SUFFIX := $(COMMON_JAVA_PACKAGE_SUFFIX)
LOCAL_SRC_FILES := ./TSWheelService.jack
LOCAL_UNINSTALLABLE_MODULE := true
LOCAL_MIN_SDK_VERSION := 24
include $(BUILD_PREBUILT)
4.源码没有报错原理
上面有说源码使用的地方不一样,下面看最终使用的是PLATFORM_JACK_MIN_SDK_VERSION为o-b1,从注释看只是都是PLATFORM_SDK_VERSION := 27,因此不会报错
@build/make/core/java.mk
ifeq ($(LOCAL_SDK_VERSION),current)
my_jack_min_sdk_version := $(PLATFORM_JACK_MIN_SDK_VERSION)
else ifeq ($(LOCAL_SDK_VERSION),system_current)
my_jack_min_sdk_version := $(PLATFORM_JACK_MIN_SDK_VERSION)
else ifeq ($(LOCAL_SDK_VERSION),test_current)
my_jack_min_sdk_version := $(PLATFORM_JACK_MIN_SDK_VERSION)
else
my_jack_min_sdk_version := $(LOCAL_SDK_VERSION)
endif
$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_JACK_MIN_SDK_VERSION := $(my_jack_min_sdk_version)
@build/make/core/version_defaults.mk
ifndef PLATFORM_SDK_VERSION
PLATFORM_SDK_VERSION := 27
endif
ifndef PLATFORM_JACK_MIN_SDK_VERSION
# This is definition of the min SDK version given to Jack for the current
# platform. For released version it should be the same as
# PLATFORM_SDK_VERSION. During development, this number may be incremented
# before PLATFORM_SDK_VERSION if the platform starts to add new java
# language supports.
PLATFORM_JACK_MIN_SDK_VERSION := o-b1
endif