主要內容是Android AOSP源碼的管理方式,項目源碼的構建和編譯,用到比如git、repo、gerrit一些命令工具,以及使用Soong編譯系統,編寫Android.bp文件的格式樣式。
1. Android操作系統堆棧概述
Android 是一個針對多種不同設備類型打造的開放源代碼軟件堆棧。Android 的主要目的是為運營商、OEM 和開發者打造一個開放的軟件平臺,使他們能夠將創新理念變為現實,并推出能夠卓有成效地改善用戶移動體驗的真實產品。
Android 平臺的設計可確保不存在一個集中瓶頸,即沒有任何行業參與者可一手限制或控制其他參與者的創新。這樣,我們不但可以打造功能完善的高品質消費類產品,而且可以完全開放源代碼,供第三方自由定制和移植。
1.1. Android AOSP代碼管理
Google維護著多個代碼流水線,以便明確區分當前穩定版 Android 與不穩定的實驗性版本。將Android代碼流水線的開放源代碼管理和維護工作納入到了更大的產品開發周期中
- 在任何特定時刻,Android平臺都有一個當前最新版本。該版本通常作為樹中的一個分支
- 設備制造商和貢獻者會以當前最新版本為基礎來修復錯誤、發布新設備、試驗新功能等
- 與此同時,Google會根據產品的需求和目標,在內部開發下一版Android平臺和框架。與設備合作伙伴就旗艦設備展開合作來開發下一個Android版本,該旗艦設備的規格旨在推動Android朝著我們認為它應該選擇的方向發展
- 當第 n+1 版準備就緒時,它就會發布到公開源代碼樹,成為新的最新版本
1.2. 代號、標記和Build號
Android 開發版本按照英文字母的順序,采用美味甜點的名字為代號,劃分為不同的系列。
1.2.1. build ID定義
參考官方文檔
在Android 8.0.0 (Oreo)及更高版本中,每個build均采用build ID格式PVBB.YYMMDD.bbb[.Cn]
進行標識,其中:
- P 表示平臺版本代號的第一個字母,例如O表示Oreo
- V 表示支持的類別。按照慣例,P表示主要平臺分支
- BB 是由字母和數字組成的代碼,Google可通過該代碼識別build所屬的確切代碼分支
- YYMMDD 表示相應版本從開發分支細分出來或與開發分支同步的日期。它并不一定是build的確切構建日期,因為Google常常會在現有build中增加細微的更改,并在新build中重復使用與現有build相同的日期代碼
- bbb 表示具有相同日期代碼的不同版本,從001開始
- Cn 是可選的字母數字,表示在現有
PVBB.YYMMDD.bbb
build之上構建的修補程序,從A1開始
2. 構建下載源碼
2.1. ubuntu構建環境
如果是ubuntu 18.04的版本,則下載以下軟件:
sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig
2.2. 源碼控制工具
如需使用Android代碼,需要使用Git一種開源版本控制系統)和Repo(一種對Git構成補充的Google 代碼庫管理工具)
2.2.1. Git
參考git官方使用說明文檔
Git可以處理分布在多個代碼庫上的大型項目。Android使用Git執行本地操作,例如建立本地分支、提交、對比差異、修改
2.2.2. Repo
Repo可以在必要時整合多個Git代碼庫,將相關內容上傳到Gerrit(修訂版本控制系統),并自動執行Android開發工作流程的部分環節
Repo啟動器會提供一個Python腳本,該腳本可以初始化檢出,并可以下載第二部分,即完整的Repo工具。完整的Repo工具包含在Android源代碼檢出中。該工具默認位于$SRCDIR/.repo/repo/...
中,它可以從下載的Repo啟動器接收轉發的命令。
Repo不會取代Git,只是為了在Android環境中更輕松地使用Git。Repo使用清單文件(XML)將Git項目匯總到Android超級項目中。
在大多數情況下,可以僅使用Git(不必使用Repo),或結合使用Repo和Git命令以組成復雜的命令。不過,使用Repo執行基本的跨網絡操作可大大簡化您的工作
2.2.2.1. 安裝Repo
- 運行以下命令以使用您的 Linux 發行版中的官方軟件包:
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
sudo apt-get updatesudo apt-get install repo
- 查看版本號
repo version
2.2.2.2. 常用repo/git命令
命令 | 說明 |
---|---|
repo init | 初始化代碼 |
repo sync | 同步代碼 |
repo prune | 安全移除已過時的主題分支 |
repo start | 新建一個分支 |
repo status | 顯示當前分支的狀態 |
repo upload | 將更改上傳到審核服務器 |
git add | 暫存文件 |
git commit | 提交暫存的文件 |
git branch或repo branches | 顯示當前分支 |
git branch [branch] | 創建新的主題分支 |
git checkout [branch] | 將 HEAD 切換到指定分支 |
git merge [branch] | 將 [branch] 合并到當前分支 |
git diff | 顯示未暫存更改的 diff 結果 |
git diff –cached | 顯示已暫存更改的 diff 結果 |
git log | 顯示當前分支的歷史記錄 |
git log m/[codeline].. | 顯示未推送的提交 |
注意:如果存在錯誤,可能會導致repo sync
重置本地主題分支。如果在您運行 repo sync 之后,git branch
顯示*(無分支)
,請再次運行git checkout
2.2.2.3. repo命令
repo help init
:針對init獲取詳細的幫助說明repo init --help
:只列出init的使用參數列表
repo sync
使用說明:(repo help sync)
-c
:僅獲取服務器中的當前清單分支-d
:將指定項目切換回清單修訂版本。如果項目當前屬于某個主題分支,但臨時需要清單修訂版本,則此選項會有所幫助-f
:即使某個項目同步失敗,也繼續同步其他項目-jthreadcount
:將同步操作拆分成多個線程,以更快地完成。確保不會使計算機超負荷運行-為其他任務預留一些 CPU。如需查看可用CPU的數量,請先運行:nproc --all
-q
:通過抑制狀態消息來確保運行過程沒有干擾-s
:同步到當前清單中的manifest-server元素指定的一個已知良好build
2.2.3. Gerrit
Gerrit是一個基于網頁的代碼審核系統,適用于使用Git的項目。Gerrit允許所有授權用戶提交更改(如果這些更改通過代碼審核,便會自動納入到項目中),以此鼓勵他們更集中地使用 Git。此外,Gerrit會在瀏覽器中并排顯示更改,并支持代碼內注釋,從而使審核工作變得非常輕松。
2.2.4. Android Studio
一個用于開發 Android 應用的官方集成開發環境 (IDE)工具軟件
2.2.5. Android 調試橋 (adb)
可將開發工作站直接與相應 Android 設備關聯,以便安裝軟件包和評估更改
2.3. 下載源碼
2.3.1. 初始化repo客戶端
- 使用mkdir創建工作文件夾目錄
- 配置git用戶名和email
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
git config --global user.name Your Name
git config --global user.email you@example.com
- 運行
repo init
獲取最新版本的repo
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
repo init -u https://android.googlesource.com/platform/manifest# 初始化某分支
repo init -u https://android.googlesource.com/platform/manifest -b master
2.3.2. python版本依賴
如果報錯/usr/bin/env 'python' no such file or directory
,則需要軟鏈接python版本:
sudo ln -s /usr/bin/python3 /usr/bin/python
2.3.3. 下載Android源代碼樹
使用repo sync
下載源代碼到工作目錄
如果需要加快速度,使用-c
當前分支,和-j threadcount
線程數標記:repo sync -c -j8
2.4. Soong編譯系統
在Android7.0發布之前,Android僅使用GNUMake描述和執行其構建規則。Make構建系統得到了廣泛的支持和使用,但在Android層面變得緩慢、容易出錯、無法擴展且難以測試。Soong構建系統正好提供了Androidbuild所需的靈活性
2.4.1. Make和Soong比較(Android.mk和Android.bp)
Make示例:
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)
LOCAL_MODULE := libxmlrpc++
LOCAL_MODULE_HOST_OS := linuxLOCAL_RTTI_FLAG := -frtti
LOCAL_CPPFLAGS := -Wall -Werror -fexceptions
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/srcLOCAL_SRC_FILES := $(call \all-cpp-files-under,src)
include $(BUILD_SHARED_LIBRARY)
Soong示例:
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
cc_library_shared {name: “libxmlrpc++”,rtti: true,cppflags: [“-Wall”,“-Werror”,“-fexceptions”,],export_include_dirs: [“src”],srcs: [“src/**/*.cpp”],target: {darwin: {enabled: false,},},
}
2.4.2. Android.bp文件格式
根據設計,Android.bp文件很簡單。它們不包含任何條件語句,也不包含控制流語句;所有復雜問題都由用Go編寫的構建邏輯處理。
2.4.2.1. 模塊
Android.bp文件中的模塊以模塊類型開頭,后跟一組name: "value"
, 格式的屬性:
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
cc_binary {/* 每個模塊必須具有name屬性,并且值唯一(僅有兩個例外情況是命名空間和預構建模塊中的 Android.bp 屬性值,這兩個值可能會重復)*/name: "gzip",// srcs屬性以字符串列表的形式指定用于構建模塊的源文件// 可以使用模塊引用語法 ":<module-name>" 來引用生成源文件的其他模塊的輸出,如 genrule或filegroupsrcs: ["src/test/minigzip.c"],shared_libs: ["libz"],stl: "none",
}
2.4.2.2. 類型
變量和屬性是強類型,變量根據第一項賦值動態變化,屬性由模塊類型靜態設置。支持的類型為:
映射可以包含任何類型的值,包括嵌套映射。列表和映射可能在最后一個值后面有終止逗號。
- 布爾值(true 或 false)
- 整數 (int)
- 字符串 (“string”)
- 字符串列表 (
["string1", "string2"]
) - 映射 (
{key1: "value1", key2: ["value2"]}
)
2.4.2.3. 支持Glob(正則)
接受文件列表的屬性(例如 srcs)也可以采用glob模式。
glob模式可以包含普通的UNIX通配符*
,例如*.java
。glob模式還可以包含單個**
通配符作為路徑元素,與零個或多個路徑元素匹配。例如,java/**/*.java
同時匹配java/Main.java 和 java/com/android/Main.java
模式
2.4.2.4. 變量
變量的作用域限定在聲明它們的文件的其余部分,以及所有子Blueprint文件。變量是不可變的,但有一個例外情況:可以使用
+=
賦值將變量附加到別處,但只能在引用它們之前附加
Android.bp文件可能包含頂級變量賦值:
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
// 定義變量
gzip_srcs = ["src/test/minigzip.c"],
cc_binary {name: "gzip",// 引用變量srcs: gzip_srcs,shared_libs: ["libz"],stl: "none",
}
2.4.2.5. 注釋
Android.bp因為本質上是go語言,所以文件可以包含C樣式的多行/* */
注釋以及C++樣式的單行//
注釋
2.4.2.6. 運算符
可以使用+
運算符附加字符串、字符串列表和映射。
可以使用+
運算符對整數求和。附加映射會生成兩個映射中鍵的并集,并附加在兩個映射中都存在的所有鍵的值
2.4.2.7. 條件語句
Soong不支持Android.bp文件中的條件語句。
但是,編譯規則中需要條件語句的復雜問題將在Go在這種語言中,您可以使用高級語言功能,并且可以跟蹤條件語句引入的隱式依賴項)中處理。
大多數條件語句都會轉換為映射屬性,其中選擇了映射中的某個值并將其附加到頂級屬性。
例如,要支持特定于架構的文件,請使用以下命令:
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
cc_library {...srcs: ["generic.cpp"],arch: {arm: {srcs: ["arm.cpp"],},x86: {srcs: ["x86.cpp"],},},
}
2.4.2.8. [實用]格式設置工具bpfmt
Soong包含一個針對Blueprint文件的規范格式設置工具,類似于gofmt
。
如需以遞歸方式重新設置當前目錄中所有Android.bp文件的格式,請運行以下命令:
bpfmt -w .
PS:規范格式包括縮進四個空格、多元素列表的每個元素后面有換行符,以及列表和映射末尾有英文逗號
2.4.3. 特殊模塊
2.4.3.1. 默認模塊
默認模塊可用于在多個模塊中重復使用相同的屬性。例如:
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
//默認模塊定義
cc_defaults {name: "gzip_defaults",shared_libs: ["libz"],stl: "none",
}//引用默認模塊
cc_binary {name: "gzip",defaults: ["gzip_defaults"],srcs: ["src/test/minigzip.c"],
}
2.4.3.2. 預編譯模塊
某些預構建的模塊類型允許模塊與其基于源代碼的對應模塊具有相同的名稱。
例如,如果已有同名的cc_binary,也可以將cc_prebuilt_binary命名為foo
例如可以預編譯一些腳本:
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
//Android 12 AOSP源碼
//packages/modules/Gki/Android.bp
cc_prebuilt_binary {name: "com.android.gki.preinstall",product_specific: true,srcs: ["preinstall.sh"],apex_available: ["com.android.gki.*"],strip: {none: true,},
}
這讓開發者可以靈活地選擇要納入其最終產品中的版本。如果編譯配置包含兩個版本,則預編譯模塊定義中的prefer標記值會指示哪個版本具有優先級。請注意,某些預編譯模塊的名稱不能以prebuilt開頭,例如android_app_import
2.4.3.3. 命名空間模塊
在Android完全從Make轉換為Soong之前,Make產品配置必須指定PRODUCT_SOONG_NAMESPACES
值。它的值應該是一個以空格分隔的列表,其中包含Soong導出到Make以使用m命令進行編譯的命名空間。
在Android完成到Soong的轉換之后,啟用命名空間的詳細信息可能會發生變化。
Soong可以讓不同目錄中的模塊指定相同的名稱,只要每個模塊都在單獨的命名空間中聲明即可。可以按如下方式聲明命名空間:
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
soong_namespace {imports: ["path/to/otherNamespace1", "path/to/otherNamespace2"],
}
PS:命名空間沒有 name 屬性;其路徑會自動指定為其名稱。系統會根據每個 Soong 模塊在樹中的位置為其分配命名空間。每個 Soong 模塊都會被視為處于 Android.bp(位于當前目錄或最近的父級目錄中的 soong_namespace 文件內)定義的命名空間中。如果未找到此類 soong_namespace 模塊,則認為該模塊位于隱式根命名空間中。
2.5. 編譯Android
2.5.1. source更新環境
使用envsetup.sh腳本初始化環境:source build/envsetup.sh
或者. build/envsetup.sh
PS:需要在每次運行repo sync
后重新發出此命令,以獲取對該腳本所做的任何更改。請注意,將source
替換為.
(一個點)可以省去一些字符,這種簡寫形式在文檔中更為常用
envsetup.sh 腳本會導入若干命令,執行后能夠使用Android源代碼,其中包括一些可使用的命令
如需查看可用命令的完整列表,請運行以下命令:hmm
2.5.2. lunch選擇目標
使用lunch選擇要構建的目標
lunch product_name-build_variant
會選擇product_name作為需要構建的產品,并選擇build_variant
作為需要構建的變體,然后將這些選擇存儲在環境中,以便供后續對m
和其他類似命令的調用讀取。
確切的配置可作為參數進行傳遞。例如,以下命令表示針對模擬器進行完整構建,并且啟用所有調試功能。
lunch aosp_arm-eng
2.5.2.1. eng/user/userdebug
參考官方文檔
所有構建目標都采用BUILD-BUILDTYPE
形式,其中BUILD
是表示特定功能組合的代號。BUILDTYPE
是以下類型之一:
構建類型 | 使用情況 |
---|---|
user | 權限受限;適用于生產環境安裝帶有user標記的模塊除了帶有標記的模塊之外,還會根據產品定義文件安裝相應模塊屬性ro.secure=1屬性ro.debuggable=0adb 默認處于停用狀態 |
userdebug | 與“user”類似,但具有 root 權限和調試功能;是進行調試時的首選編譯類型同user區別有幾點:還會安裝帶有 debug 標記的模塊屬性ro.debuggable=1adb 默認處于啟用狀態 |
eng | 具有額外調試工具的開發配置默認變種安裝帶有eng或debug標記的模塊除了帶有標記的模塊之外,還會根據產品定義文件安裝相應模塊屬性ro.secure=0屬性ro.debuggable=1屬性ro.kernel.android.checkjni=1adb 默認處于啟用狀態 |
2.5.2.2. tapas
tapas命令用于配置未捆綁應用的構建流程。
它會選擇要由Android構建系統構建的各個應用。與lunch不同,tapas不會請求為設備構建映像。
使用tapas help
查看幫助說明
2.5.3. 編譯代碼
使用m
構建所有內容。m
可以使用-jN
參數處理并行任務。
如果沒有提供-j
參數,構建系統會自動選擇認為最適合您系統的并行任務計數
m droid
是正常build。此模塊目標在此處,因為默認目標需要名稱m all
會構建所有內容,以確保包含在樹中且包含Android.mk文件的所有元素都會構建m
: 從樹的頂部運行構建系統。這很有用,因為可以在子目錄中運行make
。如果設置了TOP
環境變量,它便會使用此變量。如果未設置此變量,它便會從當前目錄中查找相應的樹,以嘗試找到樹的頂層。可以通過運行不包含參數的m
來構建整個源代碼樹,也可以通過指定相應名稱來構建特定目標mma
: 構建當前目錄中的所有模塊及其依賴項mmma
: 構建提供的目錄中的所有模塊及其依賴項croot
: cd 到樹頂部m clean
: 會刪除此配置的所有輸出和中間文件。此內容與rm -rf out/
相同- 運行
m help
即可查看m
提供的其他偽目標
2.5.4. 運行編譯結果
可以在模擬器上運行構建系統,也可以將其刷寫到設備上。由如果已經使用lunch選擇了構建目標,就不能在構建目標以外的目標上運行。
- 使用fastboot刷機
- 模擬Android設備:編譯流程會自動將模擬器添加到您的路徑中。如需運行模擬器,請輸入以下命令:
emulator
2.6. ADB命令工具
使用adb version
查看adb版本,并同時確認是否已安裝ADB
如果未安裝,可以構建Android源碼,在構建目錄下使用Android項目源碼提供的ADB工具
2.7. fastboot刷寫設備
- 按住響應組合按鍵或者使用
adb reboot bootloader
命令進入fastboot模式 - 運行命令
fastboot flashall -w
刷寫,其中-w
會擦除設備的data分區數據
2.8. 添加變種product
2.8.1. 編寫product makefile步驟
- 創建一個目錄
device/<company-name>/<device-name>
,例如device/google/marlin
(參考Android Q AOSP)。此目錄將包含您設備的源代碼以及構建這些代碼所需的Makefile - 創建一個Makefile文件device.mk,用來聲明設備所需的文件和模塊。有關示例,參考
device/google/marlin/device-marlin.mk
- 創建一個產品定義Makefile,以便基于設備創建具體產品。以下示例Makefile來自于
device/google/marlin/aosp_marlin.mk
。請注意,該產品會通過Makefile沿用device/google/marlin/device-marlin.mk
和vendor/google/marlin/device-vendor-marlin.mk
文件中的設置,同時還會聲明產品特定信息,例如名稱、品牌和型號
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
# Inherit from the common Open Source product configuration
$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_base_telephony.mk)PRODUCT_NAME := aosp_marlin
PRODUCT_DEVICE := marlin
PRODUCT_BRAND := Android
PRODUCT_MODEL := AOSP on msm8996
PRODUCT_MANUFACTURER := Google
PRODUCT_RESTRICT_VENDOR_FILES := truePRODUCT_COPY_FILES += device/google/marlin/fstab.common:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.marlin$(call inherit-product, device/google/marlin/device-marlin.mk)
$(call inherit-product-if-exists, vendor/google_devices/marlin/device-vendor-marlin.mk)PRODUCT_PACKAGES += \Launcher3QuickStep \WallpaperPicker
- 創建一個指向產品的Makefile的AndroidProducts.mk文件。在此示例中,僅需要產品定義Makefile。以下示例來自于
device/google/marlin/AndroidProducts.mk
(該文件同時包含marlin(Pixel)和sailfish(PixelXL),它們共享大部分配置)
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
PRODUCT_MAKEFILES := \$(LOCAL_DIR)/aosp_marlin.mk \$(LOCAL_DIR)/aosp_sailfish.mkCOMMON_LUNCH_CHOICES := \aosp_marlin-userdebug \aosp_sailfish-userdebug
- 創建一個包含主板特定配置的Makefile文件
BoardConfig.mk
。有關示例,請查看device/google/marlin/BoardConfig.mk
2.8.2. 設置產品定義變量
變量 | 說明 | 示例 |
---|---|---|
PRODUCT_AAPT_CONFIG | 創建軟件包時使用的 aapt 配置 | |
PRODUCT_BRAND | 對軟件進行自定義所針對的品牌(如果有),例如運營商 | |
PRODUCT_CHARACTERISTICS | 用于允許向軟件包中添加變體特定資源的 aapt 特性 | tablet、nosdcard |
PRODUCT_COPY_FILES | 字詞列表,如 source_path:destination_path。在構建相應產品時,應將源路徑下的文件復制到目標路徑。config/makefile 中定義了針對復制步驟的規則 | |
PRODUCT_DEVICE | 工業設計的名稱。這也是主板名稱,構建系統會使用它來查找 BoardConfig.mk | tuna |
PRODUCT_LOCALES | 以空格分隔的列表,用于列出由雙字母語言代碼和雙字母國家/地區代碼組成的代碼對,以便說明針對用戶的一些設置,例如界面語言和時間、日期以及貨幣格式。PRODUCT_LOCALES 中列出的第一個語言區域會用作產品的默認語言區域 | en_GB、de_DE、es_ES、fr_CA |
PRODUCT_MANUFACTURER | 制造商的名稱 | acme |
PRODUCT_MODEL | 最終產品的最終用戶可見名稱 | |
PRODUCT_NAME | 總體產品的最終用戶可見名稱,將顯示在設置 > 關于屏幕中 | |
PRODUCT_OTA_PUBLIC_KEYS | 產品的無線下載 (OTA) 公鑰列表 | |
PRODUCT_PACKAGES | 將要安裝的 APK 和模塊列表 | 日歷聯系人 |
PRODUCT_PACKAGE_OVERLAYS | 指明是使用默認資源還是添加任何產品特定疊加層 | vendor/acme/overlay |
PRODUCT_SYSTEM_PROPERTIES | 系統分區的系統屬性分配(采用 “key=value” 格式)列表。其他分區的系統屬性可通過 PRODUCT__PROPERTIES 設置,如供應商分區的 PRODUCT_VENDOR_PROPERTIES。支持的分區名稱:SYSTEM、VENDOR、ODM、SYSTEM_EXT 和 PRODUCT |
2.8.3. 配置默認系統語言和語言區域過濾器
2.8.3.1. 屬性配置
ro.product.locale
:用于設置默認語言區域。此屬性最初被設置為PRODUCT_LOCALES
變量中的第一個語言區域;可以替換該值ro.localization.locale_filter
:使用正則表達式(應用于語言區域名稱)設置語言區域過濾器。例如:-
- 包含過濾器:
^(de-AT|de-DE|en|uk).*
:只允許德語(奧地利變體和德國變體)、所有英語變體和烏克蘭語
- 包含過濾器:
-
- 排除過濾器:
^(?!de-IT|es).*
:不包括德語(意大利變體)和西班牙語的所有變體
- 排除過濾器:
2.8.3.2. 啟用語言區域過濾器
如需啟用過濾器,請設置ro.localization.locale_filter
系統屬性字符串值
通過在出廠校準期間使用oem/oem.prop
設置過濾器屬性值和默認語言,無需將過濾器烘焙 (bake) 到系統映像中即可配置限制
通過將這些屬性添加到PRODUCT_OEM_PROPERTIES
變量中(如下所示),就可以確保從OEM分區中獲取這些屬性
代碼語言:javascript
代碼運行次數:0
運行
AI代碼解釋
# Delegation for OEM customization
PRODUCT_OEM_PROPERTIES += \ro.product.locale \ro.localization.locale_filter
然后,在生產環境中,實際值會被寫入oem/oem.prop
以反映目標要求。借助這種方法,就能在恢復出廠設置期間保留默認值,讓初始設置在用戶看來與首次設置完全一樣
3. 補丁提交的生命周期
3.1. 流程圖
4. 參考
- Google官方文檔
本文轉發之??Android 項目構建編譯概述-騰訊云開發者社區-騰訊云