剪切板在哪里-windows8官方下载
![packageinstaller](/uploads/image/0333.jpg)
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的键值对
finalArrayMap
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*/
finalArrayMap
}
Settings中持有⼀个以package为键,以PackageSetting为值的ArrayMap,⼀个PackageSetting就对应中的⼀个package。
publicfinalclassPackageSettingextendsPackageSettingBase{
epkg;
SharedUserSettingsharedUser;
privateintsharedUserId;
}
PackageSetting继承⾃PackageSettingBase。
publicfinalclassPackageSettingextendsPackageSettingBase{
epkg;
SharedUserSettingsharedUser;
privateintsharedUserId;
}
2.3、mPackages
mPackages维护了所有已安装apk的详细解析信息,包名为key,e为value
finalArrayMap
newArrayMap
2.4、四⼤组件解析器
ActivityIntentResolvermActivities持有所有注册的activity信息,⽤于通过intent解析成合理的Activity
finalclassActivityIntentResolverextendsIntentResolver
//KeysareString(activityclassname),valuesareActivity.
privatefinalArrayMap
=newArrayMap
publicList
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.
finalIterator
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
发布评论