1. 程式人生 > >androidapk安裝過程詳解

androidapk安裝過程詳解

文章轉自:http://piziyuyu.blog.163.com/blog/static/96323832201110144851181/

下面各個步驟都已經分析清楚,加步驟的話就在每個階段的開始和接受加上廣播的推送即可。

APKAndroid Package的縮寫,即Android安裝包。APK是類似Symbian SisSisx的檔案格式。通過將APK檔案直接傳到Android模擬器或Android手機中執行即可安裝。

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

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

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

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

4.第三方應用安裝――通過SD卡里的APK檔案安裝,有安裝介面

二、應用安裝的流程及路徑
應用安裝涉及到如下幾個目錄:

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

在這個文件中主要介紹的是第三方應用安裝的完整過程

安裝SD卡里的APK檔案。

呼叫安裝介面完成安裝

pm.installPackage(mPackageURI,observer, installFlags);

看到這裡,我有一個疑問:

PackageManager.java中的installPackage的原型如下:

public abstract void installPackage(

Uri packageURI, IPackageInstallObserver observer, int flags,

String installerPackageName);

然後看到所有Packageanager.java裡面的方法基本都是抽象的,經過不斷尋找,終於在檔案

ContextImpl.java/framework/bash/core/java/android/app/ContextImpl.java)中找到了實現的位置首先通過getPackageManager()獲取到包管理器的控制代碼,然後再呼叫它裡邊的installPackage進行安裝。

public PackageManager getPackageManager() {

if (mPackageManager != null) {

return mPackageManager;

}

IPackageManager pm = ActivityThread.getPackageManager();

if (pm != null) {

// Doesn't matter if we make more than one instance.

return (mPackageManager=newApplicationPackageManager(this,pm));

}

return null;

}

ApplicationPackageManager繼承了PackageManager,該類實現了所有的抽象方法

public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,

String installerPackageName) {

try {

mPM.installPackage(packageURI,observer,flags,installerPackageName);

} catch (RemoteException e) {

// Should never happen!

}

}

這樣就呼叫了PackageManagerService.java/framework/base/services/java/com/android/server/PackageManagerService.java)中的installPackage裡面。

public void installPackage(

final Uri packageURI, final IPackageInstallObserver observer, final int flags,

final String installerPackageName) {

mContext.enforceCallingOrSelfPermission(

android.Manifest.permission.INSTALL_PACKAGES, null);

Message msg = mHandler.obtainMessage(INIT_COPY);

msg.obj = new InstallParams(packageURI, observer, flags,

installerPackageName);

mHandler.sendMessage(msg);

}

通過sendMessage將訊息傳送給PackageHandler中的handleMessage(Message msg)接收。

if (!mBound) {

// If this is the only one pending we might

// have to bind to the service again.

if (!connectToService()) {

Slog.e(TAG, "Failed to bind to media container service");

params.serviceError();

return;

} else {

// Once we bind to the service, the first

// pending request will be processed.

mPendingInstalls.add(idx,params);

}

} else {

mPendingInstalls.add(idx,params);

// Already bound to the service. Just make

// sure we trigger off processing the first request.

if (idx == 0) {

mHandler.sendEmptyMessage(MCS_BOUND);

}

}

分析INIT_COPY裡面的邏輯程式碼,可以知道首先檢查是否已經和IMediaContainerService服務繫結,如果沒有則與該服務嘗試連線,負責將接收到的安裝包新增到mPendingInstalls變數裡邊,但是mPendingInstalls這裡邊的請求在什麼時候被處理掉的呢?

public void onServiceConnected(ComponentName name, IBinder service) {

if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");

IMediaContainerService imcs =

IMediaContainerService.Stub.asInterface(service);

mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND,imcs));

}

原來在第一次繫結該服務成功後就傳送了MCS_BOUND訊息,呼叫到HandlerParamsstartCopy方法準備安裝

else if (mPendingInstalls.size() > 0) {

HandlerParams params = mPendingInstalls.get(0);

if (params != null) {

params.startCopy();

}

}

接下來在該方法中呼叫mHandler.sendEmptyMessage(MCS_UNBIND)PackageHandler接收到MSC_UNBIND 訊息以後會進入以下邏輯塊

if (mPendingInstalls.size() == 0) {

if (mBound) {

disconnectService();

}

} else {

// There are more pending requests in queue.

// Just post MCS_BOUND message to trigger processing

// of next pending install.

mHandler.sendEmptyMessage(MCS_BOUND);

}

如果mPendingInstalls還有未處理的請求繼續重複上述步驟,否則斷開與IMediaContainerService建立的服務。

抽象類HandlerParams中實現了方法startCopy(),而handleStartCopy()handleReturnCode()兩個方法的實現則是在HandlerParams的子類InstallParams裡邊。

final void startCopy() {

try {

if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy");

retry++;

if (retry > MAX_RETRIES) {

Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");

mHandler.sendEmptyMessage(MCS_GIVE_UP);

handleServiceError();

return;

} else {

handleStartCopy();

if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_UNBIND");

mHandler.sendEmptyMessage(MCS_UNBIND);

}

} catch (RemoteException e) {

if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT");

mHandler.sendEmptyMessage(MCS_RECONNECT);

}

handleReturnCode();

}

InstallParams裡邊handleStartCopy()主要實現的功能是獲取安裝位置資訊以及複製apk到指定位置。

if (ret == PackageManager.INSTALL_SUCCEEDED) {

// Create copy only if we are not in an erroneous state.

// Remote call to initiate copy using temporary file

ret=mArgs.copyApk(mContainerService,true);

}

抽象類InstallArgs中的copyApk負責複製APK檔案,具體實現在子類FileInstallArgsSdInstallArgs裡面。

下面我們看一下FileInstallArgs中實現該方法的關鍵部分

if (imcs.copyResource(packageURI,out)) {

ret = PackageManager.INSTALL_SUCCEEDED;

}

通過IMediaContainerService服務將APK複製到指定目錄(data/app/vmdl26489.tmp)

SdInstallArgs中該方法實現的原理差不多,就不再贅述。

我們再回到InstallParams裡面的handleReturnCode()中來,該方法呼叫processPendingInstall方法處理安裝。

@Override

void handleReturnCode() {

processPendingInstall(mArgs,mRet);

}

private void processPendingInstall(final InstallArgs args, final int currentStatus) {

// Queue up an async operation since the package installation may take a little while.

mHandler.post(new Runnable() {

public void run() {

/** 省略若干**/

if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {

args.doPreInstall(res.returnCode);

synchronized (mInstallLock) {

installPackageLI(args,true,res);

}

args.doPostInstall(res.returnCode);

}

/** 省略若干**/

if (!doRestore) {

// No restore possible, or the Backup Manager was mysteriously not

// available -- just fire the post-install work request directly.

if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);

Messagemsg=mHandler.obtainMessage(POST_INSTALL,token,0);

mHandler.sendMessage(msg);

}

}

});

}

方法processPendingInstall中關鍵的操作已經用紅色標出,主要的安裝流程都在這個方法裡面。安裝過程放在一個執行緒裡面,因為安裝需要一定的時間(這裡有個問題,Handler中有一個MessageQueue處理所有的Message佇列,那麼通過post進來一個Runnable,這個Runnable是在什麼時候處理的?)。處理流程是預安裝-安裝-安裝收尾-傳送POST_INSTALL訊息

預安裝:下面這個doPreInstall的實現是來自InstallArgs的直接子類SdInstallArgs,所做的工作是檢查當前安裝包的狀態以及確保SDCARD的掛載,並返回狀態資訊。從中我們可以看出來預安裝功能就是在安裝前確保安裝環境的可靠。

int doPreInstall(int status) {

if (status != PackageManager.INSTALL_SUCCEEDED) {

// Destroy container

PackageHelper.destroySdDir(cid);

} else {

boolean mounted = PackageHelper.isContainerMounted(cid);

if (!mounted) {

cachePath = PackageHelper.mountSdDir(cid, getEncryptKey(), Process.SYSTEM_UID);

if (cachePath == null) {

return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;

}

}

}

return status;

}

安裝:對mHistallLock加了鎖,表明同時只能有一個安裝包進行安裝,installPackageLI稍候介紹。

相關推薦

androidapk安裝過程

文章轉自:http://piziyuyu.blog.163.com/blog/static/96323832201110144851181/ 下面各個步驟都已經分析清楚,加步驟的話就在每個階段的開始和接受加上廣播的推送即可。 APK是Android Package的縮寫,即Androi

linux--系統啟動及安裝過程

linux啟動先通過一張圖來簡單了解下整個系統啟動的流程,整個過程基本可以分為POST-->BIOS-->MBR(GRUB)-->Kernel-->Init-->Runlevel本文出自 “運維自動化” 博客,請務必保留此出處http://shower.blog.51cto.co

CentOS 7系統KVM虛擬機安裝過程

選項 安裝 svm roc 支持 linu 系統 kvm flags 一、如何安裝KVM 這裏我是在Windows系統中使用VMware Workstaion安裝了一臺Linux的虛擬機來進行KVM的安裝操作的。首先,我們需要了解我們安裝的Linux系統的CPU是否支持KV

CentOS 7下Cloudera Manager及CDH 6.0.1安裝過程

一、概念介紹 1、CDH 概覽 CDH是Apache Hadoop和相關專案的最完整、最受測試和最流行的發行版。CDH提供Hadoop的核心元素-可伸縮儲存和分散式計算-以及基於web的使用者介面和重要的企業功能。CDH是Apache許可的開放原始碼,是唯一提供統一批處理、互動式SQL和互動式搜尋以及基於

python安裝過程以及到底學python2還是python3?

1.python安裝 官網下載對應版本https://www.python.org/,強烈建議官網,其他下載站總會繫結一些亂七八糟的軟體。 雙擊啟動安裝程式,選擇Customize installation 自定義安裝,勾選Add python to PATH 新增路徑,勾選後安裝程式會自

Apache Hadoop1.1.1+Apache Oozie3.3.2搭建安裝過程(親測)

寫在前面: 最近需要定製的原因,需要將原來Cloudera版本的Hadoop更改為Apache版本的Hadoop和Oozie,對官方文件的學習,發現Hadoop1.1.1和Oozie3.3.2的組合比較好,所以,經過幾天的搭建,終於成功了,現在把心得分享出來,希望給需要的朋

PHPnow圖文安裝過程

由於上一篇用PHPnow搭建本地PHP執行環境沒有詳細介紹安裝過程,可能會有很多人在安裝的過程中不會很順利,會出現很多問題,所以再附上安裝過程,可以使安裝一目瞭然,容易快速安裝好。 執行-1.4.x.exe 出現下圖所示。回車即可。 在自動解壓完畢後,將自動執行

caffe安裝過程linux版本

編者語:如果你想深入研究深度學習,強烈建議你有一塊好的顯示卡。caffe支援cpu、gpu兩個版本,強烈建議使用gpu版本訓練模型(因為速度真的非常快)。由於gpu版本需要安裝cuda和cudnn,

元資料與資料治理|Apache Atlas安裝過程(初步版本)

                                  Apache Atlas安裝過程詳解 一 

caffe安裝過程

sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler sudo apt-get install

CentOS 7下Cloudera Manager及CDH 5.14.0安裝過程

大家都知道,Apache Hadoop的配置很繁瑣,而且很零散,為此Cloudera公司提供了Clouder Manager工具,而且還封裝了Apache Hadoop,flume,spark,hive,hbase等大資料產品形成自己特色的CDH產品,再使用CM進行安裝,很大

Redhat/CentOS6.2 x86系統KVM虛擬機器安裝過程

什麼是 KVM ? KVM 是指基於 Linux 核心的虛擬機器(Kernel-based Virtual Machine)。 2006 年 10 月,由以色列的Qumranet 組織開發的一種新的“虛擬機器”實現方案。 2007 年 2 月釋出的 Linux 2.6.20

SQL Server 2012 Enterprise Edition安裝過程(包含每一步設定的含義)

一、啟動安裝程式,點選“安裝”選項卡,選擇“全新SQL Server獨立安裝或向現有安裝新增功能”。(首次安裝資料庫系統或向現有資料庫系統新增功能,均選擇此選項) 二、隨後,安裝程式進行“安裝程式支援規則”的檢測,來分析要成功安裝SQL Server 2012 E

Linux中centos中httpd源碼安裝過程

服務 vpd ces vim 1.7 指令 yum工具 清理 文件解壓 在Linux中軟件安裝有兩大類,一類是軟件包安裝,一類是源代碼安裝。軟件包安裝就是指將編譯好的二進制封裝成rpm包,可以直接使用rpm工具和yum工具安裝。源代碼安裝是指沒有編譯成二進制,需要通過手動編

Linux安裝sbt過程

                     1. 下載sbt安裝包下載地址點這裡。2. 解壓檔案tar zxvf sbt-0.13.9.tgz13. 建立啟動sbt的指令碼檔案在./sbt目錄下面新建檔名為sbt的文字檔案$ cd ./sbt$ vim sbt# 在sbt文字檔案中新增如下資訊:BT_OPTS=

解除安裝安裝Node.js與npm過程

下面記錄一下在本地 Windwos 環境用 vagrant 搭建的虛擬機器(Homestaead)和生產環境阿里雲 CentOS 系統安裝 Node.js 的步驟,以及 npm 安裝依賴的不同之處。 使用原始碼編譯的方式安裝 node.js.首先將機子上的 Node.js

myeclipse安裝maven過程

首先要先配置自己本機的java環境變數,在系統變數新增 JAVA_HOME = C:\Program Files\Java\jdk1.6.0_17 ,然後在path系統變數中新增 %JAVA_HOME %\bin.這是安裝maven的必須條件,不能缺少。 然後下載mave

kali linux安裝vmware tools過程

一、VMware tools 簡介       VMware Tools是VMware虛擬機器中自帶的一種增強工具,是VMware提供的增強虛擬顯示卡和硬碟效能、以及同步虛擬機器與主機時鐘的驅動程式。只有在VMware虛擬機器中安裝好了VMware Tools,才能實現主機

rpm包打包過程(二)——製作原始碼安裝

製作原始碼安裝包(.tar.gz) 1.      解決依賴的軟體: 系統環境:[紅帽企業Linux.6.4.64位伺服器版].rhel-server-6.4-x86_64 原始碼製作中使用到的軟體為GNU M4,GNU autoconf,GNU automake;GNU

Rational Rose 2007安裝步驟及解決安裝過程中的一些問題(解決虛擬光碟機載入不了bin檔案問題)

首先下載兩個檔案: ①:Rational.Rose.Enterprise.v7.0-TFTISO.bin ②:license.upd 網上下載不到(我是網上下載的)的可以找我要(給我留下你的百度雲,我分享給你o(^▽^)o)! 下面來講一講安裝過程: 1、解壓後兩個檔