當您點擊 APK 檔案上的「安裝」或從 Play 商店下載應用程式時,一系列複雜的操作將在幕後開始。看似簡單的進度條,其實代表了套件解析、密碼驗證、權限管理、檔案提取、程式碼優化等數十個步驟。了解此過程有助於解釋為什麼安裝有時會失敗以及您可以採取哪些措施。
在本文中,我們將介紹 Android 安裝管道的每個主要步驟,從系統收到 APK 到應用程式準備啟動的那一刻。
第 1 步:開始安裝
安裝過程的開始方式因來源而異:
- 遊戲商店: Play 商店應用程式下載 APK(或分割 APK)並以繞過某些使用者確認的特殊權限呼叫系統的軟體包安裝程式。
- 側面加載: 當您開啟 APK 檔案時,Android 會啟動套件安裝程式活動。在 Android 8.0 及更高版本上,安裝應用程式必須對其特定來源具有「安裝未知應用程式」權限。
- 亞銀: adb install 指令透過 USB 直接與套件管理器服務通信,完全繞過圖形安裝程式。
無論來源為何,所有安裝最終都會到達相同的系統服務:包管理服務 (PMS)。這是 Android 上所有套件操作的中央權限。
第二步:包解析
首先,系統需要了解它將要安裝的內容。 PackageManagerService 呼叫 套件解析器 來讀取 APK 檔案並提取其元資料。
解析器從 APK 讀取 AndroidManifest.xml 檔案。此二進位 XML 檔案包含關鍵資訊:
- 套餐名稱: 應用程式的唯一識別碼(例如,com.example.myapp)
- 版本號碼及名稱: 用於確定這是升級還是全新安裝
- 最低和目標 SDK 版本: 確定與裝置的兼容性
- 聲明的權限: 應用程式請求的權限和它定義的自訂權限
- 成分: 應用程式註冊的活動、服務、廣播接收器和內容提供者
- 硬體和軟體特色: 相機、GPS 或特定 OpenGL 版本等需求
如果清單格式錯誤或 APK 結構無效,則安裝在此階段失敗,並顯示「解析錯誤」訊息。這是旁加載 APK 無法安裝的最常見原因之一。
第 3 步:相容性檢查
解析清單後,系統會執行一系列相容性檢查:
- SDK版本: 如果應用程式的 minSdkVersion 高於裝置的 API 級別,則安裝將被拒絕。
- ABI 相容性: 如果APK包含本機程式庫,系統會檢查它們是否與裝置的CPU架構相符。僅包含 armeabi-v7a 函式庫的 APK 將無法安裝在純 x86 裝置上。
- 所需功能: 如果應用程式聲明所需的硬體功能(如 android.hardware.telephony),系統將驗證裝置支援它們。
- 可用儲存空間: 系統檢查是否有足夠的可用空間來安裝應用程序,包括用於提取的本機庫和優化的DEX檔案的空間。
第四步:簽名驗證
這是安裝過程中最關鍵的步驟之一。 Android 驗證 APK 的加密簽章以確保其完整性和真實性。
驗證過程取決於存在哪些簽章方案:
V1 簽章(JAR 簽章)
系統檢查META-INF/目錄中是否有簽名檔(.SF、.RSA或.DSA)。 APK 中的每個文件都會根據清單中列出的摘要進行驗證。這很慢,因為每個檔案都必須單獨進行哈希處理。
V2簽章(APK簽章方案v2)
該方案在 Android 7.0 中引入,將整個 APK 簽署為二進位 blob。簽名區塊插入到 ZIP 中央目錄和中央目錄末尾記錄之間。驗證速度要快得多,因為它對原始位元組進行操作,而無需解壓縮各個條目。
V3 簽章(金鑰輪換)
從 Android 9.0 開始,V3 擴展了 V2,支援密鑰輪換。它包括一個連結新舊簽署金鑰的循環證明結構,允許開發人員更改其簽署金鑰,同時保持更新相容性。
V4簽章(增量)
Android 11 引進了用於增量安裝的 V4。它提供了基於 Merkle 樹的簽名,允許在將各個區塊傳輸到裝置時對其進行驗證。
如果簽名驗證因任何原因失敗,安裝將立即中止。您可以在安裝前使用我們的 APK驗證工具 檢查 APK 的簽章。
更新簽章匹配
如果已安裝具有相同套件名稱的應用程序,系統會執行額外檢查:新 APK 的簽署憑證必須與現有安裝的憑證相符。這可以防止惡意方用篡改版本替換合法應用程式。如果簽名不匹配,您將看到錯誤「應用程式未安裝:該套件與同名的現有套件衝突」。
第五步:用戶確認
對於旁載安裝,系統會顯示一個安裝確認對話框,其中顯示:
- 應用程式名稱和圖標(從 APK 資源中提取)
- 應用程式請求的權限(在較舊的 Android 版本上)
- 這是新安裝還是更新
- 有關應用程式來源或潛在風險的任何警告
在 Android 12 及更高版本上,確認螢幕更簡單,因為運行時權限是在應用程式首次需要時單獨授予的,而不是在安裝時授予的。
第 6 步:文件提取和放置
一旦使用者確認(或對於 Play 商店安裝,自動),系統開始提取並放置檔案:
APK儲存
APK 檔案本身複製到 /data/app/[package-name]-[random]/base.apk。對於拆分 APK 安裝,split_config.arm64_v8a.apk 等附加檔案會放置在基本 APK 旁邊。下載資料夾中的原始 APK 未被修改或刪除。
本機庫擷取
如果APK包含本机库(在lib/目录中),它们将被提取到/data/app/[package-name]-[random]/lib/[abi]/。在較新的 Android 版本上,應用程式可以選擇在 APK 中壓縮本機庫,並使用 android:extractNativeLibs="false" 直接載入它們,從而節省儲存空間。
資料目錄創建
系統在 /data/data/[package-name]/(或多用戶裝置上的 /data/user/0/[package-name]/)建立應用程式的私人資料目錄。該目錄由分配給應用程式的唯一 Linux UID 擁有,確保其他應用程式在沒有 root 權限的情況下無法存取它。
第7步:DEX優化
在這一步驟中,Android 將應用程式的字節碼轉換為針對裝置特定硬體最佳化的格式。這個流程在 Android 的歷史上發生了顯著的演變:
Dalvik 時代(Android 4.4 及更早版本)
最初的Dalvik虛擬機器使用Just-In-Time(JIT)編譯。在安裝過程中,classes.dex 檔案被優化為包含經過驗證和最佳化的字節碼的 ODEX 檔案。這相對較快,但意味著應用程式在運行時運行速度較慢,因為大多數程式碼仍被解釋。
ART 與 AOT(Android 5.0 至 6.0)
Android 運行時 (ART) 取代了 Dalvik,並引入了提前 (AOT) 編譯。在安裝過程中,整個 DEX 位元組碼被編譯為本機機器碼。這使得應用程式運行速度更快,但顯著增加了安裝時間和儲存使用量。某些應用程式需要幾分鐘才能安裝。
設定檔引導編譯(Android 7.0+)
現代 Android 使用混合方法。在安裝過程中,僅編譯關鍵啟動路徑。當使用者執行應用程式時,系統會收集識別常用程式碼路徑的執行設定檔。在空閒維護期間(通常在夜間充電時),系統將這些熱路徑編譯為本機程式碼。這可以平衡安裝速度、儲存使用和運行時效能。
編譯後的程式碼儲存在 /data/dalvik-cache/ 中,或與 APK 一起儲存為 .odex、.vdex 和 .art 檔案。 .vdex 檔案包含經過驗證的 DEX 程式碼,.odex 檔案包含已編譯的本機程式碼,.art 檔案包含預先初始化的堆疊映像以加快啟動速度。
第8步:權限註冊
PackageManagerService 向系統註冊應用程式聲明的權限和元件:
- 安裝時權限(如 INTERNET 或 VIBRATE)會自動授予,無需使用者互動。
- 運行時權限(如CAMERA或LOCATION)已註冊但未授予。應用程式必須在運行時請求它們。
- 意圖過濾器 已註冊,以便系統知道哪些應用程式可以處理哪些操作(例如開啟 URL 或共用內容)。
- 內容提供者 已向其當局註冊,以便其他應用程式可以查詢它們。
第9步:系統集成
最後步驟將應用程式整合到 Android 系統中:
- 套件資料庫更新: 系統的套件資料庫 (/data/system/packages.xml) 已使用新應用程式的資訊進行更新,包括其指派的 UID、權限和元件聲明。
- 啟動器通知: 主螢幕啟動器會收到新應用程式的通知,以便它可以顯示應用程式圖示。
- 播送: 系統發送 PACKAGE_ADDED 廣播,允許其他應用程式對新安裝做出反應(例如,備份應用程式可能會安排備份)。
- SELinux 上下文: 應用程式的檔案會根據其目標 SDK 版本和聲明的權限使用適當的 SELinux 安全上下文進行標記。
為什麼安裝失敗
了解安裝管道有助於診斷常見故障:
- “解析錯誤”: APK 已損壞、不完整或清單格式錯誤。這種情況通常發生在下載不完整或檔案轉換不正確的情況下。
- 「應用程式未安裝」(簽章不符): 您正在尝试使用由不同密钥签名的 APK 更新应用程序。您必須先解除安裝現有版本。
- 「儲存空間不足」: 沒有足夠的空間用於 APK、提取的庫和 DEX 最佳化輸出。實際所需空間通常是 APK 大小的 2-3 倍。
- 「包與現有包衝突」: 相同的套件名稱但不同的簽章。在 Play 商店和旁加載版本之間切換時很常見。
- 版本降級被阻止: 預設情況下,Android 會阻止安裝舊版本而不是新版本。 ADB 可以使用 adb install -d 覆寫此設定。
拆分APK安裝
安裝拆分 APK(來自 App Bundle)時,流程略有不同。系統使用基於會話的安裝 API:
- 建立新的安裝會話
- 每個拆分 APK 都會寫入會話
- 會話已提交,觸發完整的驗證管道
- 所有拆分必須具有匹配的包名稱、版本代碼和簽名證書
這是 XAPK 安裝程式和 APKS 到 APK 合併 等工具用來處理多檔案安裝的機制。
透過 ADB 安裝
當您使用 adb install 時,該過程會繞過圖形安裝程序,但遵循相同的內部管道。 ADB 透過套接字連線與套件管理器服務進行通訊。它支援無法透過 GUI 獲得的其他標誌:
- -r:取代現有應用程式(允許重新安裝)
- -d:允許版本降級
- -g:立即授予所有運行時權限
- -t:允許安裝僅測試 APK
- --install-multiple:在單一會話中安裝拆分 APK
卸載過程中會發生什麼
為了完整起見,以下是刪除應用程式時會發生的情況:
- 應用程式的進程被終止
- APK 和提取的庫已從 /data/app/ 中刪除
- 應用程式的私人資料目錄被刪除(除非使用者選擇保留資料)
- 已編譯的DEX快取檔案被刪除
- 套件資料庫已更新
- 發送 PACKAGE_REMOVED 廣播
- 啟動器刪除應用程式圖標
請注意,由於範圍儲存強制執行,外部儲存體上的應用程式特定檔案(/Android/data/[package]/ 和 /Android/obb/[package]/)也會在 Android 10 及更高版本上刪除。
為什麼要了解 PackageManager 可以節省調試時間
Android 安裝過程是一系列精心策劃的安全檢查、文件操作和系統整合。從保護用戶免受應用程式篡改到優化特定硬體的效能,每個步驟都有一個目的。當安裝失敗時,錯誤通常指向此管道中的特定步驟,了解該過程有助於您快速診斷和解決問題。
從 Play 商店安裝,手動側載 APK,並透過相同的底層管道使用 ADB 所有漏斗推送構建,確保設備上的每個應用程式都經過驗證、正確放置並針對您的硬體進行最佳化。