疑問:
(1)瞭解APK安裝流程有什麼好處
(2)瞭解APK安裝流程可以解決什麼問題
一、可以在安裝流程裡做什麼
安裝就分為下面三個階段,每個階段可以做些什麼工作,可以幫助我們優化安裝流程,解決安裝後的一些問題呢?
(1)安裝前、安裝中:這兩個階段,第三方應用做不了什麼,一般是應用分發APP應用商店、遊戲中心、瀏覽器、應用寶這些應用會關注這兩個狀態。
(2)安裝後:這個階段,無論是內建應用還是第三方應用,或多或少的會遇到一些問題,如so檔案找不到,圖片儲存、快取資料等出現異常等...
二、安裝前
安裝前無非是根據自己的應用情況,選擇一種可以使用的安裝方法。
2.1 pm命令安裝方法
對於具有系統簽名的廠商應用,具備靜默安裝能力,使用pm命令即可實現。
String cmd = "pm install -r -d /data/data/android.apk"
Runtime run = Runtime.getRuntime();
Process process = run.exec(cmd);
2.2 包安裝管理器安裝
非系統簽名的應用寶這種應用,只能使用包安裝管理器進行安裝。
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android" + ".package-archive");
mContext.startActivity(intent);
2.3 session命令安裝
使用session安裝的原因,是因為從Android 8.0開始,pm命令無法實現靜默安裝,否則會直接顯示安裝失敗。但是網上並未發現對靜默方法的適配方案,也許這是因為這個相容只有廠商關注,第三方應用不關注這個方法的相容。下面給出相容方案:
int sessionId = packageInstaller.createSession(params);
InstallLog.d(TAG, "doPackageStage creat sessionId is : " + sessionId);
final byte[] buffer = new byte[65536];
session = packageInstaller.openSession(sessionId);
final InputStream in = new FileInputStream(file);
final long sizeBytes = file.length();
final OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes);
try {
int c;
while ((c = in.read(buffer)) != -1) {
out.write(buffer, 0, c);
}
session.fsync(out);
} catch (IOException ex) {
InstallLog.e(TAG, "doPackageStage ioException : " + ex.getMessage(), ex);
} finally {
InstallUtils.closeQuietly(in);
InstallUtils.closeQuietly(out);
}
該方法是從packageManager中抽取出的程式碼,可實現應用的靜默安裝。
三、安裝中
3.1 APK的結構
APK檔案其實是zip格式,一般包含一個或多個dex檔案、resources.arsc、AndroidManifest.xml、res目錄、META-INF目錄及包含so庫的lib目錄:
3.2 安裝過程中涉及的儲存目錄
system/app——內建應用,也就是系統自帶的應用程式,無法刪除。
data/app——使用者程式安裝的目錄,有刪除許可權。安裝時把apk檔案複製到此目錄。
data/data——存放應用程式的資料,比如一些sp快取資料。
data/dalvik-cache——將APK中的dex檔案安裝到dalvik-cache目錄下(dex檔案是dalvik虛擬機器的可執行檔案,其大小約為原始APK檔案大小的四分之一)。
3.3 安裝主要流程
安裝過程概括為:複製APK安裝包到/data/app目錄下,解壓並掃描安裝包,向資源管理器注入APK資源,解析AndroidManifest檔案,並在/data/data目錄下建立對應的應用資料目錄,然後針對dalvik/art環境優化dex檔案,儲存到dalvik-cache目錄,將AndroidManifest檔案解析出的元件、許可權註冊到PackageManagerService,完成後傳送廣播。
3.4 安裝中可以優化的點
安裝中,這個過程看上去沒有什麼可以做的,但是對於廠商應用來說,應用的安裝速度,卻是可以有很大的提升空間的。如應用更新的差分包升級就是一種常見的增量更新方式。
經過一系列測試與驗證,發現應用安裝的速度,本身與一些因素有關,最主要的是CPU的使用頻率。
眾所周知,現在的手機較為高階,為8核,但是在應用安裝過程中,分析trace檔案,可以確認,並不是8核線程全負荷工作去完成一個應用的安裝,而是一部分執行緒執行在高核,一部分在低核。
3.4.1 CPU的工作頻率介紹
cpuinfo_max_freq cpuinfo_min_freq :分別給出了 CPU 硬體所支援的最高執行頻率及最低執行頻率,
cpuinfo_cur_freq 則會從CPU 硬體暫存器中讀取CPU 當前所處的執行頻率。
Governor 在選擇合適的執行頻率時只會在scaling_max_freq 和 scaling_min_freq 所確定的頻率範圍內進行選擇。
scaling_cur_freq 返回的是cpufreq 模組快取的CPU當前執行頻率,而不會對CPU 硬體暫存器進行檢查。
scaling_available_governors 會告訴使用者當前有哪些 governors 可供使用者使用。
scaling_driver 則會顯示該 CPU 所使用的變頻驅動程式。
Scaling_governor 則會顯示當前的管理策略,往這個上 echo 其他型別會有相應的轉變。
scaling_setspeed :需將 governor 型別切換為 userspace ,才會出現,往這個檔案 echo 數值,會切換主頻。
基於此,可以在應用安裝時,提升CPU的工作頻率,即可使CPU執行在合適的頻率。
2.4.2 提升CPU的工作頻率
除了可以直接根據安裝速度判斷安裝速度是否提升外,也可以根據下面日誌判斷提頻是否有效:
adb shell cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
adb shell cat /sys/devices/system/cpu/cpu7/cpufreq/cpuinfo_cur_freq
可以直接看到頻率變化:
微信安裝速度可以由前面CPU低頻時的20s,提升到CPU頻率較高時的10s左右。
注意:頻率不是越高越好,頻率越高,手機耗電會越高,容易發熱。
四、安裝後
應用安裝後,會遇到各種各樣的問題,啟動失敗,合規整改(這個其實在應用開發時就要完成),那麼哪些問題又是可能遇到,又可以藉助apk的安裝流程去解決的
4.1 targetsdkversion=30 不得不做的事情
在《符合 Google Play 的目標 API 級別要求》 一文中,根據google官方要求,需要對隱私許可權進行管控,強制執行分割槽儲存,這就要求,每個應用不得在sd卡進行資源儲存。那麼問題來了,假如你的專案使用了Glide,Glide的儲存路徑之前設定到了sd卡下面,現在又無法使用外部儲存目錄,該怎麼辦?
當了解了apk的安裝流程之後,知道應用的資料會儲存在data/data/packagename下面,這就給Glide的資源儲存提供了一個內部資料夾,唯一要做的事情,就是為了防止data/data佔用過大,把Glide的儲存目錄設定個上限即可。
4.2 libmmkv.so無法找到問題解決
4.2.1 現象
如果你的應用接了騰訊的mmkv,你可能遇到了這樣的問題:
java.lang.UnsatisfiedLinkError dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/packagename-Sxe4_uU3WXx-ckI5DyG3UA==/base.apk"],nativeLibraryDirectories=[/data/app/packagename-Sxe4_uU3WXx-ckI5DyG3UA==/lib/arm, /system/fake-libs, /data/app/packagename-Sxe4_uU3WXx-ckI5DyG3UA==/base.apk!/lib/armeabi-v7a, /system/lib, /system/vendor/lib, /system/vendor/lib/hw]]] couldn't find "libmmkv.so"
Runtime.java 1011
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/packagename-Sxe4_uU3WXx-ckI5DyG3UA==/base.apk"],nativeLibraryDirectories=[/data/app/packagename-Sxe4_uU3WXx-ckI5DyG3UA==/lib/arm, /system/fake-libs, /data/app/packagename-Sxe4_uU3WXx-ckI5DyG3UA==/base.apk!/lib/armeabi-v7a, /system/lib, /system/vendor/lib, /system/vendor/lib/hw]]] couldn't find "libmmkv.so"
at java.lang.Runtime.loadLibrary0(Runtime.java:1011)
at java.lang.System.loadLibrary(System.java:1657)
at com.tencent.mmkv.MMKV.a(SourceFile:3)
這個表示應用載入libmmkv.so出現異常。
4.2.2 分析原因
出現問題的原因是什麼:根據日誌可以確認,是找不到應用data/app/資料夾下面的libmmkv.so檔案。
4.2.3 解決問題
前面提到,應用的資料會儲存在data/data下面,這個路徑下面也包含了應用解壓之後的so庫,所以可以做一件事情解決上面libmmkv.so的問題,重連結data/data下面的資源到data/app下面,實現資源共享。實踐證明該方案完全可行,有效解決了so庫找不到的問題。
五、疑問解答
(1)瞭解APK安裝流程有什麼好處
從apk發起安裝,安裝中、一直到安裝結束,應用狀態的變化,CPU的使用,資源的共享,牽涉到一系列知識點,這些知識點是可以串聯起來的,對提升個人的知識體系有幫助。當然,由於文章篇幅有限,本文章只是作為一個引導,大致說明安裝過程中存在什麼知識點,PMS、檔案管理、程序拉起等等安全可以另起一章節進行介紹,後續會介紹這些方面的內容。
(2)瞭解APK安裝流程可以解決什麼問題
廠商應用更多的關注安裝前、安裝中遇到的問題,第三方應用關注安裝後遇到的問題。掌握了安裝過程中的每一個環節,通過上面的分析,可以知道,能夠快速幫助定位問題。
作者:vivo網際網路客戶端團隊-Xu Jie