apk文件苹果怎么打开安装(ios安装apk软件步骤)

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

入口

apk文件苹果怎么打开安装(ios安装apk软件步骤)

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

packagecom.android.packageinstaller;publicclassPackageInstallerActivityextendsActivity{publicvoidonClick(Viewv){if(v==mOk){if(mOk.isEnabled()){//…省略一些细节startInstall();//开始安装}}elseif(v==mCancel){//Cancelandfinish}}privatevoidstartInstall(){//StartsubactivitytoactuallyinstalltheapplicationIntentnewIntent=newIntent();newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,mPkgInfo.applicationInfo);newIntent.setData(mPackageURI);newIntent.setClass(this,InstallInstalling.class);…//newIntent.putExtra其它参数startActivity(newIntent);finish();}}

InstallInstalling.onCreate

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

protectedvoidonCreate(@NullableBundlesavedInstanceState){ApplicationInfoappInfo=getIntent().getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);mPackageURI=getIntent().getData();…//根据mPackageURI创建一个对应的FilefinalFilesourceFile=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::launchFinishBasedOnResultmInstallId=InstallEventReceiver.addObserver(this,EventResultPersister.GENERATE_NEW_ID,this::launchFinishBasedOnResult);try{//PackageInstaller的createSession//方法内部会通过IPackageInstaller与PackageInstallerService进行进程间通信,//最终调用的是PackageInstallerService的createSession方法来创建并返回mSessionIdmSessionId=getPackageManager().getPackageInstaller().createSession(params);}catch(IOExceptione){launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,null);}}InstallInstalling.onResume

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

protectedvoidonResume(){super.onResume();//ThisisthefirstonResumeinasinglelifeoftheactivityif(mInstallingTask==null){PackageInstallerinstaller=getPackageManager().getPackageInstaller();PackageInstaller.SessionInfosessionInfo=installer.getSessionInfo(mSessionId);if(sessionInfo!=null&&!sessionInfo.isActive()){mInstallingTask=newInstallingAsyncTask();mInstallingTask.execute();}else{//wewillreceiveabroadcastwhentheinstallisfinishedmCancelButton.setEnabled(false);setFinishOnTouchOutside(false);}}}InstallingAsyncTaskprivatefinalclassInstallingAsyncTaskextendsAsyncTask<Void,Void,PackageInstaller.Session>{@OverrideprotectedPackageInstaller.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;}@OverrideprotectedvoidonPostExecute(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){//将包的信息封装为PackageInstallObserverAdapterfinalPackageInstallObserverAdapteradapter=newPackageInstallObserverAdapter(mContext,statusReceiver,sessionId,isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(),userId);mRemoteObserver=adapter.getBinder();//通过Handler处理消息事件mHandler.obtainMessage(MSG_COMMIT).sendToTarget();}privatefinalHandler.CallbackmHandlerCallback=newHandler.Callback(){@OverridepublicbooleanhandleMessage(Messagemsg){switch(msg.what){caseMSG_COMMIT:commitLocked();break;}}};privatefinalPackageManagerServicemPm;privatevoidcommitLocked()throwsPackageManagerException{mPm.installStage(mPackageName,stageDir,…);}}

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

拷贝安装包

继续看 installStage 的代码

//PackageManagerService.javavoidinstallStage(StringpackageName,FilestagedDir,…){finalMessagemsg=mHandler.obtainMessage(INIT_COPY);//把之前传入的sessionParams安装信息,及其它信息封装成InstallParamsfinalInstallParamsparams=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是DefaultContainerServiceIntentservice=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(){@OverridepublicParcelFileDescriptoropen(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);}//DefaultContainerServiceprivateintcopyPackageInner(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{@OverridevoidhandleReturnCode(){//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.parsePackagepkg=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 显示在桌面上。

总结

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

「本文源码基于 Android 28」

推荐阅读最近聊了一些高P,我慌了十年老码农,现场教你写简历2020总结,2021展望

发表评论

登录后才能评论