Android 新一代编译 toolchain Jack 初探

问题描述

昨天同事在项目中集成一个 aar 文件时遇到编译报错的问题,搜遍网络也没找到解决方案,最后抱着试试的心态发邮件给Google Jack team,意外的收到了回复,解决了问题,给 Jack team 大大的赞。
  aar(android archive)是Android项目的二进制归档文件,关于aar跟jar包的区别大家可以自行搜索。aar 文件的集成主要有 Android studio 环境下的集成和源码环境下的集成,我们关注的是后者。集成方案参考这篇文章 Android.mk引用aar文件。
Android.mk 修改如下:

+LOCAL_STATIC_JAVA_AAR_LIBRARIES += libsmf
+LOCAL_AAPT_FLAGS :=  --auto-add-overlay --extra-packages com.sprint.ms.smf
+
@@ -32,12 +37,24 @@ include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := optional
 LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
     com.redbend.android:libs/com.redbend.android.jar \
-    com.redbend.vdm.comm:libs/com.redbend.vdm.comm.jar
+    com.redbend.vdm.comm:libs/com.redbend.vdm.comm.jar \
+       libsmf:libs/libsmf-4.7.3.aar

编译报错如下:

com.android.sched.scheduler.RunnerProcessException: Error during 'CodeItemBuilder' runner on 'public java.util.List com.sprint.ms.smf.messaging.ShortCodeManager.getShortCodeInfo(@android.support.annotation.NonNull() com.sprint.ms.smf.oauth.OAuthToken token, java.lang.String mdn) (SourceFile:106-153)': no mapping specified for register
    at com.android.sched.scheduler.ScheduleInstance.runWithLog(ScheduleInstance.java:163)
    at com.android.sched.scheduler.MultiWorkersScheduleInstance$SequentialTask.process(MultiWorkersScheduleInstance.java:442)
    at com.android.sched.scheduler.MultiWorkersScheduleInstance$Worker.run(MultiWorkersScheduleInstance.java:162)
Caused by: java.lang.RuntimeException: no mapping specified for register
    at com.android.jack.dx.ssa.BasicRegisterMapper.map(BasicRegisterMapper.java:64)
    at com.android.jack.dx.ssa.RegisterMapper.map(RegisterMapper.java:53)
    at com.android.jack.dx.ssa.NormalSsaInsn.mapSourceRegisters(NormalSsaInsn.java:48)
    at com.android.jack.dx.ssa.SsaInsn.mapRegisters(SsaInsn.java:159)
    at com.android.jack.dx.ssa.SsaMethod.mapRegisters(SsaMethod.java:389)
    at com.android.jack.dx.ssa.back.SsaToRop.convert(SsaToRop.java:100)
    at com.android.jack.dx.ssa.back.SsaToRop.convertToRopMethod(SsaToRop.java:61)
    at com.android.jack.dx.ssa.Optimizer.optimize(Optimizer.java:107)
    at com.android.jack.dx.ssa.Optimizer.optimize(Optimizer.java:71)
    at com.android.jack.backend.dex.rop.CodeItemBuilder.run(CodeItemBuilder.java:373)
    at com.android.jack.backend.dex.rop.CodeItemBuilder.run(CodeItemBuilder.java:116)
    at com.android.sched.scheduler.ScheduleInstance.runWithLog(ScheduleInstance.java:161)
    ... 2 more

Internal compiler error (version 1.2-rc4 'Carnac' (298900 f95d7bdecfceb327f9d201a1348397ed8a843843 by [email protected])).
no mapping specified for register.

可以看到是在进行 Jack 编译时解析 Java8 语法报错。报错信息里很 nice 的包含了版本信息和联系邮箱。

关于JACK

关于Jack工具的介绍可以参考这篇文章Android 新一代编译 toolchain Jack & Jill 简介 , 基本是对官方文档的翻译。
  在14 March 2017,官方发布了一份废弃Jack的声明,原文如下:

At Google, we always try to do the right thing. Sometimes this means adjusting our plans. We know how much our Android developer community cares about good support for Java 8 language features, and we're changing the way we support them.

We've decided to add support for Java 8 language features directly into the current javac and dx set of tools, and deprecate the Jack toolchain. With this new direction, existing tools and plugins dependent on the Java class file format should continue to work. Moving forward, Java 8 language features will be natively supported by the Android build system. We're aiming to launch this as part of Android Studio in the coming weeks, and we wanted to share this decision early with you.

We initially tested adding Java 8 support via the Jack toolchain. Over time, we realized the cost of switching to Jack was too high for our community when we considered the annotation processors, bytecode analyzers and rewriters impacted. Thank you for trying the Jack toolchain and giving us great feedback. You can continue using Jack to build your Java 8 code until we release the new support. Migrating from Jack should require little or no work.

We hope the new plan will pave a smooth path for everybody to take advantage of Java 8 language features on Android. We'll share more details when we release the new support in Android Studio.

大概意思是推行 Jack 工具遇到了极大的困难,对Java 8 特性的支持方式将转向 javac和dx,将会在Android Studio中做相关支持。

问题解决

我们回到 Jack team 的回复(发送邮件到[email protected]),回复如下:

Hi,
Looks like invalid debug info in a prebuilt jar, you should try to ignore the debug info of the problematic jar (the one defining com.sprint.ms.smf.messaging.ShortCodeManager).

To ignore those debug info you should add "LOCAL_JACK_FLAGS := -D jack.import.jar.debug-info=false" to the Android.mk declaring it.
If the jar is declared with a BUILD_MULTI_PREBUILT, see https://android.googlesource.com/platform/external/jetty/+/3dddeb0b1333408963a5ec550cd9cc64cd9c646d%5E%21/#F0 as an exemple how to it.

链接里的内容如下:

Ignore debug info of jetty-util prebuilt
To workaround a Jack failure, possibly caused by malformed debug info.
Bug: 27242662
(cherry picked from commit d8b7db714ff75c37a6fe5b228a1373e9300022f0)
Change-Id:
I82bb302498abcad741a18e42f73cd2331233cc78

diff --git [a/Android.mk]
(https://android.googlesource.com/platform/external/jetty/+/806b0b93225bdf4a36d560351642126100e1950e/Android.mk) b/Android.mkindex f7ed668..d4859ec 100644--- a/Android.mk+++ b/Android.mk
@@ -48,8 +48,18 @@

LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES :=
servlet-api:lib/javax.servlet-3.0.0.v201112011016.jar
- jetty-util:lib/jetty-util-6.1.26.jar
slf4j-api:lib/slf4j-api-1.6.1.jar
slf4j-jdk14:lib/slf4j-jdk14-1.6.1.jar \

include $(BUILD_MULTI_PREBUILT)

+include $(CLEAR_VARS)

+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_MODULE := jetty-util
+LOCAL_SRC_FILES := lib/jetty-util-6.1.26.jar
+LOCAL_JACK_FLAGS := -D jack.import.jar.debug-info=false

+include $(BUILD_PREBUILT)

可以看到问题是jar包里无效的debug信息导致的,需要忽略掉debug信息。在 Android.mk 里添加 LOCAL_JACK_FLAGS := -D jack.import.jar.debug-info=false 这句;另外如果使用了 BUILD_MULTI_PREBUILT,需要将新增的 jar 改成单独的 BUILD_PREBUILT 的形式。
  尝试了以后发现还是报错,但是同事在include $(BUILD_PREBUILT)前加入了下面的语句后编译成功。

LOCAL_MODULE_SUFFIX := $(COMMON_JAVA_PACKAGE_SUFFIX)
LOCAL_BUILT_MODULE_STEM := javalib.jar
LOCAL_UNINSTALLABLE_MODULE := false 

总结

1 Jack 的目的是让 Android 支持更多的 Java 8 特性;
2 Google 将会把 Jack 的功能转移到 javac 和 dx 上;
3 如果遇到 Jack 相关的问题,可以邮件到 [email protected] 咨询;

你可能感兴趣的:(Android 新一代编译 toolchain Jack 初探)