Android-Apk的安装流程分析(一)

接着上节的内容来说,之前说到了PackageInstallerSession中调用PackageManaPgerService(简称PMS)的installStage这个方法来完成后续的安装流程

下面的流程基本的都是在PMS中进行的,我们来看下流程

1、PackageManaPgerService#installStage

void installStage(String packageName, File stagedDir, String stagedCid,IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,String installerPackageName, int installerUid, UserHandle user,Certificate[][] certificates) {if (DEBUG_EPHEMERAL) {if ((sessionParams.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0) {Slog.d(TAG, "Ephemeral install of " + packageName);}}final VerificationInfo verificationInfo = new VerificationInfo(sessionParams.originatingUri, sessionParams.referrerUri,sessionParams.originatingUid, installerUid);final OriginInfo origin;if (stagedDir != null) {origin = OriginInfo.fromStagedFile(stagedDir);} else {origin = OriginInfo.fromStagedContainer(stagedCid);}final Message msg = mHandler.obtainMessage(INIT_COPY);//实例化一个安装参数,里面有传进来的安装信息final InstallParams params = new InstallParams(origin, null, observer,sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,verificationInfo, user, sessionParams.abiOverride,sessionParams.grantedRuntimePermissions, certificates);params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));msg.obj = params;Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",System.identityHashCode(msg.obj));Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",System.identityHashCode(msg.obj));//发送一个INIT_COPY 的messagemHandler.sendMessage(msg);}

这个方法就干了一个事情,发送了一个首次copy的消息,然后处理,看看这个handler怎么处理的

2、PackageManaPgerService#doHandleMessage

 void doHandleMessage(Message msg) {switch (msg.what) {//这个就是发来的消息case INIT_COPY: {HandlerParams params = (HandlerParams) msg.obj;int idx = mPendingInstalls.size();if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);// If a bind was already initiated we dont really// need to do anything. The pending install// will be processed later on.//启动pms的时候 mContainerService 服务已经被绑定了if (!mBound) {Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",System.identityHashCode(mHandler));// If this is the only one pending we might// have to bind to the service again.// 尝试绑定服务,这里就是bindServiceif (!connectToService()) {Slog.e(TAG, "Failed to bind to media container service");params.serviceError();Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",System.identityHashCode(mHandler));if (params.traceMethod != null) {Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,params.traceCookie);}return;} else {// Once we bind to the service, the first// pending request will be processed.//绑定成功就添加一个待copy的apk 数据 等待copy//每次连接成功都会发送一个MCS_BOUND 消息 然后处理copy任务,mPendingInstalls.add(idx, params);}} else {mPendingInstalls.add(idx, params);// Already bound to the service. Just make// sure we trigger off processing the first request.if (idx == 0) {//触发下面的MCS_BOUND,进行拷贝apk,然后就是不断循环,消耗mHandler.sendEmptyMessage(MCS_BOUND);}}break;}case MCS_BOUND: {if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");if (msg.obj != null) {mContainerService = (IMediaContainerService) msg.obj;Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",System.identityHashCode(mHandler));}if (mContainerService == null) {if (!mBound) {// Something seriously wrong since we are not bound and we are not// waiting for connection. Bail out.Slog.e(TAG, "Cannot bind to media container service");for (HandlerParams params : mPendingInstalls) {// Indicate service bind errorparams.serviceError();Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",System.identityHashCode(params));if (params.traceMethod != null) {Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,params.traceMethod, params.traceCookie);}return;}mPendingInstalls.clear();} else {Slog.w(TAG, "Waiting to connect to media container service");}} else if (mPendingInstalls.size() > 0) {HandlerParams params = mPendingInstalls.get(0);if (params != null) {Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",System.identityHashCode(params));Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");//开始拷贝if (params.startCopy()) {// We are done...  look for more work or to// go idle.if (DEBUG_SD_INSTALL) Log.i(TAG,"Checking for more work or unbind...");// Delete pending installif (mPendingInstalls.size() > 0) {//拷贝成功了就移除拷贝任务数据mPendingInstalls.remove(0);}if (mPendingInstalls.size() == 0) {if (mBound) {if (DEBUG_SD_INSTALL) Log.i(TAG,"Posting delayed MCS_UNBIND");removeMessages(MCS_UNBIND);Message ubmsg = obtainMessage(MCS_UNBIND);// Unbind after a little delay, to avoid// continual thrashing.//数据没有了 等待10s 就断开服务sendMessageDelayed(ubmsg, 10000);}} else {// There are more pending requests in queue.// Just post MCS_BOUND message to trigger processing// of next pending install.if (DEBUG_SD_INSTALL) Log.i(TAG,"Posting MCS_BOUND for next work");//如果数据还有就继续执行下一个copymHandler.sendEmptyMessage(MCS_BOUND);}}Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}} else {// Should never happen ideally.Slog.w(TAG, "Empty queue");}break;}xxxxxxx 省略代码,,,

总结:

目的:把apk从PackageInstallerSession的暂存目录中 复制到data/app/ 目录下面 或则sdcard的目录下面,这个根据安装参数的flag来区分,为后续工作做准备

过程

1、这个复制的过程是交给DefaultContainerService 这个服务去做的,这个服务在单独的进程

2、每次需要复制的时候先连接服务

private boolean connectToService() {if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +" DefaultContainerService");Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);//可以看到是通过bind方式的if (mContext.bindServiceAsUser(service, mDefContainerConn,Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);mBound = true;return true;}Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);return false;}

3、然后启动了这个服务,在这个同时做了这个操作 mPendingInstalls.add(idx, params); 还有发送了一个MCS_BOUND消息给handler执行拷贝,这个消息是绑定服务成功后做的事情

final private DefaultContainerConnection mDefContainerConn =new DefaultContainerConnection();class DefaultContainerConnection implements ServiceConnection {public void onServiceConnected(ComponentName name, IBinder service) {if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");IMediaContainerService imcs =IMediaContainerService.Stub.asInterface(service);//可以看到绑定成功发送了一个MCS_BOUND消息,可以完成后续的拷贝工作mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));}public void onServiceDisconnected(ComponentName name) {if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");}}

4、MCS_BOUND 的指令下 最后调用了HandlerParams的startCopy方法,HandlerParams是一个抽象类,这里用的实现类是InstallParams ,这里多说一句HandlerParams的实现类有2种MeasureParams,和InstallParams ,

MeasureParams 是测量的作用,计算apk所占用的空间大小

InstallParams 是安装apk的拷贝作用,处理拷贝的任务

HandlerParams的startCopy方法最终会依次调用到handleStartCopy() 还有handleReturnCode() 两个方法

handleStartCopy处理拷贝,需要子类实现

handleReturnCode 处理返回结果,引发后续流程,需要子类实现

5、InstallParams 的handleStartCopy

  ......省略......} else {/** No package verification is enabled, so immediately start* the remote call to initiate copy using temporary file.*/ret = args.copyApk(mContainerService, true);}

我们看到这个arsg 其实是

final InstallArgs args = createInstallArgs(this);

createInstallArgs方法是

 private InstallArgs createInstallArgs(InstallParams params) {if (params.move != null) {return new MoveInstallArgs(params);} else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {return new AsecInstallArgs(params);} else {return new FileInstallArgs(params);}}

这里有三个实现类,

MoveInstallArgs :是处理已经安装了的apk的数据转移的

AsecInstallArgs:这个是处理asec 就是在sdcard安装apk的拷贝类型

FileInstallArgs:这个就是系统内存储的,拷贝到data/app/ 下的类型

我们就来看下FileInstallArgs类型的copyApk

最终 调用了doCopyApk,

private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {if (origin.staged) {if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");codeFile = origin.file;resourceFile = origin.file;return PackageManager.INSTALL_SUCCEEDED;}try {final boolean isEphemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;//从PackageInstallerService 获取目录,这个最终是在Environment中设置好的final File tempDir =mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);codeFile = tempDir;resourceFile = tempDir;} catch (IOException e) {Slog.w(TAG, "Failed to create copy file: " + e);return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;}//这个是跨进程 实现文件流的读写作用的类,下面很明显是根据文件名称,然后实例化一个文件描述符,最终转为Out流,进行读写final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {@Overridepublic ParcelFileDescriptor open(String name, int mode) throws RemoteException {if (!FileUtils.isValidExtFilename(name)) {throw new IllegalArgumentException("Invalid filename: " + name);}try {final File file = new File(codeFile, name);final FileDescriptor fd = Os.open(file.getAbsolutePath(),O_RDWR | O_CREAT, 0644);Os.chmod(file.getAbsolutePath(), 0644);return new ParcelFileDescriptor(fd);} catch (ErrnoException e) {throw new RemoteException("Failed to open: " + e.getMessage());}}};int ret = PackageManager.INSTALL_SUCCEEDED;//最终调用了DefaultContainerService 的 copyPackage方法ret = imcs.copyPackage(.getAbsolutePaorigin.fileth(), target);if (ret != PackageManager.INSTALL_SUCCEEDED) {Slog.e(TAG, "Failed to copy package");return ret;}//下面是so库的拷贝final File libraryRoot = new File(codeFile, LIB_DIR_NAME);NativeLibraryHelper.Handle handle = null;try {handle = NativeLibraryHelper.Handle.create(codeFile);ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,abiOverride);} catch (IOException e) {Slog.e(TAG, "Copying native libraries failed", e);ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;} finally {IoUtils.closeQuietly(handle);}return ret;}

最后在看下DafaultContainerService的拷贝实现

 @Overridepublic int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {if (packagePath == null || target == null) {return PackageManager.INSTALL_FAILED_INVALID_URI;}//这个是轻量化的apk包,这个包有可能是一个apk文件是全量的,有可能是一个apk的目录,李米娜有很多的子apk。还有其他文件,这种情况是因为方法数65535超过后,google做的把apk拆分的策略PackageLite pkg = null;try {final File packageFile = new File(packagePath);pkg = PackageParser.parsePackageLite(packageFile, 0);return copyPackageInner(pkg, target);} catch (PackageParserException | IOException | RemoteException e) {Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;}}

下面是后续实现

 private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)throws IOException, RemoteException {copyFile(pkg.baseCodePath, target, "base.apk");if (!ArrayUtils.isEmpty(pkg.splitNames)) {//看到如果是多个apk就是splitNames 数组 多个了,以此都要拷贝for (int i = 0; i < pkg.splitNames.length; i++) {copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk");}}//拷贝完成就返回成功return PackageManager.INSTALL_SUCCEEDED;}private void copyFile(String sourcePath, IParcelFileDescriptorFactory target, String targetName)throws IOException, RemoteException {Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);InputStream in = null;OutputStream out = null;try {in = new FileInputStream(sourcePath);out = new ParcelFileDescriptor.AutoCloseOutputStream(//这里这个open 就是前面的 open 传过来的的ParcelFileDescriptortarget.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE));//最终的复制工作,拷贝完成Streams.copy(in, out);} finally {IoUtils.closeQuietly(out);IoUtils.closeQuietly(in);}}

6、InstallParams#handleReturnCode

@Overridevoid 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);}}

这个方法是执行完成了拷贝apk任务后返回的结果

最终调用了PMS的processPendingInstall方法

3、PackageManaPgerService#processPendingInstall

private void processPendingInstall(final InstallArgs args, final int currentStatus) {// Queue up an async operation since the package installation may take a little while.mHandler.post(new Runnable() {public void run() {mHandler.removeCallbacks(this);// Result object to be returnedPackageInstalledInfo res = new PackageInstalledInfo();res.setReturnCode(currentStatus);res.uid = -1;res.pkg = null;res.removedInfo = null;if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//如果安装成功 执行doPreInstall 主要是解析apk前的清理工作args.doPreInstall(res.returnCode);synchronized (mInstallLock) {//核心方法 installPackageTracedLI(args, res);}//后续操作,如果没安装成功 就做清理工作args.doPostInstall(res.returnCode, res.uid);}// A restore should be performed at this point if (a) the install// succeeded, (b) the operation is not an update, and (c) the new// package has not opted out of backup participation.final boolean update = res.removedInfo != null&& res.removedInfo.removedPackage != null;final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;boolean doRestore = !update&& ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);// Set up the post-install work request bookkeeping.  This will be used// and cleaned up by the post-install event handling regardless of whether// there's a restore pass performed.  Token values are >= 1.int token;if (mNextInstallToken < 0) mNextInstallToken = 1;token = mNextInstallToken++;PostInstallData data = new PostInstallData(args, res);mRunningInstalls.put(token, data);if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);//如果apk 程序设置了备份 就执行备份操作if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {// Pass responsibility to the Backup Manager.  It will perform a// restore if appropriate, then pass responsibility back to the// Package Manager to run the post-install observer callbacks// and broadcasts.IBackupManager bm = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));if (bm != null) {if (DEBUG_INSTALL) Log.v(TAG, "token " + token+ " to BM for possible restore");Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);try {// TODO: http://b/22388012if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);} else {doRestore = false;}} catch (RemoteException e) {// can't happen; the backup manager is local} catch (Exception e) {Slog.e(TAG, "Exception trying to enqueue restore", e);doRestore = false;}} else {Slog.e(TAG, "Backup Manager not found!");doRestore = false;}}if (!doRestore) {// No restore possible, or the Backup Manager was mysteriously not// available -- just fire the post-install work request directly.if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);//发送消息给上层 安装完成,整个安装执行完毕Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);mHandler.sendMessage(msg);}}});}

我们继续看installPackageTracedLI

4、PackageManaPgerService#installPackageTracedLI

private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {try {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");installPackageLI(args, res);} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}}

5、PackageManaPgerService#installPackageLI

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {...// 1. 解析package信息,final PackageParser.Package pkg;try {pkg = pp.parsePackage(tmpPackageFile, parseFlags);} catch (PackageParserException e) {res.setError("Failed parse during installPackageLI", e);return;} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}// 2. 签名校验try {verifySignaturesLP(signatureCheckPs, pkg);} catch (PackageManagerException e) {res.setError(e.error, e.getMessage());return;}// 3. 对dex进行优化mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,null , false ,getCompilerFilterForReason(REASON_INSTALL),getOrCreateCompilerPackageStats(pkg),mDexManager.isUsedByOtherApps(pkg.packageName));// 4. 重命名 将文件夹的名称重命名为 “包名”,就是data/app/com.xx.xx/ 这样if (!args.doRename(res.returnCode, pkg, oldCodePath)) {res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");return;}// 5. 替换或新安装APK,走不同的路线if (replace) {replacePackageLIF(pkg, parseFlags, scanFlags, args.user,installerPackageName, res, args.installReason); } else {installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,args.user, installerPackageName, volumeUuid, res, args.installReason); }
}

上面的这个方法很长,我做了重点提取 以及注释

我们看下最后的installNewPackageLIF 安装一个新的apk文件

6、PackageManaPgerService#installNewPackageLIF

  /** Install a non-existing package.*/private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,PackageInstalledInfo res) {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");// Remember this for later, in case we need to rollback this installString pkgName = pkg.packageName;if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);synchronized(mPackages) {if (mSettings.mRenamedPackages.containsKey(pkgName)) {// A package with the same name is already installed, though// it has been renamed to an older name.  The package we// are trying to install should be installed as an update to// the existing one, but that has not been requested, so bail.res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName+ " without first uninstalling package running as "+ mSettings.mRenamedPackages.get(pkgName));return;}if (mPackages.containsKey(pkgName)) {// Don't allow installation over an existing package with the same name.res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName+ " without first uninstalling.");return;}}try {//扫描这个apkPackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,System.currentTimeMillis(), user);//将扫描的结果 更新到setting中updateSettingsLI(newPackage, installerPackageName, null, res, user);if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {prepareAppDataAfterInstallLIF(newPackage);} else {// Remove package from internal structures, but keep around any// data that might have already existed//如果失败了就删除 中间的临时文件deletePackageLIF(pkgName, UserHandle.ALL, false, null,PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);}} catch (PackageManagerException e) {res.setError("Package couldn't be installed in " + pkg.codePath, e);}Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}

7、PackageManaPgerService#scanPackageTracedLI

  private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");try {return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}}

8、PackageManaPgerService#scanPackageLI

    private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,long currentTime, UserHandle user) throws PackageManagerException {if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);PackageParser pp = new PackageParser();pp.setSeparateProcesses(mSeparateProcesses);pp.setOnlyCoreApps(mOnlyCore);pp.setDisplayMetrics(mMetrics);if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;}Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");final PackageParser.Package pkg;try {pkg = pp.parsePackage(scanFile, parseFlags);} catch (PackageParserException e) {throw PackageManagerException.from(e);} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);}

9、PackageManaPgerService#scanPackageLI

 /***  Scans a package and returns the newly parsed package.*  @throws PackageManagerException on a parse error.*/private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,final int policyFlags, int scanFlags, long currentTime, UserHandle user)throws PackageManagerException {// If the package has children and this is the first dive in the function// we scan the package with the SCAN_CHECK_ONLY flag set to see whether all// packages (parent and children) would be successfully scanned before the// actual scan since scanning mutates internal state and we want to atomically// install the package and its children.if ((scanFlags & SCAN_CHECK_ONLY) == 0) {if (pkg.childPackages != null && pkg.childPackages.size() > 0) {scanFlags |= SCAN_CHECK_ONLY;}} else {scanFlags &= ~SCAN_CHECK_ONLY;}// Scan the parentPackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags,scanFlags, currentTime, user);// Scan the childrenfinal int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;for (int i = 0; i < childCount; i++) {PackageParser.Package childPackage = pkg.childPackages.get(i);scanPackageInternalLI(childPackage, scanFile, policyFlags, scanFlags,currentTime, user);}if ((scanFlags & SCAN_CHECK_ONLY) != 0) {return scanPackageLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user);}return scannedPkg;}

10、PackageManaPgerService#scanPackageLI

 private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {boolean success = false;try {final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,currentTime, user);success = true;return res;} finally {if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {// DELETE_DATA_ON_FAILURES is only used by frozen pathsdestroyAppDataLIF(pkg, UserHandle.USER_ALL,StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);}}}

上面这些scanPackageLI 都是同名的方法,但是参数不同,

11、PackageManaPgerService#scanPackageDirtyLI

这个方法是很长的核心方法

主要功能:

对扫描的package 进行解析,然后把四大组件还有权限的信息 添加到PMS的内部数据集合中保存起来,供系统中的其他app或者服务来访问,PMS在系统中的作用相当于是系统的app数据中心,存储了app的一切信息,

scanPackageDirtyLI
{// 针对包名为"android" 的APK进行处理, 这个app 主要是
//选择是ChoseActivity 就是有相同的Intent 弹出的界面
//还有个关机app的界面if (pkg.packageName.equals("android")) {
//shouldCheckUpgradeKeySetLP方法进行密钥检查,是否一致
if (shouldCheckUpgradeKeySetLP(pkgSetting, scanFlags))
// 重新验证签名
verifySignaturesLP(pkgSetting, pkg);
// 确定 进程的名称
pkg.applicationInfo.processName = fixProcessName(pkg.applicationInfo.packageName,pkg.applicationInfo.processName,pkg.applicationInfo.uid);
// 设置native相关属性 系统app native 会统一放在/system/lib/
//如果是普通app 在/data/data/packageName/lib下建立和CPU类型对应的目录,例如ARM平台 arm,MIP平台 mips/
//设置native 库的路径
// 创建native库链接
//注册pkg里面的provider到PMS上的mProvider上
// 注册该Package中的service到PMS的mServices上
// 注册pkg里面的receiver到PMS上的receivers上
//注册pkg里面的activity到PMS上的activities上
//注册pkg里面的PermissionGroup到PMS上的mPermissionGroups上
//注册pkg里面的Permission到PMS上的permissionMap上
//注册pkg里面的instrumentation到PMS的mInstrumentation中

经历了上面的过程在PMS的安装过程已经完成了,接下来就是通知上层创建成功了

12、PackageManagerService#handlePackagePostInstall

安装完成后,后续流程会发送一个POST_INSTALL消息给mHandler 然后执行handlePackagePostInstall方法

 。。。。。。。省略。。。。。。// If someone is watching installs - notify themif (installObserver != null) {try {Bundle extras = extrasForInstallResult(res);//回调通知上层installObserver.onPackageInstalled(res.name, res.returnCode,res.returnMsg, extras);} catch (RemoteException e) {Slog.i(TAG, "Observer no longer exists.");}}

13、PackageInstallerSession#dispatchSessionFinished

 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {@Overridepublic void onUserActionRequired(Intent intent) {throw new IllegalStateException();}@Overridepublic void onPackageInstalled(String basePackageName, int returnCode, String msg,Bundle extras) {destroyInternal();dispatchSessionFinished(returnCode, msg, extras);}};

然后

private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {mFinalStatus = returnCode;mFinalMessage = msg;if (mRemoteObserver != null) {try {mRemoteObserver.onPackageInstalled(mPackageName, returnCode, msg, extras);} catch (RemoteException ignored) {}}final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);mCallback.onSessionFinished(this, success);}

14、PackageInstallObserverAdapter#onPackageInstalled

 @Override
1037          public void onPackageInstalled(String basePackageName, int returnCode, String msg,
1038                  Bundle extras) {
1039              if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
1040                  boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
1041                  Notification notification = buildSuccessNotification(mContext,
1042                          mContext.getResources()
1043                                  .getString(update ? R.string.package_updated_device_owner :
1044                                          R.string.package_installed_device_owner),
1045                          basePackageName,
1046                          mUserId);
1047                  if (notification != null) {
1048                      NotificationManager notificationManager = (NotificationManager)
1049                              mContext.getSystemService(Context.NOTIFICATION_SERVICE);
1050                      notificationManager.notify(basePackageName, 0, notification);
1051                  }
1052              }
1053              final Intent fillIn = new Intent();
1054              fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
1055              fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
1056              fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
1057                      PackageManager.installStatusToPublicStatus(returnCode));
1058              fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
1059                      PackageManager.installStatusToString(returnCode, msg));
1060              fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
1061              if (extras != null) {
1062                  final String existing = extras.getString(
1063                          PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
1064                  if (!TextUtils.isEmpty(existing)) {
1065                      fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
1066                  }
1067              }
1068              try {
1069                  mTarget.sendIntent(mContext, 0, fillIn, null, null);
1070              } catch (SendIntentException ignored) {
1071              }
1072          }
1073      }

最后可以看到,安装完成后,发送了一个广播,在luncher 注册了这个广播,然后更新页面,添加一个图标

Android-Apk的安装流程分析(二)相关推荐

  1. Android 11 热点(softap)流程分析(二) WifiManager--AIDL

    Android 10以后引入了stable aidl方法,结合上一篇中WifiManager类中通过aidl调用到WifiServiceImpl类中方法,做个详细的记录. 一.frameworks/b ...

  2. AOSP Android 8.0 冷启动流程分析(二)

    前奏: Android系统虽然基于Linux系统的,但是由于Android属于嵌入式设备,并没有像PC那样的BISO程序,取而代之的是Bootloader----系统启动加载器. /boot : 存放 ...

  3. c++builder启动了怎么停止_App 竟然是这样跑起来的 —— Android App/Activity 启动流程分析...

    在我的上一篇文章: AJie:按下电源键后竟然发生了这一幕 -- Android 系统启动流程分析​zhuanlan.zhihu.com 我们分析了系统在开机以后的一系列行为,其中最后一阶段 AMS( ...

  4. Android8.0(34)----Android 8.0 Settings流程分析与变动

    Android 8.0 Settings流程分析与变动 一,相比Android Settings 7.0 如下图,在7.0的基础上,去掉了7.0新加的侧滑菜单(可能是觉得有点鸡肋吧).多加了一级页面, ...

  5. Android 手机灭屏流程分析详解

    参考地址:https://www.jianshu.com/p/9241f3a91095 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 1.前言 2.Pow ...

  6. android 闪退解决方案,Android apk无法安装及闪退问题解决办法

    Android apk无法安装及闪退问题 app在部分手机上(低版本)打不开或打开就闪退的问题 之前做项目集成的是 环信的sdk ,环信的sdk 确实很好,客服 也很给力.但是在集成的过程中发现,ap ...

  7. android 屏幕旋转流程,android自动屏幕旋转流程分析.doc

    android自动屏幕旋转流程分析.doc android自动屏幕旋转流程分析 在android设置(Settings)中我们可以看到显示(display)下有一个自动屏幕旋转的checkbox, 如 ...

  8. android加载efi分区,高通Android UEFI XBL 代码流程分析

    高通Android UEFI XBL 代码流程分析 背景 之前学习的lk阶段点亮LCD的流程算是比较经典,但是高通已经推出了很多种基于UEFI方案的启动架构. 所以需要对这块比较新的技术进行学习.在学 ...

  9. Android 证书安装流程分析

    一.证书在源码中的路径 5.1系统证书(命名是 openssl x509 -subject_hash_old -in filename) libcore/luni/src/main/files/cac ...

最新文章

  1. Linux 汇编语言开发指南
  2. python输入输出-2. Python中的基本输入、输出、格式化输出
  3. vivo Y81s的usb调试模式在哪里,打开vivo Y81susb调试模式的流程
  4. SDNU 1263.C语言程序设计教程(第三版)课后习题10.5(约瑟夫环)
  5. 【CAS】Implementing generic double-word compare and swap for x86/x86-64
  6. 学习minix 3(未完成)
  7. 【转】赶集网mysql开发36军规
  8. python转bat_bat 转换为python
  9. 从SLAM到视觉识别、VIO,大牛分享!
  10. 小米电视怎么看CCTV?安装超好用的HDP直播来帮助你
  11. Prometheus 监控案例详解
  12. 自学Java语言网络编程局域网内与电脑无线传输视频,图片文件,调用系统媒体播放视频图片文件
  13. 新手玩荔枝派 f1c100s nano折腾笔记(三)
  14. Binder源码阅读指南之java层,作为Android开发程序员
  15. 企业级docker安装kong,konga实战
  16. ubuntu20.04中安装Flatpak,切换数据源
  17. 安卓程序开发需要学习哪些语言
  18. SpringCloud+SpringBoot b2b2c 电子商务平台涉及的技术、运营方案
  19. SpringBoot重点详解--dbcp2数据源配置
  20. 多商品评价页面对用户评价信息的处理

热门文章

  1. CCS6.2.0 如何将工程封装成lib文件
  2. jira把hsql转成mysql_jira从HSQL迁移到MYSQL
  3. TD-问题解答(四)
  4. USB隨身碟格式化工具程式—HPUSBFW
  5. MATLAB安装后出现“License Manager Error -8?”,替换文档时报错解决方法
  6. 给水管网模拟学习路线
  7. 超经典的20道SQL题目(附加解题思路)
  8. 2021年高压电工免费试题及高压电工模拟考试题
  9. C语言数组——交换位置
  10. python安装pandas