Android13 App 預裝詳解
- Android13 原始碼下載與編譯
- Android13 新增 Product
- Android13 自定義模組新增
- Android13 預編譯模組新增
- Android13 App 預裝詳解
- Android13系統App許可權配置
- Android13系統簽名
- Android13系統開發實用工具
1. 在系統中整合已編譯好的 apk
1.1 不可解除安裝的apk
不可解除安裝的 apk 一般是系統類應用,用於保證產品的基礎功能體驗例如 電話 簡訊 日曆 應用商店 瀏覽器等
Android Studio 新建一個 Empty Activity
專案 TestApp,編譯出 Debug Apk包,重新命名為 testapp.apk
在 device/Jelly/Rice14/prebuilt/apks
目錄下建立如下的檔案與目錄:
json
testapp/
├── Android.bp
└── testapp.apk
其中 testapp.apk 是我們使用 Android Studio 打包好的 apk 包,Android.bp 的內容如下:
```json android_app_import { name: "testapp",
//是否為特權應用
privileged: false,
//使用原來的簽名
presigned: true,
apk: "testapp.apk",
//安裝到 product 分割槽
product_specific: true,
} ```
然後修改 device/Jelly/Rice14/Rice14.mk
檔案內容,將 testapp 模組新增到產品中:
makefile
PRODUCT_PACKAGES += hello \
libmytriangle \
trianglemain \
busybox \
mymathmain \
testapp \
接下來,編譯專案,啟動虛擬機器:
bash
source build/envsetup.sh
lunch Rice14-eng
make -j16
emulator
然後再模擬器中就可以找到我們的 testapp 了:
開啟 testapp:
也可以使用 Android.mk 來整合:
```makefile LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := testapp
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_SRC_FILES := testapp.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
include $(BUILD_PREBUILT) ```
以上內容涉及到了 系統App、系統特權App以及系統簽名等概念,這裡有個印象即可,後面會有單獨的文章做詳細的說明。
1.2 可解除安裝的 apk
這類 apk 一般是廠商預裝好的一些第三方應用。
這部分內容涉及到了 selinux 與系統啟動相關的知識,在講解完這兩部分知識後,我們再回頭講解該部分內容。
1.3 可解除安裝但恢復出廠設定又恢復的 apk
這類 apk 一般是一些次重要的廠商 app,例如廠商自己的論壇,商城,智慧硬體等 app,如果第三方廠商給得足夠多,也可以將其配置為可解除安裝但恢復出廠設定又恢復的 apk。
這部分內容涉及到了 selinux 與系統啟動相關的知識,在講解完這兩部分知識後,我們再回頭講解該部分內容。
2. 在系統中整合App原始碼
2.1 簡單 App 原始碼的新增
使用 Android Studio 新建一個空專案 SourceApp,語言選擇 Java。建立完成後,將專案移動到 aosp/device/Jelly/Rice14
目錄下。在專案的根目錄下新增 Android.bp 檔案:
```json android_app { name: "SourceApp",
srcs: ["app/src/main/java/**/*.java"],
sdk_version: "current",
//LOCAL_PROGUARD_FLAG_FILES := proguard.flags
certificate: "platform",
// 指定Manifest檔案
manifest: "app/src/main/AndroidManifest.xml",
resource_dirs: ["app/src/main/res"],
//依賴
static_libs: ["androidx.appcompat_appcompat",
"androidx.recyclerview_recyclerview",
"com.google.android.material_material",
"androidx-constraintlayout_constraintlayout"],
} ```
修改 app/src/main/AndroidManifest.xml
```xml
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SourceApp"
tools:tar getApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>
```
修改的地方只有一個:給 manifest 節點添加了 package 屬性
接下來編譯系統,啟動虛擬機器就可以看到我們的 SourceApp 了
bash
source build/envsetup.sh
lunch Rice14-eng
make -j16
emulator
Android.bp 中我們添加了很多依賴:
static_libs: ["androidx.appcompat_appcompat",
"androidx.recyclerview_recyclerview",
"com.google.android.material_material",
"androidx-constraintlayout_constraintlayout"],
這些依賴模組最初定義在 SourceApp
的 build.gradle 中:
gradle
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
//測試相關的庫暫時不用管
}
在 AOSP 中, google 提供的庫和第三方提供的常用庫均以預編譯模組的方式定義在 prebuilt 目錄下。比如常用的 AndroidX 庫定義在 sdk/current/androidx
目錄下:
bash
~/aosp/prebuilts/sdk/current/androidx$ ls
Android.bp JavaPlugins.bp m2repository manifests
jar aar 庫以模組的形式引入編譯系統,這些模組就定義在上面的 Android.bp 中。比如 recyclerview 庫的定義如下:
json
android_library {
name: "androidx.recyclerview_recyclerview",
sdk_version: "31",
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
],
min_sdk_version: "14",
manifest: "manifests/androidx.recyclerview_recyclerview/AndroidManifest.xml",
static_libs: [
"androidx.recyclerview_recyclerview-nodeps",
"androidx.annotation_annotation",
"androidx.collection_collection",
"androidx.core_core",
"androidx.customview_customview",
],
java_version: "1.7",
}
當我們的系統應用需要引用一個庫時,我們應該首先考慮在 prebuilt 目錄下使用 find grep 命令搜尋。當我們需要的庫不存在時再自行引入相關的庫。
2.2 App 新增第三方依賴
在 App 的開發過程中,我們常常會引入一些第三方庫,這些庫可以分為以下三類:
- jar
- aar
- so
jar 包的引入
在Android13 預編譯模組新增中我們添加了一個 jar 庫:
json
java_import {
name: "libmytriangle",
host_supported: true,
installable: false,
jars: ["javalib.jar"],
}
上一節引入的 App, 稍作修改即可引入這個 jar 包:
```json android_app { name: "SourceApp",
srcs: ["app/src/main/java/**/*.java"],
sdk_version: "current",
//LOCAL_PROGUARD_FLAG_FILES := proguard.flags
certificate: "platform",
// 指定Manifest檔案
manifest: "app/src/main/AndroidManifest.xml",
resource_dirs: ["app/src/main/res"],
//依賴
static_libs: ["androidx.appcompat_appcompat",
"androidx.recyclerview_recyclerview",
"com.google.android.material_material",
"androidx-constraintlayout_constraintlayout"],
libs: [
"libmytriangle",
],
} ```
這裡的 static_libs 和 libs 可能有點難以區分,看看文件怎麼說的:
libs list of string , list of java libraries that will be in the classpath
static_libs list of string , list of java libraries that will be compiled into the resulting jar
翻譯一下就是 libs 引入的庫會被新增到 classpath 環境變數中,static_libs 引入的庫會打包到最終的產物中
aar包的引入
假設我們的 SourceApp 需要引入 lottie 這個動畫庫。
首先我們這裡下載好 lottie 庫的 aar 打包檔案。
在 device/Jelly/Rice14
目錄下建立如下的目錄結構:
bash
liblottie/
├── Android.bp
└── lottie-5.2.0.aar
其中 Android.bp 的內容如下:
bash
android_library_import {
name: "lib-lottie",
aars: ["lottie-5.2.0.aar"],
sdk_version: "current",
}
然後我們修改 SourceApp 中的 Android.bp:
json
static_libs: ["androidx.appcompat_appcompat",
"androidx.recyclerview_recyclerview",
"com.google.android.material_material",
"androidx-constraintlayout_constraintlayout",
"lib-lottie"],
這樣就匯入好了 lottie 庫
so包的引入
在Android13 預編譯模組新增中我們添加了一個 so 庫:
```json cc_prebuilt_library_shared { name: "libmymath",
arch: {
x86_64: {
srcs: ["libmymath.so"],
},
},
export_include_dirs: ["."],
compile_multilib: "64",
//註釋掉
//product_specific: true,
// product_available: true, 才能被我們的 app 引用
product_available: true,
} ```
我們修改 SourceApp 中的 Android.bp 引入 so 庫:
```json
android_app { name: "SourceApp", ...... jni_libs: [ "libmymath", ] //product_specific: true 才能引用到我們的 so 庫 product_specific: true, }
```
2.3 App 含有 jni native 程式碼
這個可以參考原始碼中的 development/samples/SimpleJNI
:
json
.
├── Android.bp
├── AndroidManifest.xml
├── jni
│ ├── Android.bp
│ └── native.cpp
└── src
└── com
└── example
└── android
└── simplejni
└── SimpleJNI.java
其中 jni/Android.bp:
```json package { default_applicable_licenses: ["Android-Apache-2.0"], }
cc_library_shared { name: "libsimplejni", // All of the source files that we will compile. srcs: ["native.cpp"], // All of the shared libraries we link against. shared_libs: ["liblog"], // No static libraries. static_libs: [], cflags: [ "-Wall", "-Werror", ], header_libs: ["jni_headers"], stl: "none", sdk_version: "current", }
```
Android.bp 的內容如下:
```json package { default_applicable_licenses: ["Android-Apache-2.0"], }
android_app { name: "SimpleJNI", srcs: ["*/.java"], jni_libs: ["libsimplejni"], optimize: { enabled: false, }, sdk_version: "current", dex_preopt: { enabled: false, }, }
```