1.引入
本文主要讲解,针对Android源码开发,如何将自己的java library添加到Android系统的boot jar中
本文在编写的时候,针对的Android平台为Android Q (Android 10)
2.创建jar library仓库
该仓库主要包括以下两个动作:
- 将src中的java代码编译成jar包
- 编写permission文件,并且复制到system/etc下
2.1 编写BP文件
在过去的Android平台中,Bootjar是可以通过mk文件编写的,但是在Android P以后,必须通过bp文件编写,否则不允许添加到PRODUCT_BOOT_JARS 变量中!
如果你的项目是采用mk构建的,可以通过Androidmk工具直接转换成bp文件,至于如何使用Androidmk工具,请自行查询
BP文件内容如下:
// ==== library ========================
java_library {
name: "com.ruan.util",
installable: true,
srcs: ["src/**/*.java"],
optimize: {
enabled: false,
},
}
该BP内容很简单,name代表该jar包的名称;srcs代表代码路径,可以配置多路径;optimize代表是否需要混淆,建议不要混淆,否则可能会产生NoSuchMehotd,NoSuchField的问题,不过可以对部分不需要公开的代码进行混淆
2.2 编写permission文件
该文件是必须编写的,这个是让系统能够识别到你的jar包,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<permissions>
<library name="com.ruan.util"
file="/system/framework/com.ruan.util.jar"/>
</permissions>
同时需要编写对应的MK或者BP文件,将该permission文件copy至正确的路径下,我采用的是mk文件,内容如下:
LOCAL_PATH := $(call my-dir)
# ==== permissions ========================
include $(CLEAR_VARS)
LOCAL_MODULE := com.ruan.util.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/etc/permissions
LOCAL_SRC_FILES := permissions/$(LOCAL_MODULE)
include $(BUILD_PREBUILT)
代表将permission文件 copy至 system/etc/permission/路径下
3.添加到PRODUCT_BOOT_JARS和PRODUCT_PACKAGES
首先需要将该jar包和permission文件添加到PRODUCT_PACKAGES,否则不会带着你的编译
这个建议添加到项目集中的product_package中,具体的mk文件不做限制,只要能参与编译即可,内容如下:
PRODUCT_PACKAGES += com.ruan.util
PRODUCT_PACKAGES += com.ruan.util.xml
其次,添加到PRODUCT_BOOT_JARS中
PRODUCT_BOOT_JARS += com.ruan.util
我的建议是和上面的内容写到同一个mk文件中,当然,可以根据各自项目决定
4.白名单配置
这个只是代表你的jar包变成了bootjar,但是上层应用目前是无法使用它的,除非你给它定义了一个特殊的包名
原因是因为我们这个是给framework额外增加的jar包,默认是处于黑名单中的,上层在调用的时候,会出现NoSuchMethod或者NoSuchField的报错,解决这样的包括,有三种解决思路,根据各自的项目情况而决定:
4.1 调整调用者的签名
无论你的上层应用是apk集成的方式,还是代码集成的方式,都可以调整sign签名为platform,platform是可以直接访问hidden api的
这种方式适合你只是集成个别应用,并且这个应用最好是system级别的,因为一旦改成platform的签名,它的权限会非常大
4.2 将调用者添加到hidden api白名单
将调用者的包名登记到hidden api whitelist中,便可以在不改变签名的情况下,去访问该jar
但是加入到该白名单中,也就意味着该应用也能访问其他的hidden api,也是放大了权限,视项目情况而决定
4.3 将该jar包直接变成hidden api gray list
这个有两种操作方式,也是根据各自的项目而决定,如果你的jar包是需要完全暴露给上层的,那么你可以在frameworks/base/config/hiddenapi-greylist-packages.txt 中增加你的包名;如果你的jar包只是想暴露某些方法给上层,其他的方法你并不想暴露,那么你可以在hiddenapi-greylist-max-p.txt中配置你的方法
5.上层调用
上层调用分为两种方式:
1.你的上层是直接代码的形式,那么我建议直接采用LOCAL_JAVA_LIBRARY或者LOCAL_STATIC_JAVA_LIBRARY的方式去集成,这样也是非常方便的,至于二者的区别自行查询
2.你的上层是vendor提供的apk,你无法修改它的代码,那么需要注意的是,必须在该apk的AndroidManifest.xml文件中,定义uses-library,指向该库,否则可能存在无法使用的情况
6.可能碰到的问题
6.1 Class Not Found
检查uses-library
检查该jar包是否添加到了PRODUCT_BOOT_JARS 中
检查该jar包的白名单是否正确配置
6.2 No Such Method/No Such Field
检查该jar包的白名单是否正确配置
6.3 编译报错
Error: out/target/common/obj/JAVA_LIBRARIES/com.system.info_intermediates/classes.jar: unknown package name of class file com/system/info/SystemInfo.class
如果出现这样的错误,那么需要修改build/core/tasks/package_whitelist.txt,增加你的包名;这个报错跟你的包名有关,也跟Android平台有关