编译 framework 模块
系统应用可以调用隐藏的API,开发时需要包含隐藏 API 的 jar 包。
源码下编译 Framework 模块来得到这个 jar 包:
source
lunch afra55-eng
# Android10 及以前
make framework
# Android11 及以后
#make framework-minus-apex
编译完成后,我们在 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates 目录下找到
classes.jar 文件,为方便识别,我们将该文件拷贝到其他地方,并将文件名修改为
framework.jar 。
Android Studio 下载
Android Studio 版本需要接近源码的发布日期最好。比如针对Android10源码,版本选择 3.6.3。
https://developer.android.google.cn/studio/archive?hl=zh-cn
SDK工具相关下载
https://androidsdkmanager.azurewebsites.net/
比如下载 29.0.3 版本的 build tools: https://dl.google.com/android/repository/build-tools_r29.0.3-linux.zip
解压缩重命名为 29.0.3 并放到 /home/{用户名}/Android/Sdk/build-tools 目录下。
创建项目
gradle 镜像国内配置:
distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-5.6.4-all.zip
AndroidManifest.xml 中添加系统应用标识
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:sharedUserId="android.uid.system">
android:sharedUserId="android.uid.system"
在Android应用的AndroidManifest.xml文件中,android:sharedUserId是一个属性,它允许你指定一个共享的用户ID,以便多个应用可以共享相同的Linux用户ID和相应的文件系统权限。
在Android系统中,每个应用都有一个唯一的用户ID(UID),这个UID决定了应用可以访问哪些系统资源和文件。
通过设置android:sharedUserId,你可以让多个应用共享同一个UID,这意味着这些应用在文件系统级别被视为同一个用户,可以共享数据、访问彼此的私有文件和组件(在合适权限设置下)。
数据共享: 允许不同应用访问和共享相同的数据存储,例如SharedPreferences、数据库文件等。
权限共享: 应用之间可以更方便地共享权限,例如如果一个应用获得了某个特权,其他共享同一UID的应用也可以利用这些权限。
组件访问: 在某些情况下,可以让一个应用直接启动或交互另一个应用的组件(Activity、Service等),而不需要通过Intent进行跨应用调用。
修改 build.gradle 中的 buildToolsVersion
compliteSdkVersion 29
buildToolsVersion "29.0.3"
minSdkVersion 29
targetSdkVersion 29
添加包含隐藏API的jar包
将上文的 framework.jar 拷贝到项目的 app/libs 文件夹中, 修改根 build.gradle :
Android studio 4.2 及以后:
allprojects{
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
Set<File> fileSet = options.bootstrapClasspath.getFiles()
List<File> newFileList = new ArrayList<>();
newFileList.add(new File("./app/libs/framework.jar"))
newFileList.addAll(fileSet)
options.bootstrapClasspath = files(
newFileList.toArray()
)
}
}
}
Android Studio 4.2 前包括Android Studio 3.x:
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
//相对位置,根据存放的位置修改路径
options.compilerArgs.add('-Xbootclasspath/p:app/libs/framework.jar')
}
}
}
并在应用级build.gradle添加依赖:
dependencies {
compileOnly files('libs/framework.jar')
//.......
}
制作系统签名文件
将 https://github.com/getfatday/keytool-importkeypair 签名工具 clone 到本地,并将其中的 keytool-importkeypair 文件添加到 PATH 路径。
接着进入系统源码下的 build/target/product/security 路径,接着执行:
keytool-importkeypair -k ./platform.keystore -p android -pk8 platform.pk8 -cert platform.x509.pem -alias platform
k 表示要生成的签名文件的名字,这里命名为 platform.keystore -p 表示要生成的 keystore 的密码,这里是 android -pk8 表示要导入的 platform.pk8 文件 -cert 表示要导入的platform.x509.pem -alias 表示给生成的 platform.keystore 取一个别名,这是命名为 platform。
接着,把生成的签名文件 platform.keystore 拷贝到 Android Studio 项目的 app 目录下,然后在 app/build.gradle 中添加签名的配置信息:
android {
signingConfigs {
sign {
storeFile file('platform.keystore')
storePassword 'android'
keyAlias = 'platform'
keyPassword 'android'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.sign
}
debug {
minifyEnabled false
signingConfig signingConfigs.sign
}
}
}
编译运行系统APP
在开发过程中,直接点击 Android Stuido 中的运行按钮来运行我们的配置好的 App。当我们的 App 开发完成,我们需要将其预制到系统中:
在系统源码下的 device/Victor/Afra55 目录下,创建如下的文件与文件夹:
Victor/
└── Afra55
├── Afra55.mk
├── AndroidProducts.mk
├── BoardConfig.mk
└── AsSystemApp
├── Android.mk
└── app.apk
其中 app.apk 是我们用 Android Studio 打包好的 apk 安装包。Android.mk 的内容如下(Android10 下,Android.bp 还不支持引入 apk, Android13 是没问题的):
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := AsSystemApp
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_SRC_FILES := app.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_PRODUCT_MODULE := true
include $(BUILD_PREBUILT)
修改 Afra55.mk:
PRODUCT_PACKAGES += \
AsSystemApp
然后编译系统,启动虚拟机,就可以看到 App 了。
source build/envsetup.sh
lunch Afra55-eng
make -j16
emulator
Product配置文件简述(对标 x86_64 模拟器 aosp_x86_64-eng)
BoardConfig.mk 用于定义和硬件相关的底层特性和变量,比如当前源码支持的 cpu 位数(64/32位),bootloader 和 kernel, 是否支持摄像头,GPS导航等一些板级特性。其中还通过 include 包含了 BoardConfigGsiCommon.mk 和 BoardConfigEmuCommon.mk 两个配置文件,前者用于通用系统映像的配置,后者用于模拟器的配置。主要和硬件相关,有一个基本的了解即可。一般很少改动。
# x86_64 emulator specific definitions
TARGET_CPU_ABI := x86_64
TARGET_ARCH := x86_64
TARGET_ARCH_VARIANT := x86_64
TARGET_2ND_CPU_ABI := x86
TARGET_2ND_ARCH := x86
TARGET_2ND_ARCH_VARIANT := x86_64
TARGET_PRELINK_MODULE := false
include build/make/target/board/BoardConfigGsiCommon.mk
include build/make/target/board/BoardConfigEmuCommon.mk
BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
BOARD_SEPOLICY_DIRS += device/generic/goldfish/sepolicy/x86
# Wifi.
BOARD_WLAN_DEVICE := emulator
BOARD_HOSTAPD_DRIVER := NL80211
BOARD_WPA_SUPPLICANT_DRIVER := NL80211
BOARD_HOSTAPD_PRIVATE_LIB := lib_driver_cmd_simulated
BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_simulated
WPA_SUPPLICANT_VERSION := VER_0_8_X
WIFI_DRIVER_FW_PATH_PARAM := "/dev/null"
WIFI_DRIVER_FW_PATH_STA := "/dev/null"
WIFI_DRIVER_FW_PATH_AP := "/dev/null"
AndroidProducts.mk 定义我们执行 lunch 命令时,打印的列表以及每个选项对应的配置文件
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/Afra55.mk
COMMON_LUNCH_CHOICES := \
Afra55-eng \
Afra55-userdebug \
Afra55-user
afra55.mk:产品配置
# 表示这个产品构建将使用动态分区。动态分区是 Android 10 引入的一种新特性,允许系统在运行时动态地管理分区,比如更新系统应用而不需要重新启动设备。
PRODUCT_USE_DYNAMIC_PARTITIONS := true
# The system image of aosp_x86_64-userdebug is a GSI for the devices with:
# - x86 64 bits user space
# - 64 bits binder interface
# - system-as-root
# - VNDK enforcement
# - compatible property override enabled
# This is a build configuration for a full-featured build of the
# Open-Source part of the tree. It's geared toward a US-centric
# build quite specifically for the emulator, and might not be
# entirely appropriate to inherit from for on-device configurations.
# GSI for system/product
$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/gsi_common.mk)
# Emulator for vendor
$(call inherit-product-if-exists, device/generic/goldfish/x86_64-vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/board/generic_x86_64/device.mk)
# Enable mainline checking for excat this product name
#ifeq (aosp_x86_64,$(TARGET_PRODUCT))
PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
#endif
PRODUCT_PACKAGES += AsSystemApp
PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
root/init.zygote32_64.rc \
root/init.zygote64_32.rc \
# Copy different zygote settings for vendor.img to select by setting property
# ro.zygote=zygote64_32 or ro.zygote=zygote32_64:
# 1. 64-bit primary, 32-bit secondary OR
# 2. 32-bit primary, 64-bit secondary
# init.zygote64_32.rc is in the core_64_bit.mk below
PRODUCT_COPY_FILES += \
system/core/rootdir/init.zygote32_64.rc:root/init.zygote32_64.rc
# Overrides, 定义了产品的品牌、名称、设备标识符和模型描述
PRODUCT_BRAND := Victor
PRODUCT_NAME := Afra55
PRODUCT_DEVICE := Afra55
PRODUCT_MODEL := Android SDK built for x86_64 Afra55