1. 程式人生 > 其它 >打通“任督二脈”:Android 應用安裝優化實戰

打通“任督二脈”:Android 應用安裝優化實戰

apk安裝過程,涉及到data/app、data/data等資料夾的訪問與資源的儲存,瞭解安裝流程,可以幫助業務進行整改,解決線上問題

疑問:

(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.1CPU的工作頻率介紹

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

分享 vivo 網際網路技術乾貨與沙龍活動,推薦最新行業動態與熱門會議。