今天我們一起看,看看系統(tǒng)是如何在你的手機(jī)上安裝應(yīng)用程序的。
入口
單擊Apk安裝后,將出現(xiàn)以下界面
這是Android Framework提供的軟件包安裝程序。頁(yè)面:packageInstallerActivity
package com . Android . package installer;
publicclasspackageinstalleractivityextendsactivity {
公共void onclick (viewv) {
If(v==mOk){
if(){
//.省略一些細(xì)節(jié)
start install();//開(kāi)始安裝
}
}elseif(v==mCancel){
//Cancelandfinish
}
}
PrivatevoidstartInstall(){
//startsubactivitytoactuallyinstalltheapplication
intent new intent=new intent();
紐因,
MPKGIN);
紐因(MPACKAGEURI);
新的in (this,in);
.//newIn其他參數(shù)
start activity(newIntent);
finish();
}
}
在此頁(yè)面上單擊“安裝”后,安裝包信息將通過(guò)internet傳遞給installing。此activity.installing的作用主要是將包信息發(fā)送到PMS,并處理回調(diào)。
磷
當(dāng)然,從onCreate開(kāi)始。
protectedvoidoncreate(@ nullablebundlesavedinstancestate){
applicationinfoappinfo=getintent()
.getParcelableExtra);
Mpackageuri=getintent()。get data();
.
根據(jù)//mPackageURI創(chuàng)建相應(yīng)的文件
FinalFilesourceFile=newFile();
//顯示應(yīng)用程序信息圖標(biāo)、應(yīng)用程序名稱或程序包名稱
Packageu (this,packageu (this,appinfo,
源文件)、r . id . app _ snippet);
//創(chuàng)建并裝配傳遞會(huì)話參數(shù)的sessionParams
PackageInparams=newPackageIn(
帕克金。MODE _ FULL _ INSTALL);
=package manager . install _ full _ app;
.
=
GetIntent()。getStringExtra);
file file=newFile();
對(duì)//APK執(zhí)行輕量級(jí)語(yǔ)法分析,并將語(yǔ)法分析結(jié)果分配給與SessionParams相關(guān)的字段
Packageparpkg=packagepar(文件,0);
);
);
(請(qǐng)參閱)
PackageHel(pkg、false、);
//在InstallEventReceiver中注冊(cè)觀察者時(shí),將返回新的mInstallId
//InstallEventReceiver是可以通過(guò)EventResultPersister接收所有安裝事件的BroadcastReceiver
//其中事件將回調(diào)到this : launchfinishbasedonresult
min stallid=installeventreceiver
.addObserver(this、Even、
this :3360 launchfinishbasedonresult);
Try{
?//?PackageInstaller?的?createSession? ????????//?方法內(nèi)部會(huì)通過(guò)?IPackageInstaller?與?PackageInstallerservice進(jìn)行進(jìn)程間通信, ????????//?最終調(diào)用的是?PackageInstallerService?的?createSession?方法來(lái)創(chuàng)建并返回?mSessionId ????????mSessionId?=?getPackageManager().getPackageInstaller().createSession(params); ????}?catch?(IOException?e)?{ ????????launchFailure,?null); ????} ??? ?? }In
接下來(lái)是 onResume, 通過(guò) InstallingAsyncTask 做一些異步工作
protected?void?onResume()?{
????();
????//?This?is?the?first?onResume?in?a?single?life?of?the?activity
????if?(mInstallingTask?==?null)?{
????????PackageInstaller?installer?=?getPackageManager().getPackageInstaller();
????????PackageIn?sessionInfo?=?in(mSessionId);
????????if?(sessionInfo?!=?null?&&?!())?{
????????????mInstallingTask?=?new?InstallingAsyncTask();
????????????mIn();
????????}?else?{
????????????//?we?will?receive?a?broadcast?when?the?install?is?finished
????????????mCancelBu(false);
????????????setFinishOnTouchOutside(false);
????????}
????}
}
InstallingAsyncTask
private?final?class?InstallingAsyncTask?extends?AsyncTask<Void,?Void,
????????????PackageIn;?{
????????@Override
????????protected?PackageIn?doInBackground(Void...?params)?{
????????????PackageIn?session;
????????????session?=?getPackageManager().getPackageInstaller().openSession(mSessionId);
????????????(0);
????????????File?file?=?new?File());
????????????OutputStream?out?=?("PackageInstaller",?0,?sizeBytes)
????????????InputStream?in?=?new?FileInputStream(file)
????????????long?sizeBytes?=?();
????????????byte[]?buffer?=?new?byte[1024?*?1024];
????????????while?(true)?{
????????????????int?numRead?=?in.read(buffer);
????????????????if?(numRead?==?-1)?{
????????????????????(out);
????????????????????break;
????????????????}
???????????????//?將?APK?文件通過(guò)?IO?流的形式寫(xiě)入到?PackageIn?中
????????????????out.write(buffer,?0,?numRead);
????????????????if?(sizeBytes?>?0)?{
????????????????????float?fraction?=?((float)?numRead?/?(float)?sizeBytes);
????????????????????(fraction);
????????????????}
?????????????}
?????????????return?session;?
????????}
????????@Override
????????protected?void?onPostExecute(PackageIn?session)?{?
????????????Intent?broadcastIntent?=?new?Intent(BROADCAST_ACTION);
????????????broadca);
????????????broadca(
????????????????????getPackageManager().getPermissionControllerPackageName());
????????????broadcastIn,?mInstallId);
????????????PendingIntent?pendingIntent?=?PendingIn(
????????????????????In,
????????????????????mInstallId,
????????????????????broadcastIntent,
????????????????????PendingIn);
????????????//?調(diào)用?PackageIn?的?commit?方法,進(jìn)行安裝
????????????());?
????????}
????}
來(lái)看下 PackageIn 里的實(shí)現(xiàn)
public?static?class?Session?implements?Closeable?{
????private?IPackageInstallerSession?mSession;
????public?void?commit(@NonNull?IntentSender?statusReceiver)?{
????????try?{
????????????mSe(statusReceiver,?false);
????????}?catch?(RemoteException?e)?{
????????????throw?e.rethrowFromSystemServer();
????????}
????}
}
mSession 的類(lèi)型為 IPackageInstallerSession,這說(shuō)明要通過(guò) IPackageInstallerSession 來(lái)進(jìn)行進(jìn)程間的通信,最終會(huì)調(diào)用PackageInstallerSession 的 commit 方法,劇透一下在這個(gè)類(lèi)執(zhí)行完后,就會(huì)進(jìn)入鼎鼎大名的 PMS 去真正的執(zhí)行安裝了 :
public?class?PackageInstallerSession?extends?IPackageIn?{
????public?void?commit(@NonNull?IntentSender?statusReceiver,?boolean?forTransfer)?{
????????//?將包的信息封裝為?PackageInstallObserverAdapter
????????final?PackageInstallObserverAdapter?adapter?=?new?PackageInstallObserverAdapter(
??????????mContext,?statusReceiver,?sessionId,
??????????isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(),?userId);
????????mRemoteObserver?=?ada();
????????//?通過(guò)?Handler?處理消息事件
????????mHandler.obtainMessage(msg_COMMIT).sendToTarget();
????}
??
????private?final?Handler.Callback?mHandlerCallback?=?new?Handler.Callback()?{
????????@Override
????????public?boolean?handleMessage(Message?msg)?{
????????????switch?)?{
????????????????case?MSG_COMMIT:
????????????????????commitLocked();
????????????????????break;
????????????}
????????}
????};
??
????private?final?PackageManagerService?mPm;
????private?void?commitLocked()?throws?PackageManagerException?{
????????mPm.installStage(mPackageName,?stageDir,?...);
????}
??
}
mPm 就是系統(tǒng)服務(wù) PackageManagerService。installStage 方法就是正式開(kāi)始 apk 的安裝過(guò)程。這個(gè)過(guò)程包括兩大步:拷貝安裝包、裝載代碼
拷貝安裝包
繼續(xù)看 installStage 的代碼
//?PackageManagerService.java
void?installStage(String?packageName,?File?stagedDir,...)?{
????final?Message?msg?=?mHandler.obtainMessage(INIT_COPY);
????//?把之前傳入的?sessionParams?安裝信息,及其它信息封裝成?InstallParams
????final?InstallParams?params?=?new?InstallParams(origin,?null,?observer,
????????,?installerPackageName,?,
????????verificationInfo,?user,?,
????????,?signingDetails,?installReason);
????mHandler.sendMessage(msg);
}
發(fā)送的消息 INIT_COPY 從名字上就知道是去初始化復(fù)制
class?PackageHandler?extends?Handler?{
????void?doHandleMessage(Message?msg)?{
????????switch?)?{
????????????case?INIT_COPY:?{
????????????????HandlerParams?params?=?(HandlerParams)?m;
????????????????//?調(diào)用 connectToService 方法連接安裝 apk 的 Service 服務(wù)。
????????????????if?(!connectToService())?{
????????????????????return;
????????????????}?else?{
?????????????????????//?Once?we?bind?to?the?service,?the?first
?????????????????????//?pending?request?will?be?processed.
?????????????????????mPendingIn(idx,?params);
????????????????}
????????????}
????????}
????}
????private?boolean?connectToService()?{
?????????//?通過(guò)隱式?Intent?綁定?Service,實(shí)際綁定的?Service?是?DefaultContainerService?
?????????Intent?service?=?new?Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
?????????if?(service,?mDefContainerConn,
?????????????????Con,?U))?{
?????????????mBound?=?true;
?????????????return?true;
?????????}
?????????return?false;
???}
}
當(dāng)綁定 Service 成功之后,會(huì)在 mDefContainerConn 的 onServiceConnection 方法中發(fā)送一個(gè)綁定操作的 Message,如下所示:
class?DefaultContainerConnection?implements?ServiceConnection?{
????public?void?onServiceConnected(ComponentName?name,?IBinder?service)?{
????????final?IMediaContainerService?imcs?=?IMediaCon
????????????????.asInterface(service));
????????mHandler.sendMessage(MCS_BOUND,?imcs));
????}
}
//?MCS_BOUND?還是在前面的?PackageHandler?處理,直接截取相關(guān)代碼
{
????HandlerParams?params?=?mPendingIn(0);
????if?())?{
????????if?()?>?0)?{
????????????mPendingIn(0);
????????}
????}
}
mPendingInstalls 是一個(gè)等待隊(duì)列,里面保存所有需要安裝的 apk 解析出來(lái)的 HandlerParams 參數(shù)(前面在 INIT_COPY 處理時(shí) add),從 mPendingInstalls 中取出第一個(gè)需要安裝的 HandlerParams 對(duì)象,并調(diào)用其 startCopy 方法,在 startCopy 方法中會(huì)繼續(xù)調(diào)用一個(gè)抽象方法 handleStartCopy 處理安裝請(qǐng)求。通過(guò)之前的分析,我們知道 HandlerParams 實(shí)際類(lèi)型是 InstallParams 類(lèi)型,因此最終調(diào)用的是 InstallParams 的 handlerStartCopy 方法,這是整個(gè)安裝包拷貝的核心。
class?InstallParams?extends?HandlerParams?{
??
????public?void?handleStartCopy()?throws?RemoteException?{
????????if?)?{
????????????//?設(shè)置安裝標(biāo)志位,決定是安裝在手機(jī)內(nèi)部存儲(chǔ)空間還是?sdcard?中
????????????if??!=?null)?{
????????????????installFlags?|=?PackageManager.INSTALL_INTERNAL;
????????????????installFlags?&=?~PackageManager.INSTALL_EXTERNAL;
????????????}?
????????}
????????
????????//?判斷安裝位置
????????final?boolean?onSd?=?(installFlags?&?PackageManager.INSTALL_EXTERNAL)?!=?0;
????????final?boolean?onInt?=?(installFlags?&?PackageManager.INSTALL_INTERNAL)?!=?0;
????????final?boolean?ephemeral?=?(installFlags?&?PackageManager.INSTALL_INSTANT_APP)?!=?0;
??????
????????final?InstallArgs?args?=?createInstallArgs(this);?
????????//?...??
????????ret?=?args.copyApk(mContainerService,?true);
????}
??
????private?InstallArgs?createInstallArgs(InstallParams?params)?{
????????if??!=?null)?{
????????????return?new?MoveInstallArgs(params);
????????}?else?{
????????????return?new?FileInstallArgs(params);
????????}
????}
}
正常的流程下,createInstallArgs 返回的是 FileInstallArgs 對(duì)象
FileInstallArgs 的 copyApk 方法
int?copyApk(IMediaContainerService?imcs,?boolean?temp)?throws?RemoteException?{
????return?doCopyApk(imcs,?temp);
}
private?int?doCopyApk(IMediaContainerService?imcs,?boolean?temp)?throws?RemoteException?{
????//?創(chuàng)建存儲(chǔ)安裝包的目標(biāo)路徑,實(shí)際上是?/data/app/?應(yīng)用包名目錄
????final?File?tempDir?=?mIn(volumeUuid,?isEphemeral);
????final?IParcelFileDescriptorFactory?target?=?new?IParcelFileDe()?{
????????@Override
????????public?ParcelFileDescriptor?open(String?name,?int?mode)?throws?RemoteException?{
????????????final?File?file?=?new?File(codeFile,?name);
????????????final?FileDescriptor?fd?=?Os.open(),
????????????????????O_RDWR?|?O_CREAT,?0644);
????????????Os.chmod(),?0644);
????????????return?new?ParcelFileDescriptor(fd);
????????}
????};
????//?調(diào)用服務(wù)的 copyPackage 方法將安裝包 apk 拷貝到目標(biāo)路徑中;
????ret?=?imcs.copyPackage.getAbsolutePath(),?target);
????//?將 apk 中的動(dòng)態(tài)庫(kù) .so 文件也拷貝到目標(biāo)路徑中。
????ret?=?Na(handle,?libraryRoot,
????????????????????????abiOverride);
}
這里的 IMediaContainerService imcs 就是之前連接上的 DefaultContainerService
DefaultContainerService
copyPackage 方法本質(zhì)上就是執(zhí)行 IO 流操作,具體如下:
//?new?IMediaCon()
public?int?copyPackage(String?packagePath,?IParcelFileDescriptorFactory?target)?{
????PackageLite?pkg?=?null;
????final?File?packageFile?=?new?File(packagePath);
????pkg?=?PackagePar(packageFile,?0);
????return?copyPackageInner(pkg,?target);
}
//?DefaultContainerService
private?int?copyPackageInner(PackageLite?pkg,?IParcelFileDescriptorFactory?target){
????copyFile,?target,?"ba;);
????if?(!ArrayU))?{
????????for?(int?i?=?0;?i?<?;?i++)?{
????????????copyFile[i],?target,?"split_"?+?[i]?+?".apk");
????????}
????}
????return?PackageManager.INSTALL_SUCCEEDED;
}
private?void?copyFile(String?sourcePath,?IParcelFileDescriptorFactory?target,?String?targetName){
????InputStream?in?=?null;
????OutputStream?out?=?null;
????try?{
????????in?=?new?FileInputStream(sourcePath);
????????out?=?new?ParcelFileDe(
????????????????(targetName,?ParcelFileDe));
????????FileU(in,?out);
????}?finally?{
????????IoU(out);
????????IoU(in);
????}
}
最終安裝包在 data/app 目錄下以 ba 的方式保存,至此安裝包拷貝工作就已經(jīng)完成。
裝載代碼
安裝包拷貝完成,就要開(kāi)始真正安裝了。代碼回到上述的 HandlerParams 中的 startCopy 方法:
private?abstract?class?HandlerParams?{
????final?boolean?startCopy()?{
????????...
????????handleStartCopy();
????????handleReturnCode();
????}
}
class?InstallParams?extends?HandlerParams?{
????@Override
????void?handleReturnCode()?{
????????//?If?mArgs?is?null,?then?MCS?couldn't?be?reached.?When?it
????????//?reconnects,?it?will?try?again?to?install.?At?that?point,?this
????????//?will?succeed.
????????if?(mArgs?!=?null)?{
????????????processPendingInstall(mArgs,?mRet);
????????}
????}??
??
????private?void?processPendingInstall(final?InstallArgs?args,?final?int?currentStatus)?{
?????????mHandler.post(new?Runnable()?{
?????????????public?void?run()?{
?????????????????PackageInstalledInfo?res?=?new?PackageInstalledInfo();
?????????????????if??==?PackageManager.INSTALL_SUCCEEDED)?{
????????????????????//?預(yù)安裝操作,主要是檢查安裝包的狀態(tài),確保安裝環(huán)境正常,如果安裝環(huán)境有問(wèn)題會(huì)清理拷貝文件
????????????????????args.doPreInstall);
????????????????????synchronized?(mInstallLock)?{
????????????????????????//?安裝階段
????????????????????????installPackageTracedLI(args,?res);
????????????????????}
????????????????????args.doPostInstall,?res.uid);
????????????????}
????????????????...
?????????????}
?????????}
????}
}
installPackageLI
installPackageTracedLI 方法中添加跟蹤 Trace,然后調(diào)用 installPackageLI 方法進(jìn)行安裝。這個(gè)方法有 600 行,取部分關(guān)鍵代碼:
private?void?installPackageLI(InstallArgs?args,?PackageInstalledInfo?res)?{
????...
????PackageParser?pp?=?new?PackageParser();
????final?PackagePar?pkg;
????//?1.?parsePackage
????pkg?=?(tmpPackageFile,?parseFlags);
????
????//?2.?校驗(yàn)安裝包簽名
????final?KeySetManagerService?ksms?=?mSe;
????if?(signatureCheckPs,?scanFlags))?{
????????if?(!k(signatureCheckPs,?pkg))?{
????????????res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,?"Package?"
????????????????????+??+?"?upgrade?keys?do?not?match?the?"
????????????????????+?"previously?installed?version");
????????????return;
????????}
????}
????
????//?3.?設(shè)置相關(guān)權(quán)限,生成、移植權(quán)限?
????int?N?=?();
????for?(int?i?=?N-1;?i?>=?0;?i--)?{
????????final?PackagePar?perm?=?(i);
????????...
????}
??
????//?4.?生成安裝包Abi(Application?binary?interface,應(yīng)用二進(jìn)制接口)
????try?{
????????String?abiOverride?=?(TextU)??
????????????args.abiOverride?:?);
????????final?boolean?extractNativeLibs?=?!();
????????derivePackageAbi(pkg,?abiOverride,?extractNativeLibs);
????}?catch?(PackageManagerException?pme)?{
????????res.setError(INSTALL_FAILED_INTERNAL_ERROR,?"Error?deriving?application?ABI");
????????return;
????}
??
????//?5.?凍結(jié)?APK,執(zhí)行替換安裝?或?新安裝,?
????try?(PackageFreezer?freezer?=?freezePackageForInstall(pkgName,?installFlags,
????????????"installPackageLI"))?{
????????if?(replace)?{
????????????replacePackageLIF(pkg,?parseFlags,?scanFlags,?args.user,
????????????????????installerPackageName,?res,?args.installReason);
????????}?else?{
????????????private?void?installNewPackageLIF((pkg,?parseFlags,?scanFlags?|?SCAN_DELETE_DATA_ON_FAILURES,
????????????????????args.user,?installerPackageName,?volumeUuid,?res,?args.installReason);
????????}
????}
??
????//?5.?優(yōu)化dex文件(實(shí)際為?dex2oat?操作,用來(lái)將?apk?中的?dex?文件轉(zhuǎn)換為?oat?文件)
????if?(performDexopt)?{?
??????????mPackageDexO(pkg,?,
??????????????????null?/*?instructionSets?*/,
??????????????????getOrCreateCompilerPackageStats(pkg),
??????????????????mDexManager.getPackageUseInfoOrDefault),
??????????????????dexoptOptions);?
????}
????...
}
最后我們來(lái)看一下 installNewPackageLIF
private?void?installNewPackageLIF(PackagePar?pkg,?final?@ParseFlags?int?parseFlags,
????????????final?@ScanFlags?int?scanFlags,...)?{
????//?繼續(xù)掃描解析?apk?安裝包文件,保存?apk?相關(guān)信息到?PMS?中,并創(chuàng)建?apk?的?data?目錄,具體路徑為?/data/data/應(yīng)用包名
????PackagePar?newPackage?=?scanPackageTracedLI(pkg,?parseFlags,?scanFlags,
????????Sy(),?user);
????//?更新系統(tǒng)設(shè)置中的應(yīng)用信息,比如應(yīng)用的權(quán)限信息
????updateSettingsLI(newPackage,?installerPackageName,?null,?res,?user,?installReason);
????if??==?PackageManager.INSTALL_SUCCEEDED)?{
?????????//?安裝然后準(zhǔn)備?APP?數(shù)據(jù)?
?????????prepareAppDataAfterInstallLIF(newPackage);
?????}?else?{
?????????//?如果安裝失敗,則將安裝包以及各種緩存文件刪除
?????????deletePackageLIF(pkgName,?U,?false,?null,
?????????????????PackageManager.DELETE_KEEP_DATA,?res.removedInfo,?true,?null);
?????}
}
prepareAppDataAfterInstallLIF 還會(huì)有一系列的調(diào)用
???prepareAppDataAfterInstallLIF()
->?prepareAppDataLIF()
->?prepareAppDataLeafLIF()
->?mIn(...)
final?Installer?mInstaller;
private?void?prepareAppDataLeafLIF(...)?{
???//?最終調(diào)用?系統(tǒng)服務(wù)?Installer?安裝
???ceDataInode?=?mIn(volumeUuid,?packageName,?userId,?flags,
????????????????????appId,?seInfo,?a);?????
}???
public?class?Installer?extends?SystemService?{
???...
}
至此整個(gè) apk 的安裝過(guò)程結(jié)束,實(shí)際上安裝成功之后,還會(huì)發(fā)送一個(gè) App 安裝成功的廣播 ACTION_PACKAGE_ADDED。手機(jī)桌面應(yīng)用注冊(cè)了這個(gè)廣播,當(dāng)接收到應(yīng)用安裝成功之后,就將 apk 的啟動(dòng) icon 顯示在桌面上。
總結(jié)
在手機(jī)上僅僅是點(diǎn)一下安裝按鈕而已,背后卻有著這么繁瑣的流程,相信通過(guò)今天的學(xué)習(xí)大家應(yīng)該能對(duì)系統(tǒng)的應(yīng)用安裝流程有一個(gè)完整的認(rèn)知。回顧一下安裝的流程如下:
- 點(diǎn)擊 APK 安裝,會(huì)啟動(dòng) PackageInstallerActivity,再進(jìn)入 InstallInstalling 這兩個(gè) Activity 顯示應(yīng)用信息
- 點(diǎn)擊頁(yè)面上的安裝,將 APK 信息存入 PackageIn 傳到 PMS
- PMS會(huì)做兩件事,拷貝安裝包和裝載代碼
- 在拷貝安裝包過(guò)程中會(huì)開(kāi)啟 Service 來(lái) copyAPK 、檢查apk安裝路徑,包的狀態(tài)
- 拷貝完成以 ba 形式存在/data/app包名下
- 裝載代碼過(guò)程中,會(huì)繼續(xù)解析 APK,把清單文件內(nèi)容存放于 PMS
- 對(duì) apk 進(jìn)行簽名校驗(yàn)
- 安裝成功后,更新應(yīng)用設(shè)置權(quán)限,發(fā)送廣播通知桌面顯示APP圖標(biāo),安裝失敗則刪除安裝包和各種緩存文件
- 執(zhí)行 dex2oat 優(yōu)化
「本文源碼基于 Android 28」
1.《【v8ms28l01怎么安裝軟件】談?wù)凙PK安裝過(guò)程?!吩曰ヂ?lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識(shí),僅代表作者本人觀點(diǎn),與本網(wǎng)站無(wú)關(guān),侵刪請(qǐng)聯(lián)系頁(yè)腳下方聯(lián)系方式。
2.《【v8ms28l01怎么安裝軟件】談?wù)凙PK安裝過(guò)程?!穬H供讀者參考,本網(wǎng)站未對(duì)該內(nèi)容進(jìn)行證實(shí),對(duì)其原創(chuàng)性、真實(shí)性、完整性、及時(shí)性不作任何保證。
3.文章轉(zhuǎn)載時(shí)請(qǐng)保留本站內(nèi)容來(lái)源地址,http://f99ss.com/why/3036878.html