剪切板在哪里-windows8官方下载

packageinstaller
2023年4月3日发(作者:pdx16)

Androidapk安装过程分析

⼀、何谓apk成功安装到系统

1.1、⼀个apk怎样才可以称作成功安装到了Android系统?

可以类⽐⼀下新⽣⼉。⼀个刚出⽣的孩⼦怎么样才能算是⼀个完整的社会⼈呢?

婴⼉刚从母亲体内分娩出来,他实际还不能称为⼀个"社会⼈",他需要向户籍管理单位进⾏注册,添加户⼝页,分配社保ID,

完成⼀些列注册⼿续之后,才能称为⼀个完全意义上的“社会⼈”,并且可以享受国家社会的相关福利。

apk的安装也是类似的,不仅仅需要将apk的实体放到系统的特定⽬录(/data/app/),⽽且需要向PackageManagerService注册包名、以及apk声

明的四⼤组件(Activity、Service、ContentProvider、BroadcastReceiver),该apk才能算是成功安装到了Android系统。

⼤概可分为两个⽅⾯:

1、安装apk到特定的⽬录

2、注册包名、四⼤组件到PackageManagerService

只有完成了第2步(向系统注册),Android系统才知道有这么⼀个apk存在,才可以管理(或者说启动)该apk

1.2、apk安装相关的⽬录

apk安装⽬录:

1、/system/app:系统⾃带的应⽤程序,获得adbroot权限才能删除

2、/data/app:⽤户程序安装的⽬录。安装时把apk⽂件复制到此⽬录

dex、odex保存⽬录:

3、/data/dalvik-cache:将apk中的dex⽂件安装到dalvik-cache⽬录下(dex⽂件是dalvik虚拟机的可执⾏⽂件,当

然,ART–AndroidRuntime的可执⾏⽂件格式为oat,启⽤ART时,系统会执⾏dex⽂件转换⾄oat⽂件)

⽤户数据⽬录:

4、/data/data:存放应⽤程序的数据,⽆论是系统app还是普通app,app产⽣的⽤户数据都存放在/data/data/包名/⽬

录下。

注册表⽬录

5、/data/system:该⽬录下的⽂件,类似于Windows的注册表。这个⽂件是在解析apk时由

writeLP()创建的,⾥⾯记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信

息,这些信息主要通apk的解析获取,解析完apk后将更新信息写⼊这个⽂件并保存到flash,

下次开机直接从⾥⾯读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个⽂件。

⼆、PackageManagerService概述

2.1、PackageManagerService有三⼤职责

PackageManagerService是Android系统中所有包的⼤管家,其最简化的类结构如下:

implementsPackageSender{

//保存所有已安装的apckage信息

finalSettingsmSettings;

//保存包名-Package的键值对

finalArrayMapmPackages=

newArrayMap();

//保存所有已安装包中注册的Activity信息

//Allavailableactivities,foryourresolvingpleasure.

finalActivityIntentResolvermActivities=

newActivityIntentResolver();

//保存所有已安装apk中注册的Receiver信息

//Allavailablereceivers,foryourresolvingpleasure.

finalActivityIntentResolvermReceivers=

newActivityIntentResolver();

//保存所有已安装apk中注册的Service信息

//Allavailableservices,foryourresolvingpleasure.

finalServiceIntentResolvermServices=newServiceIntentResolver();

//保存所有已安装apk中注册ContentProvider信息

//Allavailableproviders,foryourresolvingpleasure.

finalProviderIntentResolvermProviders=newProviderIntentResolver();

//安装⼀个apk

privatevoidinstallPackageLI(InstallArgsargs,PackageInstalledInfores){

}

}

PackageManagerService有三⼤职责:

(1)开机扫描过程

开机后,加载/data/system/⽂件,然后扫描特定安装⽬录:/system/app、/system/priv-app、/system/vendor/app、

/data/app

解析⾥⾯的apk⽂件,将静态信息提取到PackageManagerService中的主要数据结构中。

(2)安装apk

将⼀个新的apk安装到Android系统当中

(3)解析Intent

解析Intent意图,通过Intent获取到⽬的Activity、Provider、BroadCastReceiver或Service。

2.2、Settings

上⽂提到/data/system/记录所有已安装的包信息,的内容如下:

<?xmlversion='1.0'encoding='utf-8'standalone='yes'?>

....

省略若⼲个package声明

(1)记录了⼀个应⽤的基本信息,签名和声明的权限。

-name表⽰应⽤的包名

-codePath表⽰的是apk⽂件的路径

-nativeLibraryPath表⽰应⽤的native库的存储路径

-flags是指应⽤的属性,如FLAG_SYSTEM、FLAG_PERSISTENT等

-it表⽰应⽤安装的时间

-ut表⽰应⽤最后⼀次修改的时间

-version表⽰应⽤的版本号

-userId表⽰所属于的id

(2)表⽰应⽤的签名

-count表⽰标签中包含有多少个证书

-cert表⽰具体的证书的值

(3)表⽰应⽤声明使⽤的权限,每⼀个⼦标签代表⼀项权限

/data/system/,被PackageManagerService解析后会存储到mSettings属性中。

publicfinalclassSettings{

/**Mapfrompackagenametosettings*/

finalArrayMapmPackages=newArrayMap<>();

}

Settings中持有⼀个以package为键,以PackageSetting为值的ArrayMap,⼀个PackageSetting就对应中的⼀个package。

publicfinalclassPackageSettingextendsPackageSettingBase{

epkg;

SharedUserSettingsharedUser;

privateintsharedUserId;

}

PackageSetting继承⾃PackageSettingBase。

publicfinalclassPackageSettingextendsPackageSettingBase{

epkg;

SharedUserSettingsharedUser;

privateintsharedUserId;

}

2.3、mPackages

mPackages维护了所有已安装apk的详细解析信息,包名为key,e为value

finalArrayMapmPackages=

newArrayMap();

2.4、四⼤组件解析器

ActivityIntentResolvermActivities持有所有注册的activity信息,⽤于通过intent解析成合理的Activity

finalclassActivityIntentResolverextendsIntentResolver{

//KeysareString(activityclassname),valuesareActivity.

privatefinalArrayMapmActivities

=newArrayMap();

publicListqueryIntent(Intentintent,StringresolvedType,intflags,

intuserId){}

}

ActivityIntentResolvermReceivers⽤于解析BroadCastReceiver

ServiceIntentResolvermServices维护所有注册的Service,⽤于通过Intent解成⽬标Service

ProviderIntentResolvermProviders维护所有注册的ContentPrivider⽤于将Intent解析成⽬标ContentProvider

三、apk安装具体安装过程:

3.1、apk安装的主要流程描述

本⽂主要阐述普通apk的安装流程,⼤概分为以下⼏个步骤:

image

(1)拷贝apk⽂件到指定⽬录

在Android系统中,apk安装有固定的⽬录,默认情况下,⽤户安装的apk⾸先会被拷贝到/data/app⽬录下,同时会创

建/data/app/pkg/lib⽬录,将apk中的so⽂件解压到此⽬录

/data/app⽬录是⽤户有权限访问的⽬录,在安装apk的时候会⾃动选择该⽬录存放⽤户安装的⽂件。⽽系统出⼚的apk

⽂件则被放到了/system分区下,包括:/system/app,/system/vendor/app,以及/system/priv-app等等,该分区

只有Root权限的⽤户才能访问。这也就是为什么在没有Root⼿机之前,我们⽆法删除系统出⼚的app的原因了。

(2)扫描apk,解析⽂件,向PackagManagerService中注册该package、以及apk声明的四⼤组件。

(3)创建apk的⽤户数据⽬录,即/data/data/pkg/⽬录

/data/data/pkg为应⽤程序的数据⽬录(以应⽤的包名命名),存放应⽤的相关数据,如数据库、xml⽂件、cache

(4)为apk执⾏dexopt优化。

对于普通apk,dexopt优化后的⽂件保存在/data/app/oat⽬录

(5)安装完成发送ACTION_PACKAGE_ADDED⼴播。

3.2、apk安装代码分析

⽹络上有很多apk安装流程分析,但是版本都⽐较⽼了(Android6.0左右),和最新的代码有些地⽅对不上,本⽂以Android9.0代码为基准,分析⼀

下apk的安装流程:

PagkageManagerService的安装apk的⼊⼝是installStage

voidinstallStage(StringpackageName,FilestagedDir,

IPackageInstallObserver2observer,nParamssessionParams,

StringinstallerPackageName,intinstallerUid,UserHandleuser,

gDetailssigningDetails){

finalVerificationInfoverificationInfo=newVerificationInfo(

atingUri,erUri,

atingUid,installerUid);

finalOriginInfoorigin=agedFile(stagedDir);

finalMessagemsg=Message(INIT_COPY);

finalintinstallReason=fixUpInstallReason(installerPackageName,installerUid,

lReason);

//(1)创建⼀个InstallParams对象,封装到INIT_COPY消息中

finalInstallParamsparams=newInstallParams(origin,null,observer,

lFlags,installerPackageName,Uuid,

verificationInfo,user,rride,

dRuntimePermissions,signingDetails,installReason);

ceMethod("installStage").setTraceCookie(tyHashCode(params));

=params;

//(2)发送INIT_COPY消息

ssage(msg);

}

installStage()⽅法主要⽬的是发送⼀个INIT_COPYHandler消息。

我们看下Handler的处理函数,⽐较重要的是INIT_COPY和MCS_BOUND两个消息。

voiddoHandleMessage(Messagemsg){

switch(){

caseINIT_COPY:{

HandlerParamsparams=(HandlerParams);

intidx=();

//Ifabindwasalreadyinitiatedwedontreally

//dinginstall

//willbeprocessedlateron.

if(!mBound){

//连接DefaultContainerService,它负责具体的copy操作

if(!connectToService()){

Slog.e(TAG,"Failedtobindtomediacontainerservice");

eError();

return;

}else{

//Oncewebindtotheservice,thefirst

//pendingrequestwillbeprocessed.

(idx,params);

}

}else{

(idx,params);

//ke

//surewetriggeroffprocessingthefirstrequest.

if(idx==0){

ptyMessage(MCS_BOUND);

}

}

break;

}

caseMCS_BOUND:{

if(!=null){

mContainerService=(IMediaContainerService);

}

if(mContainerService==null){

//...省略不重要的代码

}elseif(()>0){

HandlerParamsparams=(0);

if(params!=null){

//(2)执⾏copy操作

if(opy()){

if(()>0){

(0);

}

if(()==0){//空闲时,解绑mContainerService

if(mBound){

removeMessages(MCS_UNBIND);

Messageubmsg=obtainMessage(MCS_UNBIND);

sendMessageDelayed(ubmsg,10000);

}

}else{

ptyMessage(MCS_BOUND);

}

}

}

}

break;

}

INIT_COPY的主要作⽤是connectToService()连接DefaultContainerService,copyapk的操作是借助DefaultContainerService来完成

的。connectToService成功之后,会发送MCS_BOUND消息

MCS_BOUND消息主要负责完成apk的拷贝以及apk中so⽂件的提取

privateabstractclassHandlerParams{

finalbooleanstartCopy(){

booleanres;

try{

//...省略不重要的信息

//(1)开始copy

handleStartCopy();

res=true;

}catch(RemoteExceptione){

if(DEBUG_INSTALL)Slog.i(TAG,"PostinginstallMCS_RECONNECT");

ptyMessage(MCS_RECONNECT);

res=false;

}

//(2)copy完成后的操作

handleReturnCode();

returnres;

}

}

startCopy主要做了两件事情:

handleStartCopy()完成拷贝apk的过程

handleReturnCode()拷贝之后的后续操作

handleStartCopy主要⽣成了⼀个InstallArgs对象,然后调⽤copyApk⽅法

publicvoidhandleStartCopy(){

finalInstallArgsargs=createInstallArgs(this);

ret=k(mContainerService,false);

}

copyApk->doCopyApk

privateintdoCopyApk(IMediaContainerServiceimcs,booleantemp)throwsRemoteException{

//(1)copy⽂件到安装⽬录:系统app安装到/system/app/普通app安装到/data/app

intret=L_SUCCEEDED;

ret=ckage(olutePath(),target);

if(ret!=L_SUCCEEDED){

Slog.e(TAG,"Failedtocopypackage");

returnret;

}

//(2)将apk中的so⽂件复制出来,保存到安装⽬录。如:/datap/app/lib/

finalFilelibraryRoot=newFile(codeFile,LIB_DIR_NAME);

handle=null;

try{

handle=(codeFile);

ret=tiveBinariesWithOverride(handle,libraryRoot,

abiOverride);

}catch(IOExceptione){

Slog.e(TAG,"Copyingnativelibrariesfailed",e);

ret=L_FAILED_INTERNAL_ERROR;

}finally{

uietly(handle);

}

}

我们再看看拷贝完apk之后调⽤的handleReturnCode()

voidhandleReturnCode(){

//IfmArgsisnull,thenMCScouldn'

//reconnects,point,this

//willsucceed.

if(mArgs!=null){

processPendingInstall(mArgs,mRet);

}

}

processPendingInstall完成后续的安装任务

privatevoidprocessPendingInstall(finalInstallArgsargs,finalintcurrentStatus){

//Queueupanasyncoperationsincethepackageinstallationmaytakealittlewhile.

(newRunnable(){

publicvoidrun(){

PackageInstalledInfores=newPackageInstalledInfo();

urnCode(currentStatus);

if(Code==L_SUCCEEDED){

nstall(Code);

synchronized(mInstallLock){

installPackageTracedLI(args,res);

}

Install(Code,);

}

//...省略不重要的代码

}

}

processPendingInstall->installPackageTracedLI->installPackageLI

installPackageLI是安装的核⼼操作

privatevoidinstallPackageLI(InstallArgsargs,PackageInstalledInfores){

//(1)利⽤PackageParser解析apk

epkg;

try{

pkg=ackage(tmpPackageFile,parseFlags);

tePackageDexMetadata(pkg);

}catch(PackageParserExceptione){

or("FailedparseduringinstallPackageLI",e);

return;

}finally{

nd(TRACE_TAG_PACKAGE_MANAGER);

}

//(2)执⾏installNewPackageLIF或者replacePackageLIF()

try(PackageFreezerfreezer=freezePackageForInstall(pkgName,installFlags,

"installPackageLI")){

if(replace){

if(icSharedLibrary()){

//Staticlibshaveasyntheticpackagenamecontainingtheversion

//andcannotbeupdatedasanupdatewouldgetanewpackagename,

//unlessthisistheexactsameversioncodewhichisusefulfor

//development.

eexistingPkg=(eName);

if(existingPkg!=null&&

gVersionCode()!=gVersionCode()){

or(INSTALL_FAILED_DUPLICATE_PACKAGE,"Packagesdeclaring"

+"static-sharedlibscannotbeupdated");

return;

}

}

replacePackageLIF(pkg,parseFlags,scanFlags,,

installerPackageName,res,lReason);

}else{

installNewPackageLIF(pkg,parseFlags,scanFlags|SCAN_DELETE_DATA_ON_FAILURES,

,installerPackageName,volumeUuid,res,lReason);

}

}

//(3)对apk就⾏dexopt优化

mDexOpt(pkg,braryFiles,null/*instructionSets*/,getOrCreateCompilerPackageStats(pkg),

}

(1)利⽤PackageParser解析该apk

(2)如果apk第⼀安装,则执⾏installNewPackageLIF否则执⾏替换操作replacePackageLIF(),我们主要分析⾸次安装的操作。

(3)对apk就⾏dexopt优化

我们重点看下installNewPackageLIF做了哪些事情:

privatevoidinstallNewPackageLIF(epkg,final@ParseFlagsintparseFlags,

final@ScanFlagsintscanFlags,UserHandleuser,StringinstallerPackageName,

StringvolumeUuid,PackageInstalledInfores,intinstallReason){

try{

//此处仅保留了核⼼的代码,省略了不重要的代码

//(1)扫描package,向PackageManagerService中注册该package

enewPackage=scanPackageTracedLI(pkg,parseFlags,scanFlags,

tTimeMillis(),user);

updateSettingsLI(newPackage,installerPackageName,null,res,user,installReason);

if(Code==L_SUCCEEDED){

//(2)创建/data/data/包名app数据⽬录

prepareAppDataAfterInstallLIF(newPackage);

}else{

//Removepackagefrominternalstructures,butkeeparoundany

//datathatmighthavealreadyexisted

deletePackageLIF(pkgName,,false,null,

_KEEP_DATA,dInfo,true,null);

}

}catch(PackageManagerExceptione){

or("Packagecouldn'tbeinstalledin"+th,e);

}

}

重要的操作由两个:scanPackageTracedLI和prepareAppDataAfterInstallLIF()

scanPackageTracedLI

scanPackageTracedLI()最终会调⽤commitPackageSettings()

scanPackageTracedLI->scanPackageNewLI->commitScanResultsLocked->commitPackageSettings

commitPackageSettings是真正完成向PackageManagerService注册pkg和四⼤组件的⽅法,调⽤此⽅法之后,Android系统就可以查询该apk

的信息了。

/**

*该⽅法是将pkg和四⼤组件注册到PackageManagerService的地⽅

*ismethodisfinished,thepackagewill

*beavailableforquery,resolution,etc...

*/

privatevoidcommitPackageSettings(epkg,

@eoldPkg,PackageSettingpkgSetting,UserHandleuser,

final@ScanFlagsintscanFlags,booleanchatty){

synchronized(mPackages){

//AddthenewsettingtomSettings

//将pkg插⼊到mSettings

PackageSettingLPw(pkgSetting,pkg);

//AddthenewsettingtomPackages

//将当前包pkg插⼊到mPackages

(eName,pkg);

//Makesurewedon'taccidentallydeleteitsdata.

finalIteratoriter=or();

while(t()){

PackageCleanItemitem=();

if((eName)){

();

}

}

intN=();

StringBuilderr=null;

inti;

for(i=0;i

erp=(i);

sName=fixProcessName(sName,

sName);

vider(p);

//...省略不重要的代码

}

if(r!=null){

if(DEBUG_PACKAGE_SCANNING)Log.d(TAG,"Providers:"+r);

}

//注册pkg中的service到mServices

N=();

r=null;

for(i=0;i

es=(i);

sName=fixProcessName(sName,

sName);

vice(s);

//...省略不重要的代码

}

//注册ers到mReceivers

N=();

r=null;

for(i=0;i

tya=(i);

sName=fixProcessName(sName,

sName);

ivity(a,"receiver");

//...省略不重要的代码

}

//注册ties到mActivities

N=();

r=null;

for(i=0;i

tya=(i);

sName=fixProcessName(sName,

sName);

ivity(a,"activity");

//...省略不重要的代码

}

//...省略不重要的代码

}

}

prepareAppDataAfterInstallLIF

我们再看prepareAppDataAfterInstallLIF,经过多次调⽤,最终进⼊到prepareAppDataLeafLIF

prepareAppDataAfterInstallLIF->prepareAppDataLIF->prepareAppDataLeafLIF

prepareAppDataLeafLIF⽅法内,利⽤mInstaller完成了app⽤户数据⽬录的创建.

privatevoidprepareAppDataLeafLIF(epkg,intuserId,intflags){

//...省略不重要的代码

try{

ceDataInode=AppData(volumeUuid,packageName,userId,flags,

appId,seInfo,SdkVersion);

}catch(InstallerExceptione){

}

}

handlePackagePostInstall

执⾏完上述安装操作之后,会发送POST_INSTALL消息,进⼊到handlePackagePostInstall⽅法

handlePackagePostInstall会发送ACTION_PACKAGE_ADDED⼴播给监听者。

privatevoidhandlePackagePostInstall(PackageInstalledInfores,booleangrantPermissions,

booleankillApp,booleanvirtualPreload,String[]grantedPermissions,

booleanlaunchedForRestore,StringinstallerPackage,

IPackageInstallObserver2installObserver){

sendPackageBroadcast(_PACKAGE_ADDED,packageName,

extras,0/*flags*/,

null/*targetPackage*/,null/*finishedReceiver*/,

updateUserIds,instantUserIds);

}

⾄此⼀个新apk的安装完成。

3.3、Android6.0下的完整调⽤流程

下⾯Android6.0源码apk安装的完成调⽤过程,虽然最新的androidsdk⼀些⽅法已经发⽣了变化,但是多少也可以做⼀些参考。

├──lPackage()

└──lPackageAsUser()

|传递InstallParams参数

leMessage().INIT_COPY

|

leMessage().MCS_BOUND

├──opy()

│├──StartCopy()

││└──k()

│└──ReturnCode()

│└──sPendingInstall()

│├──nstall()

│├──lPackageLI()

││├──ackage()

││├──tCertificates()

││├──tManifestDigest()

││├──mDexOpt()

││├──me()

│││└──tCodePath()

││├──replacePackageLI()

│││├──shouldCheckUpgradeKeySetLP()

│││├──compareSignatures()

│││├──replaceSystemPackageLI()

││││├──killApplication()

││││├──removePackageLI()

││││├──eSystemPackageLPw()

││││├──createInstallArgsForExisting()

││││├──deleteCodeCacheDirsLI()

││││├──scanPackageLI()

││││└──updateSettingsLI()

│││└──replaceNonSystemPackageLI()

│││├──deletePackageLI()

│││├──deleteCodeCacheDirsLI()

│││├──scanPackageLI()

│││└──updateSettingsLI()

││└──installNewPackageLI()

││├──scanPackageLI()

││└──updateSettingsLI()

│├──Install()

│├──eAtInstall()

│└──sendMessage(POST_INSTALL)

│|

│leMessage().POST_INSTALL

│├──grantRequestedRuntimePermissions()

│├──sendPackageBroadcast()

│└──ageInstalled()

└──leMessage().MCS_UNBIND

└──nectService()![image](/upload_images/)

四、参考⽂章

更多推荐

packageinstaller