本文通過對源碼進行追蹤,并且調試各種方式,得出android通過adb push apk放置目錄/sdcard/Download/下無法安裝的原因,并從兩個修改點觸發,提出如何能修復此問題的建議。
1. 現象
把apk通過adb push的方式放在/sdcard/Download文件夾下,
(1)直接打開File(DocumentUI),直接進入Download文件夾, 點擊應用無法安裝
(2)點擊左上角,選擇Device -> Download,進入之后Download文件夾, 點擊應用可以安裝。
2. 分析
trace代碼,判定這是android正常的設計,目的是確保下載APK的來源是經過用戶同意后才能允許安裝。
(1)當APK下載保存到設備后,MediaProvider數據庫會保存apk的來源(owner_package_name),
比如 通過adb push的方式owner_package_name=com.android.shell;通過chrome瀏覽器下載的方式owner_package_name=com.android.chrome
(2)進入安裝流程,區別在于發起源不同:
a. Files -> P3000 -> Download 是通過package:com.android.documentsui直接啟動com.android.packageinstaller
b. Files -> Download 是package:com.android.documentsui轉給package:com.android.providers.downloads.ui再啟動com.android.packageinstaller
而在b的情況下,
系統會將apk對應的路徑會從 下載未安裝:raw:/storage/emulated/0/Download/XXX.apk 變為 下載已安裝:msf:1000000044(數字為系統分配),這樣做是因為android文件系統為了優化訪問性能
在這個優化過程中,改變之前可以正常安裝,改變之后安裝需要驗證來源的權限:
比如:使用chrome下載
如果是通過shell放入至設備,com.android.shell并沒有申請Manifest.permission.REQUEST_INSTALL_PACKAGES的方式,所以安裝就被攔截了;
同樣,本地驗證通過Settings -> Connected devices -> USB -> File Transfer的方式將APK放入Internal shared storage -> Download 安裝同樣也會被攔截;
這是因為有些進程沒有UI申請Manifest.permission.REQUEST_INSTALL_PACKAGES的方式。
3. 結論
(1)確保Download文件夾中APK的來源是通過下載的方式
(2)其他方式存入設備的APK不要存放在Download文件夾
4. 修復方案
(1)不攔截
未知來源的APK,在兩種情況下會攔截安裝
a. originatingUid所對應的apk(也就是APK的來源)的targetSdkVersion < 0
b. originatingUid所對應的apk(也就是APK的來源)未申請權限Manifest.permission.REQUEST_INSTALL_PACKAGES
Index: frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
============================