Android-Studio开发系统应用

73 阅读4分钟

编译 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。 developer.android.google.cn/studio/arch…

SDK工具相关下载

androidsdkmanager.azurewebsites.net/ 比如下载 29.0.3 版本的 build tools: dl.google.com/android/rep… 解压缩重命名为 29.0.3 并放到 /home/{用户名}/Android/Sdk/build-tools 目录下。

创建项目

gradle 镜像国内配置: distributionUrl=mirrors.cloud.tencent.com/gradle/grad…

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')
    //.......
}

制作系统签名文件

github.com/getfatday/k… 签名工具 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