apk有哪些安装方式 (安装apk的超级命令)

今天我们一起来看一下,系统是怎么把应用安装到你的手机上的。

入口

当我们点击一个 APK 进行安装时,会弹出以下界面

apk安装包内容介绍,第一步安装apk是什么意思

这是 Android Framework 提供的软件包安装程序,页面为:PackageInstallerActivity

packagecom.android.packageinstaller;

publicclassPackageInstallerActivityextendsActivity{
publicvoidonClick(Viewv){
if(v==mOk){
if(mOk.isEnabled()){
//...省略一些细节
startInstall();//开始安装
}
}elseif(v==mCancel){
//Cancelandfinish
}
}

privatevoidstartInstall(){
//Startsubactivitytoactuallyinstalltheapplication
IntentnewIntent=newIntent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this,InstallInstalling.class);
...//newIntent.putExtra其它参数
startActivity(newIntent);
finish();
}
}

在这个页面点击安装时,会把安装包的信息通过 Intent 传递到 InstallInstalling 这个 Activity. InstallInstalling 的作用主要是向 PMS 发送包信息以及处理回调。

InstallInstalling.onCreate

进来新页面,当然是先从 onCreate 开始了

protectedvoidonCreate(@NullableBundlesavedInstanceState){
ApplicationInfoappInfo=getIntent()
.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI=getIntent().getData();
...
//根据mPackageURI创建一个对应的File
finalFilesourceFile=newFile(mPackageURI.getPath());
//显示应用信息icon,应用名或包名
PackageUtil.initSnippetForNewApp(this,PackageUtil.getAppSnippet(this,appInfo,
sourceFile),R.id.app_snippet);

//创建、组装SessionParams,它用来携带会话的参数
PackageInstaller.SessionParamsparams=newPackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.installFlags=PackageManager.INSTALL_FULL_APP;
...
params.installerPackageName=
getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);

Filefile=newFile(mPackageURI.getPath());
//对APK进行轻量级的解析,并将解析的结果赋值给SessionParams相关字段
PackageParser.PackageLitepkg=PackageParser.parsePackageLite(file,0);
params.setAppPackageName(pkg.packageName);
params.setInstallLocation(pkg.installLocation);
params.setSize(
PackageHelper.calculateInstalledSize(pkg,false,params.abiOverride));
//向InstallEventReceiver注册一个观察者返回一个新的mInstallId
//InstallEventReceiver是一个BroadcastReceiver,可以通过EventResultPersister接收到所有的安装事件
//这里事件会回调给this::launchFinishBasedOnResult
mInstallId=InstallEventReceiver
.addObserver(this,EventResultPersister.GENERATE_NEW_ID,
this::launchFinishBasedOnResult);

try{
//PackageInstaller的createSession
//方法内部会通过IPackageInstaller与PackageInstallerService进行进程间通信,
//最终调用的是PackageInstallerService的createSession方法来创建并返回mSessionId
mSessionId=getPackageManager().getPackageInstaller().createSession(params);
}catch(IOExceptione){
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,null);
}


}

InstallInstalling.onResume

接下来是 onResume, 通过 InstallingAsyncTask 做一些异步工作

protectedvoidonResume(){
super.onResume();

//ThisisthefirstonResumeinasinglelifeoftheactivity
if(mInstallingTask==null){
PackageInstallerinstaller=getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfosessionInfo=installer.getSessionInfo(mSessionId);

if(sessionInfo!=null&&!sessionInfo.isActive()){
mInstallingTask=newInstallingAsyncTask();
mInstallingTask*ex.e**cute();
}else{
//wewillreceiveabroadcastwhentheinstallisfinished
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
}
}
}

InstallingAsyncTask

privatefinalclassInstallingAsyncTaskextendsAsyncTask<Void,Void,
PackageInstaller.Session>{

@Override
protectedPackageInstaller.SessiondoInBackground(Void...params){
PackageInstaller.Sessionsession;
session=getPackageManager().getPackageInstaller().openSession(mSessionId);
session.setStagingProgress(0);

Filefile=newFile(mPackageURI.getPath());
OutputStreamout=session.openWrite("PackageInstaller",0,sizeBytes)
InputStreamin=newFileInputStream(file)
longsizeBytes=file.length();
byte[]buffer=newbyte[1024*1024];

while(true){
intnumRead=in.read(buffer);
if(numRead==-1){
session.fsync(out);
break;
}
//将APK文件通过IO流的形式写入到PackageInstaller.Session中
out.write(buffer,0,numRead);
if(sizeBytes>0){
floatfraction=((float)numRead/(float)sizeBytes);
session.addProgress(fraction);
}
}
returnsession;
}

@Override
protectedvoidonPostExecute(PackageInstaller.Sessionsession){
IntentbroadcastIntent=newIntent(BROADCAST_ACTION);
broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntent.setPackage(
getPackageManager().getPermissionControllerPackageName());
broadcastIntent.putExtra(EventResultPersister.EXTRA_ID,mInstallId);

PendingIntentpendingIntent=PendingIntent.getBroadcast(
InstallInstalling.this,
mInstallId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
//调用PackageInstaller.Session的commit方法,进行安装
session.commit(pendingIntent.getIntentSender());
}
}

来看下 PackageInstaller.Session 里的实现

publicstaticclassSessionimplementsCloseable{
privateIPackageInstallerSessionmSession;
publicvoidcommit(@NonNullIntentSenderstatusReceiver){
try{
mSession.commit(statusReceiver,false);
}catch(RemoteExceptione){
throwe.rethrowFromSystemServer();
}
}
}

mSession 的类型为 IPackageInstallerSession,这说明要通过 IPackageInstallerSession 来进行进程间的通信,最终会调用PackageInstallerSession 的 commit 方法,剧透一下在这个类执行完后,就会进入鼎鼎大名的 PMS 去真正的执行安装了 :

publicclassPackageInstallerSessionextendsIPackageInstallerSession.Stub{
publicvoidcommit(@NonNullIntentSenderstatusReceiver,booleanforTransfer){
//将包的信息封装为PackageInstallObserverAdapter
finalPackageInstallObserverAdapteradapter=newPackageInstallObserverAdapter(
mContext,statusReceiver,sessionId,
isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(),userId);
mRemoteObserver=adapter.getBinder();
//通过Handler处理消息事件
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}

privatefinalHandler.CallbackmHandlerCallback=newHandler.Callback(){
@Override
publicbooleanhandleMessage(Messagemsg){
switch(msg.what){
caseMSG_COMMIT:
commitLocked();
break;
}
}
};

privatefinalPackageManagerServicemPm;
privatevoidcommitLocked()throwsPackageManagerException{
mPm.installStage(mPackageName,stageDir,...);
}

}

mPm 就是系统服务 PackageManagerService。installStage 方法就是正式开始 apk 的安装过程。这个过程包括两大步:拷贝安装包、装载代码

拷贝安装包

继续看 installStage 的代码

//PackageManagerService.java
voidinstallStage(StringpackageName,FilestagedDir,...){
finalMessagemsg=mHandler.obtainMessage(INIT_COPY);
//把之前传入的sessionParams安装信息,及其它信息封装成InstallParams
finalInstallParamsparams=newInstallParams(origin,null,observer,
sessionParams.installFlags,installerPackageName,sessionParams.volumeUuid,
verificationInfo,user,sessionParams.abiOverride,
sessionParams.grantedRuntimePermissions,signingDetails,installReason);
mHandler.sendMessage(msg);
}

发送的消息 INIT_COPY 从名字上就知道是去初始化复制

classPackageHandlerextendsHandler{
voiddoHandleMessage(Messagemsg){
switch(msg.what){
caseINIT_COPY:{
HandlerParamsparams=(HandlerParams)msg.obj;
//调用 connectToService 方法连接安装 apk 的 Service 服务。
if(!connectToService()){
return;
}else{
//Oncewebindtotheservice,thefirst
//pendingrequestwillbeprocessed.
mPendingInstalls.add(idx,params);
}
}
}
}

privatebooleanconnectToService(){
//通过隐式Intent绑定Service,实际绑定的Service是DefaultContainerService
Intentservice=newIntent().setComponent(DEFAULT_CONTAINER_COMPONENT);
if(mContext.bindServiceAsUser(service,mDefContainerConn,
Context.BIND_AUTO_CREATE,UserHandle.SYSTEM)){
mBound=true;
returntrue;
}
returnfalse;
}
}

当绑定 Service 成功之后,会在 mDefContainerConn 的 onServiceConnection 方法中发送一个绑定操作的 Message,如下所示:

classDefaultContainerConnectionimplementsServiceConnection{
publicvoidonServiceConnected(ComponentNamename,IBinderservice){
finalIMediaContainerServiceimcs=IMediaContainerService.Stub
.asInterface(Binder.allowBlocking(service));
mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND,imcs));
}
}

//MCS_BOUND还是在前面的PackageHandler处理,直接截取相关代码
{
HandlerParamsparams=mPendingInstalls.get(0);
if(params.startCopy()){
if(mPendingInstalls.size()>0){
mPendingInstalls.remove(0);
}
}
}

mPendingInstalls 是一个等待队列,里面保存所有需要安装的 apk 解析出来的 HandlerParams 参数(前面在 INIT_COPY 处理时 add),从 mPendingInstalls 中取出第一个需要安装的 HandlerParams 对象,并调用其 startCopy 方法,在 startCopy 方法中会继续调用一个抽象方法 handleStartCopy 处理安装请求。通过之前的分析,我们知道 HandlerParams 实际类型是 InstallParams 类型,因此最终调用的是 InstallParams 的 handlerStartCopy 方法,这是整个安装包拷贝的核心。

classInstallParamsextendsHandlerParams{

publicvoidhandleStartCopy()throwsRemoteException{
if(origin.staged){
//设置安装标志位,决定是安装在手机内部存储空间还是sdcard中
if(origin.file!=null){
installFlags|=PackageManager.INSTALL_INTERNAL;
installFlags&=~PackageManager.INSTALL_EXTERNAL;
}
}

//判断安装位置
finalbooleanonSd=(installFlags&PackageManager.INSTALL_EXTERNAL)!=0;
finalbooleanonInt=(installFlags&PackageManager.INSTALL_INTERNAL)!=0;
finalbooleanephemeral=(installFlags&PackageManager.INSTALL_INSTANT_APP)!=0;

finalInstallArgsargs=createInstallArgs(this);
//...
ret=args.copyApk(mContainerService,true);
}

privateInstallArgscreateInstallArgs(InstallParamsparams){
if(params.move!=null){
returnnewMoveInstallArgs(params);
}else{
returnnewFileInstallArgs(params);
}
}
}

正常的流程下,createInstallArgs 返回的是 FileInstallArgs 对象

FileInstallArgs 的 copyApk 方法

intcopyApk(IMediaContainerServiceimcs,booleantemp)throwsRemoteException{
returndoCopyApk(imcs,temp);
}

privateintdoCopyApk(IMediaContainerServiceimcs,booleantemp)throwsRemoteException{
//创建存储安装包的目标路径,实际上是/data/app/应用包名目录
finalFiletempDir=mInstallerService.allocateStageDirLegacy(volumeUuid,isEphemeral);

finalIParcelFileDescriptorFactorytarget=newIParcelFileDescriptorFactory.Stub(){
@Override
publicParcelFileDescriptoropen(Stringname,intmode)throwsRemoteException{
finalFilefile=newFile(codeFile,name);
finalFileDescriptorfd=Os.open(file.getAbsolutePath(),
O_RDWR|O_CREAT,0644);
Os.chmod(file.getAbsolutePath(),0644);
returnnewParcelFileDescriptor(fd);
}
};
//调用服务的 copyPackage 方法将安装包 apk 拷贝到目标路径中;
ret=imcs.copyPackage(origin.file.getAbsolutePath(),target);
//将 apk 中的动态库 .so 文件也拷贝到目标路径中。
ret=NativeLibraryHelper.copyNativeBinariesWithOverride(handle,libraryRoot,
abiOverride);
}

这里的 IMediaContainerService imcs 就是之前连接上的 DefaultContainerService

DefaultContainerService

copyPackage 方法本质上就是执行 IO 流操作,具体如下:

//newIMediaContainerService.Stub()
publicintcopyPackage(StringpackagePath,IParcelFileDescriptorFactorytarget){
PackageLitepkg=null;
finalFilepackageFile=newFile(packagePath);
pkg=PackageParser.parsePackageLite(packageFile,0);
returncopyPackageInner(pkg,target);
}

//DefaultContainerService
privateintcopyPackageInner(PackageLitepkg,IParcelFileDescriptorFactorytarget){
copyFile(pkg.baseCodePath,target,"base.apk");
if(!ArrayUtils.isEmpty(pkg.splitNames)){
for(inti=0;i<pkg.splitNames.length;i++){
copyFile(pkg.splitCodePaths[i],target,"split_"+pkg.splitNames[i]+".apk");
}
}

returnPackageManager.INSTALL_SUCCEEDED;
}

privatevoidcopyFile(StringsourcePath,IParcelFileDescriptorFactorytarget,StringtargetName){
InputStreamin=null;
OutputStreamout=null;
try{
in=newFileInputStream(sourcePath);
out=newParcelFileDescriptor.AutoCloseOutputStream(
target.open(targetName,ParcelFileDescriptor.MODE_READ_WRITE));
FileUtils.copy(in,out);
}finally{
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(in);
}
}

最终安装包在 data/app 目录下以 base.apk 的方式保存,至此安装包拷贝工作就已经完成。

装载代码

安装包拷贝完成,就要开始真正安装了。代码回到上述的 HandlerParams 中的 startCopy 方法:

privateabstractclassHandlerParams{
finalbooleanstartCopy(){
...
handleStartCopy();
handleReturnCode();
}
}

classInstallParamsextendsHandlerParams{
@Override
voidhandleReturnCode(){
//IfmArgsisnull,thenMCScouldn'tbereached.Whenit
//reconnects,itwilltryagaintoinstall.Atthatpoint,this
//willsucceed.
if(mArgs!=null){
processPendingInstall(mArgs,mRet);
}
}

privatevoidprocessPendingInstall(finalInstallArgsargs,finalintcurrentStatus){
mHandler.post(newRunnable(){
publicvoidrun(){
PackageInstalledInfores=newPackageInstalledInfo();
if(res.returnCode==PackageManager.INSTALL_SUCCEEDED){
//预安装操作,主要是检查安装包的状态,确保安装环境正常,如果安装环境有问题会清理拷贝文件
args.doPreInstall(res.returnCode);
synchronized(mInstallLock){
//安装阶段
installPackageTracedLI(args,res);
}
args.doPostInstall(res.returnCode,res.uid);
}
...
}
}
}
}


installPackageLI

installPackageTracedLI 方法中添加跟踪 Trace,然后调用 installPackageLI 方法进行安装。这个方法有 600 行,取部分关键代码:

privatevoidinstallPackageLI(InstallArgsargs,PackageInstalledInfores){
...
PackageParserpp=newPackageParser();
finalPackageParser.Packagepkg;
//1.parsePackage
pkg=pp.parsePackage(tmpPackageFile,parseFlags);

//2.校验安装包签名
finalKeySetManagerServiceksms=mSettings.mKeySetManagerService;
if(ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs,scanFlags)){
if(!ksms.checkUpgradeKeySetLocked(signatureCheckPs,pkg)){
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,"Package"
+pkg.packageName+"upgradekeysdonotmatchthe"
+"previouslyinstalledversion");
return;
}
}

//3.设置相关权限,生成、移植权限
intN=pkg.permissions.size();
for(inti=N-1;i>=0;i--){
finalPackageParser.Permissionperm=pkg.permissions.get(i);
...
}

//4.生成安装包Abi(Applicationbinaryinterface,应用二进制接口)
try{
StringabiOverride=(TextUtils.isEmpty(pkg.cpuAbiOverride)?
args.abiOverride:pkg.cpuAbiOverride);
finalbooleanextractNativeLibs=!pkg.isLibrary();
derivePackageAbi(pkg,abiOverride,extractNativeLibs);
}catch(PackageManagerExceptionpme){
res.setError(INSTALL_FAILED_INTERNAL_ERROR,"ErrorderivingapplicationABI");
return;
}

//5.冻结APK,执行替换安装或新安装,
try(PackageFreezerfreezer=freezePackageForInstall(pkgName,installFlags,
"installPackageLI")){
if(replace){
replacePackageLIF(pkg,parseFlags,scanFlags,args.user,
installerPackageName,res,args.installReason);
}else{
privatevoidinstallNewPackageLIF((pkg,parseFlags,scanFlags|SCAN_DELETE_DATA_ON_FAILURES,
args.user,installerPackageName,volumeUuid,res,args.installReason);
}
}

//5.优化dex文件(实际为dex2oat操作,用来将apk中的dex文件转换为oat文件)
if(performDexopt){
mPackageDexOptimizer.performDexOpt(pkg,pkg.usesLibraryFiles,
null/*instructionSets*/,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
dexoptOptions);
}
...
}

最后我们来看一下 installNewPackageLIF

privatevoidinstallNewPackageLIF(PackageParser.Packagepkg,final@ParseFlagsintparseFlags,
final@ScanFlagsintscanFlags,...){
//继续扫描解析apk安装包文件,保存apk相关信息到PMS中,并创建apk的data目录,具体路径为/data/data/应用包名
PackageParser.PackagenewPackage=scanPackageTracedLI(pkg,parseFlags,scanFlags,
System.currentTimeMillis(),user);
//更新系统设置中的应用信息,比如应用的权限信息
updateSettingsLI(newPackage,installerPackageName,null,res,user,installReason);
if(res.returnCode==PackageManager.INSTALL_SUCCEEDED){
//安装然后准备APP数据
prepareAppDataAfterInstallLIF(newPackage);
}else{
//如果安装失败,则将安装包以及各种缓存文件删除
deletePackageLIF(pkgName,UserHandle.ALL,false,null,
PackageManager.DELETE_KEEP_DATA,res.removedInfo,true,null);
}
}

prepareAppDataAfterInstallLIF 还会有一系列的调用

prepareAppDataAfterInstallLIF()
->prepareAppDataLIF()
->prepareAppDataLeafLIF()
->mInstaller.createAppData(...)

finalInstallermInstaller;
privatevoidprepareAppDataLeafLIF(...){
//最终调用系统服务Installer安装
ceDataInode=mInstaller.createAppData(volumeUuid,packageName,userId,flags,
appId,seInfo,app.targetSdkVersion);
}

publicclassInstallerextendsSystemService{
...
}


至此整个 apk 的安装过程结束,实际上安装成功之后,还会发送一个 App 安装成功的广播 ACTION_PACKAGE_ADDED。手机桌面应用注册了这个广播,当接收到应用安装成功之后,就将 apk 的启动 icon 显示在桌面上。

总结

在手机上仅仅是点一下安装按钮而已,背后却有着这么繁琐的流程,相信通过今天的学习大家应该能对系统的应用安装流程有一个完整的认知。回顾一下安装的流程如下:

  • 点击 APK 安装,会启动 PackageInstallerActivity,再进入 InstallInstalling 这两个 Activity 显示应用信息
  • 点击页面上的安装,将 APK 信息存入 PackageInstaller.Session 传到 PMS
  • PMS会做两件事,拷贝安装包和装载代码
  • 在拷贝安装*过包**程中会开启 Service 来 copyAPK 、检查apk安装路径,包的状态
  • 拷贝完成以 base.apk 形式存在/data/app包名下
  • 装载代码过程中,会继续解析 APK,把清单文件内容存放于 PMS
  • 对 apk 进行签名校验
  • 安装成功后,更新应用设置权限,发送广播通知桌面显示APP图标,安装失败则删除安装包和各种缓存文件
  • 执行 dex2oat 优化

「本文源码基于 Android 28」