1. 程式人生 > >APK 安裝過程 及 原理 詳解

APK 安裝過程 及 原理 詳解

APK為AndroidPackage的縮寫

Android應用安裝有如下四種方式:

1.系統應用安裝――開機時完成,沒有安裝介面

2.網路下載應用安裝――通過market應用完成,沒有安裝介面

3.ADB工具安裝――沒有安裝介面。

4.第三方應用安裝――通過SD卡里的APK檔案安裝,有安裝介面,由 packageinstaller.apk 應用處理安裝及解除安裝。

-------------------------------------

應用安裝涉及到如下幾個目錄:        

system/app ---------------系統自帶的應用程式,獲得adb root許可權才能刪除

data/app  ---------------使用者程式安裝的目錄。使用者 安裝時把apk檔案 複製 到此目錄
data/data ---------------存放應用程式的資料
data/dalvik-cache--------將apk中的dex檔案安裝到dalvik-cache目錄下(dex檔案是dalvik虛擬機器的可執行檔案,其大小約為原始apk檔案大小的四分之一)

安裝過程:

複製APK安裝包到data/app目錄下,解壓並掃描安裝包,把dex檔案(Dalvik位元組碼)儲存到dalvik-cache目錄,並data/data目錄下建立對應的應用資料目錄。

解除安裝過程:

刪除 安裝過程中在上述三個目錄下建立的檔案及目錄。

-------------------------

安裝應用的過程解析

一.開機安裝 
PackageManagerService處理各種 應用的安裝,解除安裝,管理等工作,開機時 由systemServer啟動此服務

(原始檔路徑:android\frameworks\base\services\java\com\android\server\PackageManagerService.java)

PackageManagerService服務 啟動的流程:

1.首先 掃描安裝“system\framework”

目錄下的jar包

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln"> </span><span class="com">// Find base frameworks (resource packages without code).</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            mFrameworkInstallObserver = new AppDirObserver(</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                mFrameworkDir.getPath(), OBSERVER_EVENTS, true);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            mFrameworkInstallObserver.startWatching();</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    | PackageParser.PARSE_IS_SYSTEM_DIR,</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    scanMode | SCAN_NO_DEX, 0);</span></span></p>

2.掃描 安裝系統system/app的應用程式

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">  </span><span class="com">// Collect all system packages.</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            mSystemAppDir = new File(Environment.getRootDirectory(), "app");</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            mSystemInstallObserver = new AppDirObserver(</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                mSystemAppDir.getPath(), OBSERVER_EVENTS, true);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            mSystemInstallObserver.startWatching();</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);</span></span></p>

3.製造商的目錄下/vendor/app應用包

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln"> </span><span class="com">// Collect all vendor packages.</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            mVendorAppDir = new File("/vendor/app");</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            mVendorInstallObserver = new AppDirObserver(</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                mVendorAppDir.getPath(), OBSERVER_EVENTS, true);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            mVendorInstallObserver.startWatching();</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);</span></span></p>

4.掃描“data\app”目錄,即使用者安裝的第三方應用

<p><strong>scanDirLI</strong><span class="pun">(</span><span class="pln">mAppInstallDir</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> scanMode</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span></p>

5.掃描" data\app-private"目錄,即安裝DRM保護的APK檔案(一個受保護的歌曲或受保 護的視訊是使用 DRM 保護的檔案)

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span class="pln">scanDirLI</span><span class="pun">(</span><span class="pln">mDrmAppPrivateInstallDir</span><span class="pun">,</span><span class="pln"> </span><span class="typ">PackageParser</span><span class="pun">.</span><span class="pln">PARSE_FORWARD_LOCK</span><span class="pun">,</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span class="pln">                    scanMode</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span></span></p>

掃描方法的程式碼清單

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="kwd">private</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> scanDirLI</span><span class="pun">(</span><span class="typ">File</span><span class="pln"> dir</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> flags</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> scanMode</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> currentTime</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        </span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> files </span><span class="pun">=</span><span class="pln"> dir</span><span class="pun">.</span><span class="pln">list</span><span class="pun">();</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">files </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="typ">Log</span><span class="pun">.</span><span class="pln">d</span><span class="pun">(</span><span class="pln">TAG</span><span class="pun">,</span><span class="pln"> </span><span class="str">"No files in app dir "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> dir</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="kwd">return</span><span class="pun">;</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        </span><span class="pun">}</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">false</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="typ">Log</span><span class="pun">.</span><span class="pln">d</span><span class="pun">(</span><span class="pln">TAG</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Scanning app dir "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> dir</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        </span><span class="pun">}</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        </span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">;</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun"><</span><span class="pln">files</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="typ">File</span><span class="pln"> file </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">File</span><span class="pun">(</span><span class="pln">dir</span><span class="pun">,</span><span class="pln"> files</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">isPackageFilename</span><span class="pun">(</span><span class="pln">files</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                </span><span class="com">// Ignore entries which are not apk's</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                continue;</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            PackageParser.Package pkg =<strong> scanPackageLI</strong>(file,</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            // Don't mess around with apps in system partition.</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                // Delete the apk</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                Slog.w(TAG, "Cleaning up failed install of " + file);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                file.delete();</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">        }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">    }</span></span></p>

並且從該掃描方法中可以看出呼叫了scanPackageLI()

private PackageParser.Package scanPackageLI(File scanFile,

int parseFlags, int scanMode, long currentTime)

跟蹤scanPackageLI()方法後發現,程式經過很多次的if else 的篩選,最後判定 可以安裝apk後,呼叫了 mInstaller.install

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">mInstaller </span><span class="pun">!=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                    </span><span class="kwd">int</span><span class="pln"> ret </span><span class="pun">=</span><span class="pln"> <strong>mInstaller</strong></span><strong><span class="pun">.</span><span class="pln">install</span></strong><span class="pun">(</span><span class="pln">pkgName</span><span class="pun">,</span><span class="pln"> useEncryptedFSDir</span><span class="pun">,</span><span class="pln">  pkg</span><span class="pun">.</span><span class="pln">applicationInfo</span><span class="pun">.</span><span class="pln">uid</span><span class="pun">,</span><span class="pln">pkg</span><span class="pun">.</span><span class="pln">applicationInfo</span><span class="pun">.</span><span class="pln">uid</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">ret </span><span class="pun"><</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                        </span><span class="com">// Error from installer</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        mLastScanError =    PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        return null;</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                }</span></span></p>

mInstaller.install()  通過    

  LocalSocketAddress address = new LocalSocketAddress(

                "installd", LocalSocketAddress.Namespace.RESERVED);

指揮installd在C語言的檔案中完成工作

PackageManagerService小節 :

1)從apk, xml中載入pacakge資訊, 儲存到內部成員變數中, 用於後面的查詢. 關鍵的方法是scanPackageLI().
2)各種查詢操作, 包括query Intent操作.
3)install package和delete package的操作. 還有後面的關鍵方法是installPackageLI().

二、從網路上下載應用:

下載完成後,會自動呼叫Packagemanager的安裝方法installPackage()

   /* Called when a downloaded package installation has been confirmed by the user */

    由英文註釋可見PackageManagerService 類的installPackage()函式為 安裝程式 的入口

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> installPackage</span><span class="pun">(</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="kwd">final</span><span class="pln"> </span><span class="typ">Uri</span><span class="pln"> packageURI</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">final</span><span class="pln"> </span><span class="typ">IPackageInstallObserver</span><span class="pln"> observer</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">final</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> flags</span><span class="pun">,</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="kwd">final</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> installerPackageName</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        mContext</span><span class="pun">.</span><span class="pln">enforceCallingOrSelfPermission</span><span class="pun">(</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                android</span><span class="pun">.</span><span class="typ">Manifest</span><span class="pun">.</span><span class="pln">permission</span><span class="pun">.</span><span class="pln">INSTALL_PACKAGES</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        </span><span class="typ">Message</span><span class="pln"> msg </span><span class="pun">=</span><span class="pln"> mHandler</span><span class="pun">.</span><span class="pln">obtainMessage</span><span class="pun">(</span><span class="pln">INIT_COPY</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        msg</span><span class="pun">.</span><span class="pln">obj </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">InstallParams</span><span class="pun">(</span><span class="pln">packageURI</span><span class="pun">,</span><span class="pln"> observer</span><span class="pun">,</span><span class="pln"> flags</span><span class="pun">,</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                installerPackageName</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        <strong>mHandler</strong></span><strong><span class="pun">.</span><span class="pln">sendMessage</span></strong><span class="pun">(</span><span class="pln">msg</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">    </span><span class="pun">}</span></span></span></p>

其中是通過PackageHandler的例項mhandler.sendMessage(msg)把資訊發給繼承Handler的類HandleMessage()方法

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="kwd">class</span><span class="pln"> </span><span class="typ">PackageHandler</span><span class="pln"> </span><span class="kwd">extends</span><span class="pln"> </span><span class="typ">Handler</span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                 </span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">*****************省略若干********************</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">         </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> handleMessage</span><span class="pun">(</span><span class="typ">Message</span><span class="pln"> msg</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                doHandleMessage</span><span class="pun">(</span><span class="pln">msg</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">finally</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                </span><span class="typ">Process</span><span class="pun">.</span><span class="pln">setThreadPriority</span><span class="pun">(</span><span class="typ">Process</span><span class="pun">.</span><span class="pln">THREAD_PRIORITY_BACKGROUND</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="pun">}</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        </span><span class="pun">}</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">   </span><span class="pun">******************省略若干**********************</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln"> </span><span class="pun">}</span></span></span></p>

把資訊發給doHandleMessage()方法,方法中用switch()語句進行判定傳來Message

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln"> </span><span class="kwd">void</span><span class="pln"> doHandleMessage</span><span class="pun">(</span><span class="typ">Message</span><span class="pln"> msg</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">msg</span><span class="pun">.</span><span class="pln">what</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">           </span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                </span><span class="kwd">case</span><span class="pln"> INIT_COPY</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">DEBUG_SD_INSTALL</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Log</span><span class="pun">.</span><span class="pln">i</span><span class="pun">(</span><span class="pln">TAG</span><span class="pun">,</span><span class="pln"> </span><span class="str">"init_copy"</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                    </span><span class="typ">HandlerParams</span><span class="pln"> </span><span class="kwd">params</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">HandlerParams</span><span class="pun">)</span><span class="pln"> msg</span><span class="pun">.</span><span class="pln">obj</span><span class="pun">;</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                    </span><span class="kwd">int</span><span class="pln"> idx </span><span class="pun">=</span><span class="pln"> mPendingInstalls</span><span class="pun">.</span><span class="pln">size</span><span class="pun">();</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">DEBUG_SD_INSTALL</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Log</span><span class="pun">.</span><span class="pln">i</span><span class="pun">(</span><span class="pln">TAG</span><span class="pun">,</span><span class="pln"> </span><span class="str">"idx="</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> idx</span><span class="pun">);</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">                    </span><span class="com">// If a bind was already initiated we dont really</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    // need to do anything. The pending install</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    // will be processed later on.</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    if (!mBound) {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        // If this is the only one pending we might</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        // have to bind to the service again.</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        if (!connectToService()) {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            Slog.e(TAG, "Failed to bind to media container service");</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            params.serviceError();</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            return;</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        } else {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            // Once we bind to the service, the first</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            // pending request will be processed.</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            mPendingInstalls.add(idx, params);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    } else {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        mPendingInstalls.add(idx, params);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        // Already bound to the service. Just make</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        // sure we trigger off processing the first request.</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        if (idx == 0) {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            mHandler.sendEmptyMessage(MCS_BOUND);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    break;</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                case MCS_BOUND: {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_bound");</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    if (msg.obj != null) {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        mContainerService = (IMediaContainerService) msg.obj;</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    if (mContainerService == null) {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        // Something seriously wrong. Bail out</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        Slog.e(TAG, "Cannot bind to media container service");</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        for (HandlerParams params : mPendingInstalls) {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            mPendingInstalls.remove(0);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            // Indicate service bind error</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            params.serviceError();</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        mPendingInstalls.clear();</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    } else if (mPendingInstalls.size() > 0) {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        HandlerParams params = mPendingInstalls.get(0);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        if (params != null) {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                            params.startCopy();</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    } else {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        // Should never happen ideally.</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                        Slog.w(TAG, "Empty queue");</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                    break;</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            ****************省略若干**********************</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">}</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">}             </span></span></p>

public final boolean sendMessage (Message msg)

public final boolean sendEmptyMessage (int what)

兩者引數有別。

然後呼叫抽象類HandlerParams中的一個startCopy()方法

abstract class HandlerParams {

final void startCopy() {

   ***************若干if語句判定否這打回handler訊息*******

handleReturnCode();

}
}

handleReturnCode()複寫了兩次其中有一次是刪除時要呼叫的,只列出安裝呼叫的一個方法

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln"> </span><span class="lit">@Override</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">        </span><span class="kwd">void</span><span class="pln"> handleReturnCode</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;"><span class="pln">            </span><span class="com">// If mArgs is null, then MCS couldn't be reached. When it</span></span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            // reconnects, it will try again to install. At that point, this</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            // will succeed.</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            if (mArgs != null) {</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">                processPendingInstall(mArgs, mRet);</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">            }</span></span></p><p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="font-size: 15px; line-height: 24px;">        }</span></span></p>

這時可以清楚的看見 processPendingInstall()被呼叫。

其中run()方法如下

<p style="margin-bottom: 0.21cm;"><span style="font-family: Arial;"><span style="fo