android 9 adb安装过程学习(三)

PackageManagerService

一、PackageManagerService.installStage

接下来,进入 PackageManagerService 阶段。从PackageInstallerSession.java的commitLocked调用

这里的 IPackageInstallObserver2 observer 是前面创建的本次 localObserver:

位置:./frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

java 复制代码
    void installStage(String packageName, File stagedDir,
            IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
            String installerPackageName, int installerUid, UserHandle user,
            PackageParser.SigningDetails signingDetails) {
        if (DEBUG_INSTANT) {
            if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
                Slog.d(TAG, "Ephemeral install of " + packageName);
            }
        }
        //【1.1】创建一个 VerificationInfo 对象,用于校验
        final VerificationInfo verificationInfo = new VerificationInfo(
                sessionParams.originatingUri, sessionParams.referrerUri,
                sessionParams.originatingUid, installerUid);
		//【1.2】创建了一个 OriginInfo 对象
        final OriginInfo origin = OriginInfo.fromStagedFile(stagedDir);
		//【1】创建了一个 INIT_COPY 消息
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        final int installReason = fixUpInstallReason(installerPackageName, installerUid,
                sessionParams.installReason);
        //【1.3】创建一个 InstallParams 安装参数对象
        final InstallParams params = new InstallParams(origin, null, observer,
                sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
                verificationInfo, user, sessionParams.abiOverride,
                sessionParams.grantedRuntimePermissions, signingDetails, installReason);
        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));
		//【2】发送 INIT_COPY 消息
        mHandler.sendMessage(msg);
    }

这里的 mHandler 是在 PackageManagerService 的构造器中创建的:

java 复制代码
	synchronized (mPackages) {
    		mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            //...
    }

是一个 PackageHandler 实例,其绑定了一个子线程 ServiceThread

1.1 new VerificationInfo

VerificationInfo 类定义在 PackageManagerService 中,用于信息校验:

java 复制代码
    static class VerificationInfo {
        /** A constant used to indicate that a uid value is not present. */
        public static final int NO_UID = -1;

        /** URI referencing where the package was downloaded from. */
        final Uri originatingUri;

        /** HTTP referrer URI associated with the originatingURI. */
        final Uri referrer;

        /** UID of the application that the install request originated from. */
        final int originatingUid;

        /** UID of application requesting the install */
        final int installerUid;	// 安装者应用的 uid

        VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) {
            this.originatingUri = originatingUri;
            this.referrer = referrer;
            this.originatingUid = originatingUid;
            this.installerUid = installerUid;
        }
    }

1.2 new OriginInfo

这里创建了一个 OriginInfo 实例,封装安装目录相关信息

java 复制代码
    static class OriginInfo {
        /**
         * Location where install is coming from, before it has been
         * copied/renamed into place. This could be a single monolithic APK
         * file, or a cluster directory. This location may be untrusted.
         */
        final File file;	// 安装到内置存储,不为 null

        /**
         * Flag indicating that {@link #file} or {@link #cid} has already been
         * staged, meaning downstream users don't need to defensively copy the
         * contents.
         */
        final boolean staged;

        /**
         * Flag indicating that {@link #file} or {@link #cid} is an already
         * installed app that is being moved.
         */
        final boolean existing;

        final String resolvedPath;
        final File resolvedFile;

        static OriginInfo fromNothing() {
            return new OriginInfo(null, false, false);
        }

        static OriginInfo fromUntrustedFile(File file) {
            return new OriginInfo(file, false, false);
        }

        static OriginInfo fromExistingFile(File file) {
            return new OriginInfo(file, false, true);
        }

        static OriginInfo fromStagedFile(File file) {	//【1】安装到内置存储会调用
            return new OriginInfo(file, true, false);
        }

        private OriginInfo(File file, boolean staged, boolean existing) {
            this.file = file;	// 内置时为:/data/app/vmdl[sessionId].tmp
            this.staged = staged;	// 安装到内置存储时为 true
            this.existing = existing;	// 安装到内置存储时为 false

            if (file != null) {
                resolvedPath = file.getAbsolutePath();
                resolvedFile = file;
            } else {
                resolvedPath = null;
                resolvedFile = null;
            }
        }
    }

这里我们先关注安装到内置存储中的逻辑

1.3 new PMS.InstallParams

InstallParams 类定义在 PackageManagerService 中,封装了安装参数:

java 复制代码
    class InstallParams extends HandlerParams {
        final OriginInfo origin;
        final MoveInfo move;	// move package 才会传入,安装时为 null
        final IPackageInstallObserver2 observer;	// 本地传观察者
        int installFlags;
        final String installerPackageName;
        final String volumeUuid;
        private InstallArgs mArgs;
        private int mRet;
        final String packageAbiOverride;
        final String[] grantedRuntimePermissions;	// 安装时授予的运行时权限列表
        final VerificationInfo verificationInfo;
        final PackageParser.SigningDetails signingDetails;
        final int installReason;

        InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                int installFlags, String installerPackageName, String volumeUuid,
                VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
                String[] grantedPermissions, PackageParser.SigningDetails signingDetails, int installReason) {
            super(user);
            this.origin = origin;
            this.move = move;
            this.observer = observer;
            this.installFlags = installFlags;
            this.installerPackageName = installerPackageName;
            this.volumeUuid = volumeUuid;
            this.verificationInfo = verificationInfo;
            this.packageAbiOverride = packageAbiOverride;
            this.grantedRuntimePermissions = grantedPermissions;
            this.signingDetails = signingDetails;
            this.installReason = installReason;
        }
        //...
    }

InstallParams 继承了 HandlerParams

这里涉及到一个 MoveInfo move,在 movePackageInternal 也就是移动 package 时才会调用,这里是安装,我们先不关注

二、PackageHandler.doHandleMessage[INIT_COPY]

位置:./frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

installStage最后发送了INIT_COPY消息,它会在子线程的PackageHandler 中处理 INIT_COPY 消息:

java 复制代码
				case INIT_COPY: {
					//【1】取出 InstallParams
                    HandlerParams params = (HandlerParams) msg.obj;
                    // mPendingInstalls 中会保存所有正在等待的安装
                    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.
                    //【2】mBound 用来判断是否已经绑定到了 DefaultContainerService,该服务用于安装
                    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.
                        //【2.1】尝试去 bind 服务,bind 成功后,mBound 置为 true
                        if (!connectToService()) {
                            Slog.e(TAG, "Failed to bind to media container service");
                            //【2.2】如果不能 bind 成功,那就触发 HandlerParams 的 serviceError 方法
                            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.
                            //【3】将本次的安装参数添加到等待集合中
                            mPendingInstalls.add(idx, params);
                        }
                    } else {
                    //【4】如果之前已经 bind 了,那就直接将安装参数添加到等待集合中
                        mPendingInstalls.add(idx, params);
                        // Already bound to the service. Just make
                        // sure we trigger off processing the first request.
                        //【3】如果是第一次添加,发送 MCS_BOUND 消息
                        if (idx == 0) {
                            mHandler.sendEmptyMessage(MCS_BOUND);
                        }
                    }
                    break;
                }

这里逻辑很清晰了,我们继续看

2.1 PackageHandler.connectToService

java 复制代码
        private boolean connectToService() {
            if (DEBUG_INSTALL) Log.i(TAG, "Trying to bind to DefaultContainerService");
            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
            //【1】开始 bind 服务,传入了 mDefContainerConn 对象
            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;
        }

这里 bind 的服务是 DefaultContainerService

java 复制代码
    public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
            DEFAULT_CONTAINER_PACKAGE,
            "com.android.defcontainer.DefaultContainerService");

PackageManagerService 内部持有一个 DefaultContainerConnection 实例

java 复制代码
    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");
            //【1】获得 DefaultContainerConnection 代理对象
            final IMediaContainerService imcs = IMediaContainerService.Stub
                    .asInterface(Binder.allowBlocking(service));
            //【5.3】发送 MCS_BOUND 消息
            mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
        }

        public void onServiceDisconnected(ComponentName name) {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
        }
    }

最后会发送 MCS_BOUND 消息给 PackageHandler 对象

2.2 InstallParams.serviceError

serviceError 方法是从 HandlerParams 中继承到的

java 复制代码
        final void serviceError() {
            if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");
            //【4.2】安装异常,保存结果
            handleServiceError();
            handleReturnCode();
        }

三、PackageHandler.doHandleMessage[MCS_BOUND] - 绑定服务

继续来看下 PackageHandler 对 MCS_BOUND 的处理

java 复制代码
				case MCS_BOUND: {
                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
                    //【1】这里的 msg.obj 是前面 bind 获得的代理对象,将其保存到 mContainerService 中
                    if (msg.obj != null) {
                        mContainerService = (IMediaContainerService) msg.obj;
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                System.identityHashCode(mHandler));
                    }
                    //【2】异常处理,如果 mContainerService 为 null,且 mBound 为 ture,那么这种情况是异常
                    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");
                            //【2.1】遍历所有的 HandlerParams 安装参数,回调 serviceError
                            for (HandlerParams params : mPendingInstalls) {
                                // Indicate service bind error
                                params.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);
                                }
                            }
                            //【2.2】清空 mPendingInstalls 集合
                            mPendingInstalls.clear();
                        } else {
                            Slog.w(TAG, "Waiting to connect to media container service");
                        }
                    } else if (mPendingInstalls.size() > 0) {
                    	//【3】正常情况下,bind 是有效的,那么会进入这里
                        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");
                            //【5.4】调用了 HandlerParams 的 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 install
                                //【3.1】本次安装完成,删除本次处理的安装参数
                                if (mPendingInstalls.size() > 0) {
                                    mPendingInstalls.remove(0);
                                }
                                if (mPendingInstalls.size() == 0) {
                                	//【3.2】如果所有的安装参数都处理玩了,unbind 服务
                    				// 这里的 unbind 延迟了 10s
                                    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.
                                        sendMessageDelayed(ubmsg, 10000);
                                    }
                                } else {
                                    // There are more pending requests in queue.
                                    // Just post MCS_BOUND message to trigger processing
                                    // of next pending install.
                                    //【3.3】在安装队列中有其他的安装项,我们发送 MCS_BOUND 消息继续处理
                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
                                            "Posting MCS_BOUND for next work");
                                    mHandler.sendEmptyMessage(MCS_BOUND);
                                }
                            }
                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                        }
                    } else {
                        // Should never happen ideally.
                        Slog.w(TAG, "Empty queue");
                    }
                    break;
                }

四、InstallParams.startCopy

InstallParams 继承了 HandlerParams

java 复制代码
        final boolean startCopy() {
            boolean res;
            try {
                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
				//【1】如果重试次数大于 4 ,那么就放弃本次安装
                if (++mRetries > MAX_RETRIES) {
                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                    //【4.1】发送 MCS_GIVE_UP 消息
                    mHandler.sendEmptyMessage(MCS_GIVE_UP);
                    //【4.2】处理失败结果
                    handleServiceError();
                    return false;
                } else {
                	//【5】继续安装
                    handleStartCopy();
                    res = true;
                }
            } catch (RemoteException e) {
                if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
                //【4.3】发送 MCS_RECONNECT 消息
                mHandler.sendEmptyMessage(MCS_RECONNECT);
                res = false;
            }
            //【4.4】处理返回码
            handleReturnCode();
            return res;
        }

这里定义了安装尝试次数:

java 复制代码
        private static final int MAX_RETRIES = 4;

4.1 PackageHandler.doHandleMessage[MCS_GIVE_UP] - 放弃安装

重试次数大于 4 ,那么就放弃本次安装

java 复制代码
                case MCS_GIVE_UP: {
                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries");
                    //【1】移除这个安装参数
                    HandlerParams params = mPendingInstalls.remove(0);
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                            System.identityHashCode(params));
                    break;
                }

4.2 InstallParams.handleServiceError

处理本次安装失败的结果:

java 复制代码
        @Override
        void handleServiceError() {
        	//【2.3】创建安装参数 InstallArgs
            mArgs = createInstallArgs(this);
            mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
        }

这里的 createInstallArgs 方法我们后面再分析

4.3 PackageHandler.doHandleMessage[MCS_RECONNECT] - 重连服务

MCS_RECONNECT 消息会尝试重连服务

java 复制代码
                case MCS_RECONNECT: {
                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect");
                    if (mPendingInstalls.size() > 0) {
                    	//【1】如果 mBound 为 true,先尝试断开连接
                        if (mBound) {
                            disconnectService();
                        }
                        //【2】开始重新连接服务
                        if (!connectToService()) {
                            Slog.e(TAG, "Failed to bind to media container service");
                            for (HandlerParams params : mPendingInstalls) {
                                // Indicate service bind error
                                //【2.2】返回安装异常
                                params.serviceError();
                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                        System.identityHashCode(params));
                            }
                            //【3】清空 mPendingInstalls 集合
                            mPendingInstalls.clear();
                        }
                    }
                    break;
                }

4.4 InstallParams.handleReturnCode

当 mArgs 为 null 的时候,此时该 package 正在被校验,所以需要等到校验成功后才能安装,所以不会进入这里

java 复制代码
        @Override
        void 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.
            //【1】如果 mArgs 这里为 null,可能是不需要校验
            if (mArgs != null) {
                processPendingInstall(mArgs, mRet);	//【7】继续安装
            }
        }

五、InstallParams.handleStartCopy

在startCopy里,如果正常就继续copy,调用handleStartCopy()

java 复制代码
        public void handleStartCopy() throws RemoteException {
        	//【1】保存安装结果,默认为成功
            int ret = PackageManager.INSTALL_SUCCEEDED;

            // If we're already staged, we've firmly committed to an install location
            //【2】我们知道 origin 中存储了安装目录相关的信息
            if (origin.staged) {
                if (origin.file != null) {
	                //【2.1】安装到内置存储中
                    installFlags |= PackageManager.INSTALL_INTERNAL;
                    installFlags &= ~PackageManager.INSTALL_EXTERNAL;
                } else {
                    throw new IllegalStateException("Invalid stage location");
                }
            }
			//【3】判断安装位置
            final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
            final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
            final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
            PackageInfoLite pkgLite = null;
			//【4】判断安装位置是否满足条件
            if (onInt && onSd) {
                // Check if both bits are set.	//【4.1】不能同时设置安装在 sd 和内置中
                Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else if (onSd && ephemeral) {
                Slog.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
                //【4.2】不能设置短暂安装在 sd 中
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else {
            	//【5.1】利用 ContainerService 获取 PackageInfoLite,同时判断空间是否合适
                pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                        packageAbiOverride);

                if (DEBUG_INSTANT && ephemeral) {
                    Slog.v(TAG, "pkgLite for install: " + pkgLite);
                }

                /*
                 * If we have too little free space, try to free cache
                 * before giving up.
                 */	//【4.3】空间不足,尝试释放空间
                if (!origin.staged && pkgLite.recommendedInstallLocation
                        == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                    // TODO: focus freeing disk space on the target device
                    final StorageManager storage = StorageManager.from(mContext);
                    final long lowThreshold = storage.getStorageLowBytes(
                            Environment.getDataDirectory());

                    final long sizeBytes = mContainerService.calculateInstalledSize(
                            origin.resolvedPath, packageAbiOverride);

                    try {
                    	//【4.4】通过 installd 释放存储
                        mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
                        //【5.1】再次利用 ContainerService 获取 PackageInfoLite,同时判断空间是否合适
                        pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
                                installFlags, packageAbiOverride);
                    } catch (InstallerException e) {
                        Slog.w(TAG, "Failed to free cache", e);
                    }

                    /*
                     * The cache free must have deleted the file we
                     * downloaded to install.
                     *
                     * TODO: fix the "freeCache" call to not delete
                     *       the file we care about.
                     */	//【4.5】依然无法安装,设置结果为 RECOMMEND_FAILED_INSUFFICIENT_STORAGE
                    if (pkgLite.recommendedInstallLocation
                            == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                        pkgLite.recommendedInstallLocation
                            = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
                    }
                }
            }
			//【5】处理前面的空间判断后的结果
            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                int loc = pkgLite.recommendedInstallLocation;
                if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
                    ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                    ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_APK;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_URI;
                } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                    ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
                } else {
                    // Override with defaults if needed.
                    //【5.2】调用 installLocationPolicy 方法,针对于降级安装和替换安装做处理
                    loc = installLocationPolicy(pkgLite);
                    if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
                        ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;	// 处理无法降级的结果
                    } else if (!onSd && !onInt) {
                        // Override install location with flags
                        // 如果 flags 没有指定内置还是外置,那么由 installLocationPolicy 的返回值指定
                        if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
                            // Set the flag to install on external media.
                            installFlags |= PackageManager.INSTALL_EXTERNAL;	// 外置
                            installFlags &= ~PackageManager.INSTALL_INTERNAL;
                        } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) { 	// 内置并且是短暂安装
                            if (DEBUG_INSTANT) {
                                Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
                            }
                            installFlags |= PackageManager.INSTALL_INSTANT_APP;	// 内置
                            installFlags &= ~(PackageManager.INSTALL_EXTERNAL	
                                    |PackageManager.INSTALL_INTERNAL);
                        } else {
                            // Make sure the flag for installing on external
                            // media is unset
                            installFlags |= PackageManager.INSTALL_INTERNAL;	// 内置并且是短暂安装
                            installFlags &= ~PackageManager.INSTALL_EXTERNAL;
                        }
                    }
                }
            }
			 //【5.3】创建一个 InstallArgs 对象,和 InstallParams 相互引用
            final InstallArgs args = createInstallArgs(this);
            mArgs = args;

            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                // TODO: http://b/22976637
                // Apps installed for "all" users use the device owner to verify the app
                //【6】如果该应用是安装给 all users 的,那么需要校验应用
                UserHandle verifierUser = getUser();
                if (verifierUser == UserHandle.ALL) {
                    verifierUser = UserHandle.SYSTEM;
                }

                /*
                 * Determine if we have any installed package verifiers. If we
                 * do, then we'll defer to them to verify the packages.
                 */
                //【7】尝试找到系统中安装的 pacakge 校验器,如果可以找到,那就要做校验啦
                //【7.1】获得校验器的 uid 
                final int requiredUid = mRequiredVerifierPackage == null ? -1
                        : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
                                verifierUser.getIdentifier());
                //【7.1】如果是安装到内置存储(existing 为 true),并且系统中有校验器,并且系统打开了校验功能,那么就尝试校验
                //【5.4】通过 isVerificationEnabled 判断是否打开校验功能
                final int installerUid =
                        verificationInfo == null ? -1 : verificationInfo.installerUid;
                if (!origin.existing && requiredUid != -1
                        && isVerificationEnabled(
                                verifierUser.getIdentifier(), installFlags, installerUid)) {
                    //【7.1.1】准备发送校验广播
                    final Intent verification = new Intent(
                            Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
                    verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                    verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                            PACKAGE_MIME_TYPE);		// 设置 DataAndType 属性,包含了 apk 路径对应的 uri
                    verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);	// 增加了临时的权限授予

                    // Query all live verifiers based on current user state
                    //【7.1.2】查询校验器
                    final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
                            PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),
                            false /*allowDynamicSplits*/);

                    if (DEBUG_VERIFY) {
                        Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
                                + verification.toString() + " with " + pkgLite.verifiers.length
                                + " optional verifiers");
                    }
					// 计算本次校验的唯一标识 token
                    final int verificationId = mPendingVerificationToken++;

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
					// 安装器(packageInstaller)
                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
                            installerPackageName);
					// 本次安装的 installFlags
                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
                            installFlags);
					// 要校验的应用
                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
                            pkgLite.packageName);
					// 版本号
                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
                            pkgLite.versionCode);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
                            pkgLite.getLongVersionCode());
					// 如果指定了校验信息,将其写入 intent
                    if (verificationInfo != null) {
                        if (verificationInfo.originatingUri != null) {
                            verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
                                    verificationInfo.originatingUri);
                        }
                        if (verificationInfo.referrer != null) {
                            verification.putExtra(Intent.EXTRA_REFERRER,
                                    verificationInfo.referrer);
                        }
                        if (verificationInfo.originatingUid >= 0) {
                            verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
                                    verificationInfo.originatingUid);
                        }
                        if (verificationInfo.installerUid >= 0) {
                            verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
                                    verificationInfo.installerUid);
                        }
                    }
					//【5.5.5】创建一个 PackageVerificationState 对象,用于保存应用校验状态,同时将创建的
					// installArgs 作为参数传入,并加入 mPendingVerification 集合中
                    final PackageVerificationState verificationState = new PackageVerificationState(
                            requiredUid, args);

                    mPendingVerification.append(verificationId, verificationState);
					//【7.1.3】如果应用指定了校验者,那么我们要尝试先用指定的校验器校验
                    final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                            receivers, verificationState);

                    DeviceIdleController.LocalService idleController = getDeviceIdleController();
                    final long idleDuration = getVerificationTimeout();

                    /*
                     * If any sufficient verifiers were listed in the package
                     * manifest, attempt to ask them.
                     */
                    if (sufficientVerifiers != null) {
                        final int N = sufficientVerifiers.size();
                        if (N == 0) {
                            Slog.i(TAG, "Additional verifiers required, but none installed.");
                            ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
                        } else {
                            for (int i = 0; i < N; i++) {
                                final ComponentName verifierComponent = sufficientVerifiers.get(i);
                                // 使用前面创建的 verification 意图,再创建一个 intent!
                        		// 指定组件为应用指定的校验器,并发送广播
                                idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                                        verifierComponent.getPackageName(), idleDuration,
                                        verifierUser.getIdentifier(), false, "package verifier");

                                final Intent sufficientIntent = new Intent(verification);
                                sufficientIntent.setComponent(verifierComponent);
                                mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
                            }
                        }
                    }
					//【7.1.4】找到和 mRequiredVerifierPackage(系统指定的默认校验器)匹配的接收者
                    final ComponentName requiredVerifierComponent = matchComponentForVerifier(
                            mRequiredVerifierPackage, receivers);
                    if (ret == PackageManager.INSTALL_SUCCEEDED
                            && mRequiredVerifierPackage != null) {
                        Trace.asyncTraceBegin(
                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
                        /*
                         * Send the intent to the required verification agent,
                         * but only start the verification timeout after the
                         * target BroadcastReceivers have run.
                         */	
                        //【7.1.5】指定目标应用为 mRequiredVerifierPackage 的内部组件
                		// 发送 verification 意图
                        verification.setComponent(requiredVerifierComponent);
                        idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                                mRequiredVerifierPackage, idleDuration,
                                verifierUser.getIdentifier(), false, "package verifier");
                        mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
                                android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
                                new BroadcastReceiver() {
                                    @Override
                                    public void onReceive(Context context, Intent intent) {
                                    	//【7.1.6】当 mRequiredVerifierPackage 接收到广播后,会回调
                                		// 该 BroadcastReceiver 的 onReceive 方法!
                                		//【5.6】此时校验完成,这里会发送 CHECK_PENDING_VERIFICATION 给 PackageHandler
                                		// 携带校验标识符
                                        final Message msg = mHandler
                                                .obtainMessage(CHECK_PENDING_VERIFICATION);
                                        msg.arg1 = verificationId;
                                        mHandler.sendMessageDelayed(msg, getVerificationTimeout());
                                    }
                                }, null, 0, null, null);

                        /*
                         * We don't want the copy to proceed until verification
                         * succeeds, so null out this field.
                         */
                        mArgs = null;
                    }
                } else {
                    /*
                     * No package verification is enabled, so immediately start
                     * the remote call to initiate copy using temporary file.
                     */
                    //【5.7】没有合适的校验器,那么会调用 InstallArgs 的 copyApk 方法
                    ret = args.copyApk(mContainerService, true);
                }
            }

            mRet = ret;
        }

5.1 DefaultContainerService.getMinimalPackageInfo

getMinimalPackageInfo 方法会解析 apk,返回 apk 的解析信息,同时判断空间状态

位置:"./frameworks/base/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java"

java 复制代码
		public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,
                String abiOverride) {
            final Context context = DefaultContainerService.this;
			 //【5.1.1】创建了一个 PackageInfoLite 实例
            PackageInfoLite ret = new PackageInfoLite();
            if (packagePath == null) {
                Slog.i(TAG, "Invalid package file " + packagePath);
                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;	// 该 apk 无效
                return ret;
            }

            final File packageFile = new File(packagePath);
            final PackageParser.PackageLite pkg;
            final long sizeBytes;
            try {
            	//【2】解析 apk,获得其 PackageLite 对象,并计算安装所需空间
                pkg = PackageParser.parsePackageLite(packageFile, 0);
                sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);
            } catch (PackageParserException | IOException e) {
                Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);

                if (!packageFile.exists()) {
                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;	// 该 apk 无效
                } else {
                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;	// 该 apk 无效
                }

                return ret;
            }

            final int recommendedInstallLocation;
            final long token = Binder.clearCallingIdentity();
            try {
            	//【5.1.2】解析安装位置状态信息
                recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
                        pkg.packageName, pkg.installLocation, sizeBytes, flags);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
			//【3】将解析到的参数保存到 PackageInfoLite 中
            ret.packageName = pkg.packageName;
            ret.splitNames = pkg.splitNames;
            ret.versionCode = pkg.versionCode;
            ret.versionCodeMajor = pkg.versionCodeMajor;
            ret.baseRevisionCode = pkg.baseRevisionCode;
            ret.splitRevisionCodes = pkg.splitRevisionCodes;
            ret.installLocation = pkg.installLocation;
            ret.verifiers = pkg.verifiers;
            ret.recommendedInstallLocation = recommendedInstallLocation;
            ret.multiArch = pkg.multiArch;
			//【4】返回该 PackageInfoLite 实例
            return ret;
        }

5.1.1 new PackageInfoLite

PackageInfoLite 用来保存解析到的 apk 的一些信息

位置:./frameworks/base/core/java/android/content/pm/PackageInfoLite.java

java 复制代码
public class PackageInfoLite implements Parcelable {
    /**
     * The name of this package.  From the &lt;manifest&gt; tag's "name"
     * attribute.
     */
    public String packageName;	// 应用包名

    /** Names of any split APKs, ordered by parsed splitName */
    public String[] splitNames;	// split apk 的名字

    /**
     * The android:versionCode of the package.
     * @deprecated Use {@link #getLongVersionCode()} instead, which includes both
     * this and the additional
     * {@link android.R.styleable#AndroidManifest_versionCode versionCodeMajor} attribute.
     */
    @Deprecated
    public int versionCode;	// 版本号

    /**
     * @hide
     * The android:versionCodeMajor of the package.
     */
    public int versionCodeMajor;

    /**
     * Return {@link #versionCode} and {@link #versionCodeMajor} combined together as a
     * single long value.  The {@link #versionCodeMajor} is placed in the upper 32 bits.
     */
    public long getLongVersionCode() {
        return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
    }

    /** Revision code of base APK */
    public int baseRevisionCode;
    /** Revision codes of any split APKs, ordered by parsed splitName */
    public int[] splitRevisionCodes;

    /**
     * The android:multiArch flag from the package manifest. If set,
     * we will extract all native libraries for the given app, not just those
     * from the preferred ABI.
     */
    public boolean multiArch;

    /**
     * Specifies the recommended install location. Can be one of
     * {@link PackageHelper#RECOMMEND_INSTALL_INTERNAL} to install on internal storage,
     * {@link PackageHelper#RECOMMEND_INSTALL_EXTERNAL} to install on external media,
     * {@link PackageHelper#RECOMMEND_FAILED_INSUFFICIENT_STORAGE} for storage errors,
     * or {@link PackageHelper#RECOMMEND_FAILED_INVALID_APK} for parse errors.
     */
    public int recommendedInstallLocation;
    public int installLocation;

    public VerifierInfo[] verifiers;

    public PackageInfoLite() {
    }
    //...
}

这里的 recommendedInstallLocation 可以取下面四个值:

PackageHelper.RECOMMEND_INSTALL_INTERNAL // 内置
PackageHelper.RECOMMEND_INSTALL_EXTERNAL // 外置
PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE // 存储异常
PackageHelper.RECOMMEND_FAILED_INVALID_APK // apk解析异常

5.1.2 PackageHelper.resolveInstallLocation

resolveInstallLocation 方法用于计算一个合适的安装位置给 apk

java 复制代码
    @Deprecated
    public static int resolveInstallLocation(Context context, String packageName,
            int installLocation, long sizeBytes, int installFlags) {
        final SessionParams params = new SessionParams(SessionParams.MODE_INVALID);
        params.appPackageName = packageName;
        params.installLocation = installLocation;
        params.sizeBytes = sizeBytes;
        params.installFlags = installFlags;
        try {
            return resolveInstallLocation(context, params);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * Given a requested {@link PackageInfo#installLocation} and calculated
     * install size, pick the actual location to install the app.
     */
    public static int resolveInstallLocation(Context context, SessionParams params)
            throws IOException {
        //【1】如果该应用已经安装了,那么我们获得上一次安装后的信息
        ApplicationInfo existingInfo = null;
        try {
            existingInfo = context.getPackageManager().getApplicationInfo(params.appPackageName,
                    PackageManager.MATCH_ANY_USER);
        } catch (NameNotFoundException ignored) {
        }

        final int prefer;
        final boolean checkBoth;
        boolean ephemeral = false;
        //【2】根据安装参数 installFlags,来选择合适的安装位置,按照优先级依次解析
        if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
        	//【2.1】如果指定了 PackageManager.INSTALL_EPHEMERAL,优先内置
            prefer = RECOMMEND_INSTALL_INTERNAL;
            ephemeral = true;	// 表示短暂安装
            checkBoth = false;
        } else if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
        	//【2.2】如果指定了 PackageManager.INSTALL_INTERNAL,优先内置
            prefer = RECOMMEND_INSTALL_INTERNAL;
            checkBoth = false;
        } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
        	//【2.3】如果指定了 PackageManager.INSTALL_EXTERNAL,优先外置
            prefer = RECOMMEND_INSTALL_EXTERNAL;
            checkBoth = false;
        } else if (params.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
        	//【2.4】如果指定了 PackageManager.INSTALL_LOCATION_INTERNAL_ONLY,优先内置
            prefer = RECOMMEND_INSTALL_INTERNAL;
            checkBoth = false;
        } else if (params.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
        	//【2.5】如果指定了 PackageManager.INSTALL_LOCATION_PREFER_EXTERNAL,优先外置
            prefer = RECOMMEND_INSTALL_EXTERNAL;
            checkBoth = true;
        } else if (params.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
            // When app is already installed, prefer same medium
            //【2.6】如果指定了 PackageManager.INSTALL_LOCATION_AUTO,那么我们自动调整
            if (existingInfo != null) {
                // TODO: distinguish if this is external ASEC
                //【2.6.1】如果之前已经安装过该应用,那么就和之前安装的位置保持一致
                if ((existingInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
                    prefer = RECOMMEND_INSTALL_EXTERNAL;
                } else {
                    prefer = RECOMMEND_INSTALL_INTERNAL;
                }
            } else {
            	 //【2.6.2】否则,自动安装到内置
                prefer = RECOMMEND_INSTALL_INTERNAL;
            }
            checkBoth = true;
        } else {
        	//【2.7】其他情况,默认是内置
            prefer = RECOMMEND_INSTALL_INTERNAL;
            checkBoth = false;
        }
		//【3】再次校验内置和外置是否合适
        boolean fitsOnInternal = false;
        if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) {
            fitsOnInternal = fitsOnInternal(context, params);
        }

        boolean fitsOnExternal = false;
        if (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL) {
            fitsOnExternal = fitsOnExternal(context, params);
        }
		//【4】最后,返回合适的安装位置
        if (prefer == RECOMMEND_INSTALL_INTERNAL) {
            // The ephemeral case will either fit and return EPHEMERAL, or will not fit
            // and will fall through to return INSUFFICIENT_STORAGE
            //【4.1】如果优先安装到内置,且内置存储是合适的,根据是否是 ephemeral 返回不同的值
            if (fitsOnInternal) {
                return (ephemeral)
                        ? PackageHelper.RECOMMEND_INSTALL_EPHEMERAL
                        : PackageHelper.RECOMMEND_INSTALL_INTERNAL;
            }
        } else if (prefer == RECOMMEND_INSTALL_EXTERNAL) {
        	//【4.2】如果优先安装到外置,且外置存储是合适的,返回结果
            if (fitsOnExternal) {
                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
            }
        }
		//【4.3】其他情况
        if (checkBoth) {
            if (fitsOnInternal) {
                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
            } else if (fitsOnExternal) {
                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
            }
        }
		 //【5】异常情况,返回 PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE
        return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
    }

5.2 PackageManagerS.installLocationPolicy

PackageInfoLite pkgLite 保存了本次要安装的应用的信息

installLocationPolicy 方法会对降级安装和替换安装做一个校验和判断

java 复制代码
        private int installLocationPolicy(PackageInfoLite pkgLite) {
            String packageName = pkgLite.packageName;
            int installLocation = pkgLite.installLocation;
            boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
            // reader
            synchronized (mPackages) {
                // Currently installed package which the new package is attempting to replace or
                // null if no such package is installed.	//【1】如果该应用已经安装过的话,那就获得上次安装后的解析信息
                PackageParser.Package installedPkg = mPackages.get(packageName);
                // Package which currently owns the data which the new package will own if installed.
                // If an app is unstalled while keeping data (e.g., adb uninstall -k), installedPkg
                // will be null whereas dataOwnerPkg will contain information about the package
                // which was uninstalled while keeping its data.
                // 下面这段代码主要是处理卸载但是保留了数据的情况,比如 adb uninstall -k
                PackageParser.Package dataOwnerPkg = installedPkg;
                if (dataOwnerPkg  == null) {
                    PackageSetting ps = mSettings.mPackages.get(packageName);
                    if (ps != null) {
                        dataOwnerPkg = ps.pkg;
                    }
                }
				//【2】如果 dataOwnerPkg 不为 nulkl,说明之前已经安装了
                if (dataOwnerPkg != null) {
                    // If installed, the package will get access to data left on the device by its
                    // predecessor. As a security measure, this is permited only if this is not a
                    // version downgrade or if the predecessor package is marked as debuggable and
                    // a downgrade is explicitly requested.
                    //
                    // On debuggable platform builds, downgrades are permitted even for
                    // non-debuggable packages to make testing easier. Debuggable platform builds do
                    // not offer security guarantees and thus it's OK to disable some security
                    // mechanisms to make debugging/testing easier on those builds. However, even on
                    // debuggable builds downgrades of packages are permitted only if requested via
                    // installFlags. This is because we aim to keep the behavior of debuggable
                    // platform builds as close as possible to the behavior of non-debuggable
                    // platform builds.
                    //【2.1】如果安装标志位设置了 INSTALL_ALLOW_DOWNGRADE,表示允许降级安装
                    final boolean downgradeRequested =
                            (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0;
                    //【2.2】判断应用是否允许 debug
                    final boolean packageDebuggable =
                                (dataOwnerPkg.applicationInfo.flags
                                        & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
                    //【2.3】如果要能够降级安装,必须满足 2 个条件:1、安装标志位设置了 allow downgrade
                    // 2、系统允许 debug 或者该应用可以 debug
                    final boolean downgradePermitted =
                            (downgradeRequested) && ((Build.IS_DEBUGGABLE) || (packageDebuggable));
                    if (!downgradePermitted) {
                        try {
                        	//【5.2.1】如果,安装不允许降级,那就需要做检查
                            checkDowngrade(dataOwnerPkg, pkgLite);
                        } catch (PackageManagerException e) {
                            Slog.w(TAG, "Downgrade detected: " + e.getMessage());
                            return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE;
                        }
                    }
                }
				//【3】接着处理覆盖安装的情况,即相同包名的应用已经存在
                if (installedPkg != null) {
                	//【3.1】覆盖安装的情况,必须携带 PackageManager.INSTALL_REPLACE_EXISTING 安装标志位
                    if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                        // Check for updated system application.
                        if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                        	//【3.1.1】对于系统应用,不能覆盖安装到 sd 卡上
                            if (onSd) {
                                Slog.w(TAG, "Cannot install update to system app on sdcard");
                                return PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION;
                            }
                            return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
                        } else {
                        	//【3.1.2】对于非系统应用,如果是安装到 sdcard,直接返回对应值
                            if (onSd) {
                                // Install flag overrides everything.
                                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
                            }
                            // If current upgrade specifies particular preference
                            //【3.1.2】对于非系统应用,如果只安装到内置,直接返回对应值
                            if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
                                // Application explicitly specified internal.
                                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
                            } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
                                // App explictly prefers external. Let policy decide
                                //【3.1.3】对于非系统应用,如果优先安装到外置,那么安装位置由 
                        		// pkgLite.recommendedInstallLocation 决定
                            } else {
                                // Prefer previous location	//【3.1.4】对于非系统应用,其他情况进入这里
                                if (isExternal(installedPkg)) {
                                    return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
                                }
                                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
                            }
                        }
                    } else {
                        // Invalid install. Return error code	//【3.2】异常情况
                        return PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS;
                    }
                }
            }
            // All the special cases have been taken care of.
            // Return result based on recommended install location.
            //【4】如果上面的条件都不满足,并且指定了在 sdcard,那么就返回 RECOMMEND_INSTALL_EXTERNAL
            if (onSd) {
                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
            }
            //【5】其他情况,均由 pkgLite.recommendedInstallLocation 决定
            return pkgLite.recommendedInstallLocation;
        }

5.3 PackageManagerS.createInstallArgs

其实就是针对不同的安装方式,创建不同的 InstallArgs

java 复制代码
    private InstallArgs createInstallArgs(InstallParams params) {
        if (params.move != null) {
        	//【1】如果是 move package,那么会创建 MoveInstallArgs 实例
            return new MoveInstallArgs(params);
        } else {
	        //【5.3.1】对于一般安装,创建 FileInstallArgs 实例
            return new FileInstallArgs(params);
        }
    }

这里我们先关注一般情况,即创建 FileInstallArgs 实例的情况

5.3.1 new FileInstallArgs - 要安装的 apk

java 复制代码
    class FileInstallArgs extends InstallArgs {
        private File codeFile;
        private File resourceFile;

        // Example topology:
        // /data/app/com.example/base.apk
        // /data/app/com.example/split_foo.apk
        // /data/app/com.example/lib/arm/libfoo.so
        // /data/app/com.example/lib/arm64/libfoo.so
        // /data/app/com.example/dalvik/arm/base.apk@classes.dex

        /** New install */	//【1】安装一个新的 apk
        FileInstallArgs(InstallParams params) {
            super(params.origin, params.move, params.observer, params.installFlags,
                    params.installerPackageName, params.volumeUuid,
                    params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
                    params.grantedRuntimePermissions,
                    params.traceMethod, params.traceCookie, params.signingDetails,
                    params.installReason);
            //【1.1】这里校验了下是否是  Forward Locked 的
            if (isFwdLocked()) {
                throw new IllegalArgumentException("Forward locking only supported in ASEC");
            }
        }

        /** Existing install */		//【2】用于描述已存在的一个安装
        FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
            super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
                    null, null, null, 0, PackageParser.SigningDetails.UNKNOWN,
                    PackageManager.INSTALL_REASON_UNKNOWN);
            this.codeFile = (codePath != null) ? new File(codePath) : null;
            this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
        }
		//...
    }

我们看到 FileInstallArgs 有两个构造器

  • 一参数构造器用于创建安装过程中的 InstallArgs
  • 三参数构造器,用于描述一个已存在的安装,主要用于清除旧的安装,或者作为移动应用的时候的源数据,我们在 pms 开机初始化的过程中就已经看到过了
    当然,这里我们重点关注安装过程

5.4 PackageManagerService.isVerificationEnabled

isVerificationEnabled 用于校验系统是否打开了校验功能

java 复制代码
    private boolean isVerificationEnabled(int userId, int installFlags, int installerUid) {
        if (!DEFAULT_VERIFY_ENABLE) {	//【1】如果默认没有打开校验,false
            return false;
        }
		//【3】判断该用户下是否允许校验应用
        boolean ensureVerifyAppsEnabled = isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS);

        // Check if installing from ADB		//【4】如果安装指定了 INSTALL_FROM_ADB,进入这里
        if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
            // Do not run verification in a test harness environment	//【4.1】test harness environment 不校验
            if (ActivityManager.isRunningInTestHarness()) {
                return false;
            }
            //【4.2】如果同时该用户下能校验应用,返回 true
            if (ensureVerifyAppsEnabled) {
                return true;
            }
            // Check if the developer does not want package verification for ADB installs
            //【4.3】对于 adb install,如果系统属性 PACKAGE_VERIFIER_INCLUDE_ADB 为 0 ,那就不用校验
            if (android.provider.Settings.Global.getInt(mContext.getContentResolver(),
                    android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) == 0) {
                return false;
            }
        } else {	//【2】如果不是INSTALL_FROM_ADB方式的安装,不校验,false
            // only when not installed from ADB, skip verification for instant apps when
            // the installer and verifier are the same.
            if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
                if (mInstantAppInstallerActivity != null
                        && mInstantAppInstallerActivity.packageName.equals(
                                mRequiredVerifierPackage)) {
                    try {
                        mContext.getSystemService(AppOpsManager.class)
                                .checkPackage(installerUid, mRequiredVerifierPackage);
                        if (DEBUG_VERIFY) {
                            Slog.i(TAG, "disable verification for instant app");
                        }
                        return false;
                    } catch (SecurityException ignore) { }
                }
            }
        }
		//【5】如果该用户下能校验应用,返回 true
        if (ensureVerifyAppsEnabled) {
            return true;
        }
		//【6】判断系统属性 PACKAGE_VERIFIER_ENABLE 如果为 0,那就不用校验
        return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
                android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) == 1;
    }

5.5 new PackageVerificationState

PackageVerificationState 用于保存被安装的应用的校验状态信息:

java 复制代码
class PackageVerificationState {
    private final InstallArgs mArgs;	// InstallArgs 实例

    private final SparseBooleanArray mSufficientVerifierUids;

    private final int mRequiredVerifierUid;	// 校验者的 uid

    private boolean mSufficientVerificationComplete;

    private boolean mSufficientVerificationPassed;

    private boolean mRequiredVerificationComplete;

    private boolean mRequiredVerificationPassed;

    private boolean mExtendedTimeout;

    /**
     * Create a new package verification state where {@code requiredVerifierUid}
     * is the user ID for the package that must reply affirmative before things
     * can continue.
     *
     * @param requiredVerifierUid user ID of required package verifier
     * @param args
     */
    public PackageVerificationState(int requiredVerifierUid, InstallArgs args) {
        mRequiredVerifierUid = requiredVerifierUid;
        mArgs = args;
        mSufficientVerifierUids = new SparseBooleanArray();
        mExtendedTimeout = false;	// 表示是否超时
    }
}

六、PackageHandler.doHandleMessage[CHECK_PENDING_VERIFICATION] - 校验完成

java 复制代码
                case CHECK_PENDING_VERIFICATION: {
					//【1】获得校验唯一标识
                    final int verificationId = msg.arg1;
                    //【2】获得本次校验的 PackageVerificationState 实例
                    final PackageVerificationState state = mPendingVerification.get(verificationId);

                    if ((state != null) && !state.timeoutExtended()) {
                    	//【3】获得 InstallArgs 实例
                        final InstallArgs args = state.getInstallArgs();
                        final Uri originUri = Uri.fromFile(args.origin.resolvedFile);

                        Slog.i(TAG, "Verification timed out for " + originUri);
                        //【4】从 mPendingVerification 中移除校验状态对象
                        mPendingVerification.remove(verificationId);

                        int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;

                        final UserHandle user = args.getUser();
                        //【5】处理校验结果
                        if (getDefaultVerificationResponse(user)
                                == PackageManager.VERIFICATION_ALLOW) {
                            //【5.1】校验成功
                            Slog.i(TAG, "Continuing with installation of " + originUri);
                            state.setVerifierResponse(Binder.getCallingUid(),
                                    PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
                            //【5.6.1】发送 Intent.ACTION_PACKAGE_VERIFIED 广播
                            broadcastPackageVerified(verificationId, originUri,
                                    PackageManager.VERIFICATION_ALLOW, user);
                            try {
                            	//【5.6.2】校验成功后,调用 installArgs.copyApk 继续处理
                                ret = args.copyApk(mContainerService, true);
                            } catch (RemoteException e) {
                                Slog.e(TAG, "Could not contact the ContainerService");
                            }
                        } else {
                        	//【5.6.1】校验失败,发送 Intent.ACTION_PACKAGE_VERIFIED 广播
                            broadcastPackageVerified(verificationId, originUri,
                                    PackageManager.VERIFICATION_REJECT, user);
                        }

                        Trace.asyncTraceEnd(
                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
						//【5.7】继续安装
                        processPendingInstall(args, ret);
                        // 安装过程结束,发送 MCS_UNBIND 消息
                        mHandler.sendEmptyMessage(MCS_UNBIND);
                    }
					Slog.d(TAG, "Tuo CHECK_PENDING_VERIFICATION end");
                    break;
                }

这里我们通过 getDefaultVerificationResponse 方法返回校验结果:

java 复制代码
    /**
     * Get the default verification agent response code.
     *
     * @return default verification response code
     */
    private int getDefaultVerificationResponse(UserHandle user) {
        if (sUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
            return PackageManager.VERIFICATION_REJECT;
        }
        return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
                android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
                DEFAULT_VERIFICATION_RESPONSE);
    }

默认返回的是 PackageManager.VERIFICATION_ALLOW,比如在校验超时的情况下

6.1 PackageManagerS.broadcastPackageVerified

java 复制代码
    private void broadcastPackageVerified(int verificationId, Uri packageUri,
            int verificationCode, UserHandle user) {
        final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
        intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
        intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode);

        mContext.sendBroadcastAsUser(intent, user,
                android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
    }

6.2 FileInstallArgs.(do)copyApk

java 复制代码
        int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
            try {
                return doCopyApk(imcs, temp);
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        }

copyApk 调用了 doCopyApk 方法:

java 复制代码
        private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
        	//【1】如果 origin.staged 为 true,那么说明应用已经 copy 到目标目录了,
    		// 那就直接返回 PackageManager.INSTALL_SUCCEEDED
            if (origin.staged) {
                if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
                //【1.1】设置 FileInstallArgs 的 codeFile 属性
                codeFile = origin.file;
                resourceFile = origin.file;
                return PackageManager.INSTALL_SUCCEEDED;
            }
			//【2】如果 origin.staged 为 false,说明应用没有拷贝到目标目录
            try {
                final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
                //【5.6.2.1】获得要拷贝的目标目录
                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;
            }
			//【3】回调接口
            final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
                @Override
                public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
                    if (!FileUtils.isValidExtFilename(name)) {
                        throw new IllegalArgumentException("Invalid filename: " + name);
                    }
                    try {
                    	//【3.1】访问 codeFile 目录下的 name 文件,设置权限,并返回其文件描述符
                        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;
            //【6.2.2】将应用程序拷贝到目标目录
            ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
            if (ret != PackageManager.INSTALL_SUCCEEDED) {
                Slog.e(TAG, "Failed to copy package");
                return ret;
            }
			//【4】解压本地 lib 库文件
            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;
        }

根据前面创建 OriginInfo 时知道:

java 复制代码
if (stagedDir != null) {
    origin = OriginInfo.fromStagedFile(stagedDir);
} else {
    origin = OriginInfo.fromStagedContainer(stagedCid);
}

通过 adb 安装时,安装到内置存储,会调用 OriginInfo.fromStagedFile 方法,此时 OriginInfo.staged 为 true,安装到外置存储时, OriginInfo.staged 也会为 true

这是因为在进行 adb install 过程中时,我们通过 Session,已经拷贝到目标目录了:/data/app/vml[sessionId].tmp/,所以这里 doCopyApk 无需在继续进行下去

对于其他的安装方式,OriginInfo.staged 为 false 的,那么会进入 doCopyApk 的下一步

6.2.1 PackageInstallerService.allocateStageDirLegacy

java 复制代码
    @Deprecated
    public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
        synchronized (mSessions) {
            try {
            	//【3.1.2】分配一个 sessionId,保存到 mLegacySessions 中
                final int sessionId = allocateSessionIdLocked();
                mLegacySessions.put(sessionId, true);
                //【3.1.2】创建目标目录
                final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
                //【2】创建目录,设置权限
                prepareStageDir(stageDir);
                return stageDir;
            } catch (IllegalStateException e) {
                throw new IOException(e);
            }
        }
    }

6.2.2 DefaultContainerService.copyPackage(Inner)

java 复制代码
        public int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {
            if (packagePath == null || target == null) {
                return PackageManager.INSTALL_FAILED_INVALID_URI;
            }

            PackageLite pkg = null;
            try {
                final File packageFile = new File(packagePath);
                //【1】解析应用
                pkg = PackageParser.parsePackageLite(packageFile, 0);
                //【2】继续处理 copyPackageInner
                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 {
        //【1】对 base apk 和 split apk 分别执行 copy
        copyFile(pkg.baseCodePath, target, "base.apk");
        if (!ArrayUtils.isEmpty(pkg.splitNames)) {
            for (int i = 0; i < pkg.splitNames.length; i++) {
                copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk");
            }
        }

        return PackageManager.INSTALL_SUCCEEDED;
    }
//最终,调用了 copyFile 执行 copy
    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(
                    target.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE));
            FileUtils.copy(in, out);
        } finally {
            IoUtils.closeQuietly(out);
            IoUtils.closeQuietly(in);
        }
    }

七、PackageManagerS.processPendingInstall

processPendingInstall 用于继续安装:

java 复制代码
    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 returned
                //【5.7.1】创建 PackageInstalledInfo 实例,封装安装结果
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.setReturnCode(currentStatus);	// 保存当前的返回码
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = null;
                //【1】如果返回码为 PackageManager.INSTALL_SUCCEEDED
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                	//【×5.7.2】安装前处理
                    args.doPreInstall(res.returnCode);
                    synchronized (mInstallLock) {
                    	//【×5.7.3】执行安装
                        installPackageTracedLI(args, res);
                    }
                    //【×5.7.4】安装后处理
                    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.
                //【2】判断是否执行备份,要备份必须满足 3 个条件
                // 1、安装正常;2、本次安装并不是更新操作!3、应用允许备份
                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.
                //【3】计算本次安装的 token
                int token;
                if (mNextInstallToken < 0) mNextInstallToken = 1;
                token = mNextInstallToken++;
				//【*5.7.5】创建一个 PostInstallData 对象,并将其加入 mRunningInstalls 中
                PostInstallData data = new PostInstallData(args, res);
                mRunningInstalls.put(token, data);
                if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);

                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.
                    //【4】如果安装成功,并且需要备份,那就获得 BackupManager 执行备份
                    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/22388012
                            if (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;
                    }
                }
				//【5】如果备份失败或者不需要备份,那就进入这个阶段
                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);
                }
            }
        });
    }

7.1 new PackageInstalledInfo

PackageInstalledInfo 用于保存该应用的安装结果信息

java 复制代码
    static class PackageInstalledInfo {
        String name;
        int uid;
        // The set of users that originally had this package installed.
        int[] origUsers;	// 该 pacakge 之前安装后所属的 user
        // The set of users that now have this package installed.
        int[] newUsers;		// 该 pacakge 现在安装后所属的 user
        PackageParser.Package pkg;
        int returnCode;		// 返回码
        String returnMsg;
        String installerPackageName;
        PackageRemovedInfo removedInfo;	//【7.1.1】用于封装要移除的 apk 的信息
        ArrayMap<String, PackageInstalledInfo> addedChildPackages;	// split apk 的安装结果信息
		
		//...
		
        // In some error cases we want to convey more info back to the observer
        String origPackage;
        String origPermission;
    }

7.1.1 new PackageRemovedInfo

封装要移除的 apk 的信息:

java 复制代码
    static class PackageRemovedInfo {
        final PackageSender packageSender;
        String removedPackage;
        String installerPackageName;
        int uid = -1;
        int removedAppId = -1;
        int[] origUsers;
        int[] removedUsers = null;
        int[] broadcastUsers = null;
        int[] instantUserIds = null;
        SparseArray<Integer> installReasons;
        boolean isRemovedPackageSystemUpdate = false;
        boolean isUpdate;
        boolean dataRemoved;
        boolean removedForAllUsers;
        boolean isStaticSharedLib;
        // Clean up resources deleted packages.	//【1】InstallArgs 用于清除 apk 的相关数据,后面会看到
        InstallArgs args = null;
        ArrayMap<String, PackageRemovedInfo> removedChildPackages;
        ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
		//...
	}

7.2 FileInstallArgs.doPreInstall

安装前执行清理操作,正常情况不会触发

java 复制代码
		int doPreInstall(int status) {
			//【1】如果安装前的状态不是 PackageManager.INSTALL_SUCCEEDED
			if (status != PackageManager.INSTALL_SUCCEEDED) {
			//【5.7.2.1】执行清理操作
				cleanUp();
			}
			return status;
		}

7.2.1 FileInstallArgs.cleanUp(ResourcesLI)

清理操作

java 复制代码
        private boolean cleanUp() {
            if (codeFile == null || !codeFile.exists()) {
                return false;
            }
			//【1】删除目标目录下的所有文件
            removeCodePathLI(codeFile);

            if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
                resourceFile.delete();
            }

            return true;
        }
//可以看到,最后调用了 removeCodePathLI 方法
    void removeCodePathLI(File codePath) {
        if (codePath.isDirectory()) {
            try {
                mInstaller.rmPackageDir(codePath.getAbsolutePath());
            } catch (InstallerException e) {
                Slog.w(TAG, "Failed to remove code path", e);
            }
        } else {
            codePath.delete();
        }
    }

7.3 PackageManagerS.installPackageTracedLI - 核心安装入口

java 复制代码
    private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
            //【1】调用了 installPackageLI 方法
            installPackageLI(args, res);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }
//这里调用了 installPackageLI 方法:
	private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
		//【1】获得安装时传入的参数和标志位
        final int installFlags = args.installFlags;
        final String installerPackageName = args.installerPackageName;
        final String volumeUuid = args.volumeUuid;
        final File tmpPackageFile = new File(args.getCodePath());
        final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
        final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
                || (args.volumeUuid != null));
        final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
        final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
        final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0);
        final boolean virtualPreload =
                ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
        boolean replace = false;
        //【2】重新设置扫描参数
        @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
        if (args.move != null) {
            // moving a complete application; perform an initial scan on the new install location
            //【2.1】如果 args.move 不为 null,表示正在移动一个 app,我们会对其进行一个初始化的扫描
        	// 增加 SCAN_INITIAL 位
            scanFlags |= SCAN_INITIAL;
        }
        if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
        	//【2.2】如果安装参数指定了 INSTALL_DONT_KILL_APP,那么增加 SCAN_DONT_KILL_APP 位
            scanFlags |= SCAN_DONT_KILL_APP;
        }
        if (instantApp) {
            scanFlags |= SCAN_AS_INSTANT_APP;
        }
        if (fullApp) {
            scanFlags |= SCAN_AS_FULL_APP;
        }
        if (virtualPreload) {
            scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
        }

        // Result object to be returned		//【3】更新结果码
        res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
        res.installerPackageName = installerPackageName;

        if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);

        // Sanity check	//【4】检查 instantApp 是否和 forwardLocked/onExternal 共存,共存则报错
        if (instantApp && (forwardLocked || onExternal)) {
            Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
                    + " external=" + onExternal);
            res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
            return;
        }

        // Retrieve PackageSettings and parse package	//【5】设置解析参数 parseFlags
        @ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
                | PackageParser.PARSE_ENFORCE_CODE
                | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
                | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
                | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
        PackageParser pp = new PackageParser();		//【6】创建解析对象
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setDisplayMetrics(mMetrics);
        pp.setCallback(mPackageParserCallback);

        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
        final PackageParser.Package pkg;
        try {
        	//【*7.3.1】解析 apk,获得其对应的 Package 对象
            pkg = pp.parsePackage(tmpPackageFile, parseFlags);
            DexMetadataHelper.validatePackageDexMetadata(pkg);
        } catch (PackageParserException e) {
            res.setError("Failed parse during installPackageLI", e);
            return;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }

        // Instant apps have several additional install-time checks.
        if (instantApp) {
            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
                Slog.w(TAG,
                        "Instant app package " + pkg.packageName + " does not target at least O");
                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
                        "Instant app package must target at least O");
                return;
            }
            if (pkg.applicationInfo.targetSandboxVersion != 2) {
                Slog.w(TAG, "Instant app package " + pkg.packageName
                        + " does not target targetSandboxVersion 2");
                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
                        "Instant app package must use targetSandboxVersion 2");
                return;
            }
            if (pkg.mSharedUserId != null) {
                Slog.w(TAG, "Instant app package " + pkg.packageName
                        + " may not declare sharedUserId.");
                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
                        "Instant app package may not declare a sharedUserId");
                return;
            }
        }

        if (pkg.applicationInfo.isStaticSharedLibrary()) {
            // Static shared libraries have synthetic package names
            renameStaticSharedLibraryPackage(pkg);

            // No static shared libs on external storage
            if (onExternal) {
                Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
                res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                        "Packages declaring static-shared libs cannot be updated");
                return;
            }
        }

        // If we are installing a clustered package add results for the children
        //【7】如果该应用有子包的话,那么对于每个子包,也会创建安装结果对象
        if (pkg.childPackages != null) {
            synchronized (mPackages) {
                final int childCount = pkg.childPackages.size();
                for (int i = 0; i < childCount; i++) {
                    PackageParser.Package childPkg = pkg.childPackages.get(i);
                    //【*5.7.1】针对子包,创建 PackageInstalledInfo 对象!
	                // 设置返回码,子包包名
                    PackageInstalledInfo childRes = new PackageInstalledInfo();
                    childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                    childRes.pkg = childPkg;
                    childRes.name = childPkg.packageName;
                    //【7.1】获得子包的源 user
                    PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                    if (childPs != null) {
                        childRes.origUsers = childPs.queryInstalledUsers(
                                sUserManager.getUserIds(), true);
                    }
                    //【7.2】如果子包之前被扫描到了(安装过),创建 PackageRemovedInfo 对象
                    if ((mPackages.containsKey(childPkg.packageName))) {
                        childRes.removedInfo = new PackageRemovedInfo(this);
                        childRes.removedInfo.removedPackage = childPkg.packageName;
                        childRes.removedInfo.installerPackageName = childPs.installerPackageName;
                    }
                    if (res.addedChildPackages == null) {
                        res.addedChildPackages = new ArrayMap<>();
                    }
                    //【7.3】将子包的安装结果对象保存到 base apk 的信息中
                    res.addedChildPackages.put(childPkg.packageName, childRes);
                }
            }
        }

        // If package doesn't declare API override, mark that we have an install
        // time CPU ABI override.	// 如果应用没有指定 abi,我们通过安装参数指定
        if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
            pkg.cpuAbiOverride = args.abiOverride;
        }
		// 如果应用指定了 ApplicationInfo.FLAG_TEST_ONLY,那么安装参数也需要指定这个参数
        String pkgName = res.name = pkg.packageName;
        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
            if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
                res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
                return;
            }
        }

        try {
        	//【8】收集证书信息
            // either use what we've been given or parse directly from the APK
            if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
                pkg.setSigningDetails(args.signingDetails);
            } else {
                PackageParser.collectCertificates(pkg, false /* skipVerify */);
            }
        } catch (PackageParserException e) {
            res.setError("Failed collect during installPackageLI", e);
            return;
        }

        if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
                < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
            Slog.w(TAG, "Instant app package " + pkg.packageName
                    + " is not signed with at least APK Signature Scheme v2");
            res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Instant app package must be signed with APK Signature Scheme v2 or greater");
            return;
        }

        // Get rid of all references to package scan path via parser.
        pp = null;
        String oldCodePath = null;
        boolean systemApp = false;
        synchronized (mPackages) {
            // Check if installing already existing package
            //【9】如果安装参数指定了 INSTALL_REPLACE_EXISTING,那么我们要尝试判断是否存在已安装的应用!
        	// 如果存在,那就要 replace
            if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                String oldName = mSettings.getRenamedPackageLPr(pkgName);	// 判断该应用是否重命名过
                if (pkg.mOriginalPackages != null
                        && pkg.mOriginalPackages.contains(oldName)
                        && mPackages.containsKey(oldName)) {
                    // This package is derived from an original package,
                    // and this device has been updating from that original
                    // name.  We must continue using the original name, so
                    // rename the new package here.	
                    //【9.1】如果有源包(系统应用才会有),要命名为源包,replace 为 true
                    pkg.setPackageName(oldName);
                    pkgName = pkg.packageName;
                    replace = true;
                    if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
                            + oldName + " pkgName=" + pkgName);
                } else if (mPackages.containsKey(pkgName)) {
                    // This package, under its official name, already exists
                    // on the device; we should replace it.
                    //【9.2】如果没有源包(系统应用才会有),但是已经有相同包名的应用存在,replace 为 true
                    replace = true;
                    if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
                }

                // Child packages are installed through the parent package
                //【9.2】对于子包,只能通过父包更新,这里不处理子包的 replace
                if (pkg.parentPackage != null) {
                    res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                            "Package " + pkg.packageName + " is child of package "
                                    + pkg.parentPackage.parentPackage + ". Child packages "
                                    + "can be updated only through the parent package.");
                    return;
                }
				//【9.3】如果需要替换已存在的 apk,那么需要做 sdk 的校验!
            	// 如果旧应用支持运行时,不允许新的应用不支持运行时
                if (replace) {
                    // Prevent apps opting out from runtime permissions
                    PackageParser.Package oldPackage = mPackages.get(pkgName);
                    final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
                    final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
                    if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
                            && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                        res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
                                "Package " + pkg.packageName + " new target SDK " + newTargetSdk
                                        + " doesn't support runtime permissions but the old"
                                        + " target SDK " + oldTargetSdk + " does.");
                        return;
                    }
                    // Prevent persistent apps from being updated	//【9.4】如果旧包也是子包,也不安装
                    if ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) {
                        res.setError(PackageManager.INSTALL_FAILED_INVALID_APK,
                                "Package " + oldPackage.packageName + " is a persistent app. "
                                        + "Persistent apps are not updateable.");
                        return;
                    }
                    // Prevent installing of child packages
                    //【9.4】如果旧包也是子包,也不安装
                    if (oldPackage.parentPackage != null) {
                        res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                                "Package " + pkg.packageName + " is child of package "
                                        + oldPackage.parentPackage + ". Child packages "
                                        + "can be updated only through the parent package.");
                        return;
                    }
                }
            }
			//【10】获得上一次的安装数据
            PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);

                // Static shared libs have same package with different versions where
                // we internally use a synthetic package name to allow multiple versions
                // of the same package, therefore we need to compare signatures against
                // the package setting for the latest library version.
                PackageSetting signatureCheckPs = ps;
                if (pkg.applicationInfo.isStaticSharedLibrary()) {
                    SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
                    if (libraryEntry != null) {
                        signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
                    }
                }

                // Quick sanity check that we're signed correctly if updating;
                // we'll check this again later when scanning, but we want to
                // bail early here before tripping over redefined permissions.
                //【10.1】如果安装过旧版本,那就要校验签名!
	            //【×3.7.2】shouldCheckUpgradeKeySetLP 用于判断是否检查签名更新;
                final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
                	//【×3.7.3】checkUpgradeKeySetLP 用于检查签名更新;
                    if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
                        res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                                + pkg.packageName + " upgrade keys do not match the "
                                + "previously installed version");
                        return;
                    }
                } else {
                    try {
                        final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
                        final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
                        // We don't care about disabledPkgSetting on install for now.
                        //【×3.7.4】校验签名,如果签名不相等,那就禁止安装
                        final boolean compatMatch = verifySignatures(
                                signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
                                compareRecover);
                        // The new KeySets will be re-added later in the scanning process.
                        if (compatMatch) {
                            synchronized (mPackages) {
                                ksms.removeAppKeySetDataLPw(pkg.packageName);
                            }
                        }
                    } catch (PackageManagerException e) {
                        res.setError(e.error, e.getMessage());
                        return;
                    }
                }
				//【10.2】获得旧的 apk 的路径,判断旧应用是否是系统应用
                oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
                if (ps.pkg != null && ps.pkg.applicationInfo != null) {
                    systemApp = (ps.pkg.applicationInfo.flags &
                            ApplicationInfo.FLAG_SYSTEM) != 0;
                }
                res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
            }
			//【11】检查权限是否被重新定义,如果重新定义,那就要校验权限
            int N = pkg.permissions.size();
            for (int i = N-1; i >= 0; i--) {
            	//【11.1】获得该应用定义的权限
                final PackageParser.Permission perm = pkg.permissions.get(i);
                //【11.2】尝试从系统中获得该权限已有的信息
                final BasePermission bp =
                        (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);

                // Don't allow anyone but the system to define ephemeral permissions.
                if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
                        && !systemApp) {
                    Slog.w(TAG, "Non-System package " + pkg.packageName
                            + " attempting to delcare ephemeral permission "
                            + perm.info.name + "; Removing ephemeral.");
                    perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
                }

                // Check whether the newly-scanned package wants to define an already-defined perm
                if (bp != null) {
                    // If the defining package is signed with our cert, it's okay.  This
                    // also includes the "updating the same package" case, of course.
                    // "updating same package" could also involve key-rotation.
                    //【11.3】如果该权限已经被定义过了,那就要校验下签名
                    final boolean sigsOk;
                    final String sourcePackageName = bp.getSourcePackageName();
                    final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
                    final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                    if (sourcePackageName.equals(pkg.packageName)
                            && (ksms.shouldCheckUpgradeKeySetLocked(
                                    sourcePackageSetting, scanFlags))) {
                        //【11.3.1】检查签名更新
                        sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
                    } else {	//【11.3.2】如果不检查签名更新,那就直接比较签名
                        // in the event of signing certificate rotation, we need to see if the
                        // package's certificate has rotated from the current one, or if it is an
                        // older certificate with which the current is ok with sharing permissions
                        if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
                                        pkg.mSigningDetails,
                                        PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
                            sigsOk = true;
                        } else if (pkg.mSigningDetails.checkCapability(
                                        sourcePackageSetting.signatures.mSigningDetails,
                                        PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {

                            // the scanned package checks out, has signing certificate rotation
                            // history, and is newer; bring it over
                            sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;
                            sigsOk = true;
                        } else {
                            sigsOk = false;
                        }
                    }
                    //【11.4】如果签名发生了变化
                    if (!sigsOk) {
                        // If the owning package is the system itself, we log but allow
                        // install to proceed; we fail the install on all other permission
                        // redefinitions.
                        if (!sourcePackageName.equals("android")) {
                        	//【11.4.1】如果权限的定义者不是系统,那么不允许重新定义,同时不允许继续安装
                            res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
                                    + pkg.packageName + " attempting to redeclare permission "
                                    + perm.info.name + " already owned by " + sourcePackageName);
                            res.origPermission = perm.info.name;
                            res.origPackage = sourcePackageName;
                            return;
                        } else {
                            Slog.w(TAG, "Package " + pkg.packageName
                                    + " attempting to redeclare system permission "
                                    + perm.info.name + "; ignoring new declaration");
                            pkg.permissions.remove(i);
                        }
                    } else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
                    	//【11.4.2】如果权限的定义不是系统,那么允许安装,但是会忽视掉新的定义
                        // Prevent apps to change protection level to dangerous from any other
                        // type as this would allow a privilege escalation where an app adds a
                        // normal/signature permission in other app's group and later redefines
                        // it as dangerous leading to the group auto-grant.
                        if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
                                == PermissionInfo.PROTECTION_DANGEROUS) {
                            if (bp != null && !bp.isRuntime()) {
                                Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
                                        + "non-runtime permission " + perm.info.name
                                        + " to runtime; keeping old protection level");
                                perm.info.protectionLevel = bp.getProtectionLevel();
                            }
                        }
                    }
                }
            }
        }
		//【12】如果覆盖更新的是系统应用,要针对安装位置做判断!
    	// 新的 apk 不能是 onExternal / ephemeral
        if (systemApp) {
            if (onExternal) {
                // Abort update; system app can't be replaced with app on sdcard
                res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                        "Cannot install updates to system apps on sdcard");
                return;
            } else if (instantApp) {
                // Abort update; system app can't be replaced with an instant app
                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
                        "Cannot update a system app with an instant app");
                return;
            }
        }
		//【13】根据安装参数做不同的处理
        if (args.move != null) {
            // We did an in-place move, so dex is ready to roll
            //【13.1】如果是 move package,进入这里
            // 设置以下标签,无需做 odex,我们需要已有的移动过去即可
            scanFlags |= SCAN_NO_DEX;
            scanFlags |= SCAN_MOVE;

            synchronized (mPackages) {
                final PackageSetting ps = mSettings.mPackages.get(pkgName);
                if (ps == null) {
                    res.setError(INSTALL_FAILED_INTERNAL_ERROR,
                            "Missing settings for moved package " + pkgName);
                }

                // We moved the entire application as-is, so bring over the
                // previously derived ABI information.	//【13.1.1】对于 abi,和移动前的保持一致
                pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
                pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
            }

        } else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
            // Enable SCAN_NO_DEX flag to skip dexopt at a later stage
            //【13.2】如果不是 forward lock 模式安装且没有安装到外置存储上,进入这里
            // 扫描参数设置 SCAN_NO_DEX,意味着后面不做 odex,因为这里会做
            scanFlags |= SCAN_NO_DEX;

            try {
                String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
                    args.abiOverride : pkg.cpuAbiOverride);
                final boolean extractNativeLibs = !pkg.isLibrary();
                derivePackageAbi(pkg, abiOverride, extractNativeLibs);
            } catch (PackageManagerException pme) {
                Slog.e(TAG, "Error deriving application ABI", pme);
                res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
                return;
            }

            // Shared libraries for the package need to be updated.
            //【13.2.1】更新共享库文件
            synchronized (mPackages) {
                try {
                    updateSharedLibrariesLPr(pkg, null);
                } catch (PackageManagerException e) {
                    Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
                }
            }
        }
		//【×5.7.3.5】重命名文件目录,此时文件目录由 /data/app/tmpl[SessionId].tmp 变为 /data/app/packageName-X
    	// 如果 X 存在,那么会 X + 1
        if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
            res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
            return;
        }

        if (PackageManagerServiceUtils.isApkVerityEnabled()) {
            String apkPath = null;
            synchronized (mPackages) {
                // Note that if the attacker managed to skip verify setup, for example by tampering
                // with the package settings, upon reboot we will do full apk verification when
                // verity is not detected.
                final PackageSetting ps = mSettings.mPackages.get(pkgName);
                if (ps != null && ps.isPrivileged()) {
                    apkPath = pkg.baseCodePath;
                }
            }

            if (apkPath != null) {
                final VerityUtils.SetupResult result =
                        VerityUtils.generateApkVeritySetupData(apkPath);
                if (result.isOk()) {
                    if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath);
                    FileDescriptor fd = result.getUnownedFileDescriptor();
                    try {
                        final byte[] signedRootHash = VerityUtils.generateFsverityRootHash(apkPath);
                        mInstaller.installApkVerity(apkPath, fd, result.getContentSize());
                        mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);
                    } catch (InstallerException | IOException | DigestException |
                             NoSuchAlgorithmException e) {
                        res.setError(INSTALL_FAILED_INTERNAL_ERROR,
                                "Failed to set up verity: " + e);
                        return;
                    } finally {
                        IoUtils.closeQuietly(fd);
                    }
                } else if (result.isFailed()) {
                    res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Failed to generate verity");
                    return;
                } else {
                    // Do nothing if verity is skipped. Will fall back to full apk verification on
                    // reboot.
                }
            }
        }
		//【*7.3.6】开始 intentFilter 校验
        if (!instantApp) {
            startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
        } else {
            if (DEBUG_DOMAIN_VERIFICATION) {
                Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
            }
        }
		//【*7.3.7】冻结应用
        try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
                "installPackageLI")) {
            if (replace) {
                if (pkg.applicationInfo.isStaticSharedLibrary()) {
                    // Static libs have a synthetic package name containing the version
                    // and cannot be updated as an update would get a new package name,
                    // unless this is the exact same version code which is useful for
                    // development.
                    PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
                    if (existingPkg != null &&
                            existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
                        res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
                                + "static-shared libs cannot be updated");
                        return;
                    }
                }
                //【*6】如果是覆盖安装,进入这里
                replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
                        installerPackageName, res, args.installReason);
            } else {
            	//【*7】如果是全新安装,进入这里
                installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                        args.user, installerPackageName, volumeUuid, res, args.installReason);
            }
        }

        // Prepare the application profiles for the new code paths.
        // This needs to be done before invoking dexopt so that any install-time profile
        // can be used for optimizations.
        mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier()));

        // Check whether we need to dexopt the app.
        //
        // NOTE: it is IMPORTANT to call dexopt:
        //   - after doRename which will sync the package data from PackageParser.Package and its
        //     corresponding ApplicationInfo.
        //   - after installNewPackageLIF or replacePackageLIF which will update result with the
        //     uid of the application (pkg.applicationInfo.uid).
        //     This update happens in place!
        //
        // We only need to dexopt if the package meets ALL of the following conditions:
        //   1) it is not forward locked.
        //   2) it is not on on an external ASEC container.
        //   3) it is not an instant app or if it is then dexopt is enabled via gservices.
        //   4) it is not debuggable.
        //
        // Note that we do not dexopt instant apps by default. dexopt can take some time to
        // complete, so we skip this step during installation. Instead, we'll take extra time
        // the first time the instant app starts. It's preferred to do it this way to provide
        // continuous progress to the useur instead of mysteriously blocking somewhere in the
        // middle of running an instant app. The default behaviour can be overridden
        // via gservices.
        final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)
                && !forwardLocked
                && !pkg.applicationInfo.isExternalAsec()
                && (!instantApp || Global.getInt(mContext.getContentResolver(),
                Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
                && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
		//【13.2.2】执行 odex 优化
        if (performDexopt) {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
            // Do not run PackageDexOptimizer through the local performDexOpt
            // method because `pkg` may not be in `mPackages` yet.
            //
            // Also, don't fail application installs if the dexopt step fails.
            DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
                    REASON_INSTALL,
                    DexoptOptions.DEXOPT_BOOT_COMPLETE |
                    DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
            mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
                    null /* instructionSets */,
                    getOrCreateCompilerPackageStats(pkg),
                    mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
                    dexoptOptions);
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }

        // Notify BackgroundDexOptService that the package has been changed.
        // If this is an update of a package which used to fail to compile,
        // BackgroundDexOptService will remove it from its blacklist.
        // TODO: Layering violation
        //【13.2.3】将该应用从 odex fail list 中删除
        BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
		//【14】为本次安装的 apk 更新目标用户信息
        synchronized (mPackages) {
            final PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
                ps.setUpdateAvailable(false /*updateAvailable*/);
            }

            final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
            for (int i = 0; i < childCount; i++) {
                PackageParser.Package childPkg = pkg.childPackages.get(i);
                PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                if (childPs != null) {
                    childRes.newUsers = childPs.queryInstalledUsers(
                            sUserManager.getUserIds(), true);
                }
            }

            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                updateSequenceNumberLP(ps, res.newUsers);
                updateInstantAppInstallerLocked(pkgName);
            }
        }
    }

7.3.1 PackageParser.parsePackage

PackageParser.parsePackage 其实我们在 PMS 启动扫描的过程中已经分析过了,这里我们重点关注其对 installFlags 的处理

java 复制代码
    public boolean shouldCheckUpgradeKeySetLocked(PackageSettingBase oldPs, int scanFlags) {
	      //【1】以下情况无需检查签名更新:
	      // 1、本次是全新安装;2、扫描设置了 SCAN_INITIAL(move pkg);3、本次是覆盖安装,但是应用是 sharedUser 的
	      // 4、应用不使用 upgradeKeySets
        // Can't rotate keys during boot or if sharedUser.
        if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
                || !oldPs.keySetData.isUsingUpgradeKeySets()) {
            return false;
        }
        // app is using upgradeKeySets; make sure all are valid
        //【2】如果应用是覆盖安装,且不是 move pkg,且不是共享 uid 的,且使用 upgradeKeySets,那么就要检查
			 // upgradeKeySets 有效性,只有有效的 upgradeKeySets 才能检查更新
        long[] upgradeKeySets = oldPs.keySetData.getUpgradeKeySets();
        for (int i = 0; i < upgradeKeySets.length; i++) {
        		 //【2.1】判断 upgradeKeySets 是否有效
            if (!isIdValidKeySetId(upgradeKeySets[i])) {
                Slog.wtf(TAG, "Package "
                         + (oldPs.name != null ? oldPs.name : "<null>")
                         + " contains upgrade-key-set reference to unknown key-set: "
                         + upgradeKeySets[i]
                         + " reverting to signatures check.");
                return false;
            }
        }
        return true;
    }

7.3.3 checkUpgradeKeySetLP

进行签名更新检查:

java 复制代码
    public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS,
            PackageParser.Package newPkg) {
        //【1】检查 key set 更新,更新有效的前提是新的 apk 持有的 keyset 至少包含旧应用的 keyset
        // Upgrade keysets are being used.  Determine if new package has a superset of the
        // required keys.
        long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
        for (int i = 0; i < upgradeKeySets.length; i++) {
            Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
            if (upgradeSet != null && newPkg.mSigningDetails.publicKeys.containsAll(upgradeSet)) {
                return true;
            }
        }
        return false;
    }

7.3.4 verifySignaturesLP

校验签名:

java 复制代码
    public static boolean verifySignatures(PackageSetting pkgSetting,
            PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures,
            boolean compareCompat, boolean compareRecover)
            throws PackageManagerException {
        final String packageName = pkgSetting.name;
        boolean compatMatch = false;
        if (pkgSetting.signatures.mSigningDetails.signatures != null) {

            // Already existing package. Make sure signatures match
            boolean match = parsedSignatures.checkCapability(
                    pkgSetting.signatures.mSigningDetails,
                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
                            || pkgSetting.signatures.mSigningDetails.checkCapability(
                                    parsedSignatures,
                                    PackageParser.SigningDetails.CertCapabilities.ROLLBACK);
            if (!match && compareCompat) {
                match = matchSignaturesCompat(packageName, pkgSetting.signatures,
                        parsedSignatures);
                compatMatch = match;
            }
            if (!match && compareRecover) {
                match = matchSignaturesRecover(
                        packageName,
                        pkgSetting.signatures.mSigningDetails,
                        parsedSignatures,
                        PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
                                || matchSignaturesRecover(
                                        packageName,
                                        parsedSignatures,
                                        pkgSetting.signatures.mSigningDetails,
                                        PackageParser.SigningDetails.CertCapabilities.ROLLBACK);
            }

            if (!match && isApkVerificationForced(disabledPkgSetting)) {
                match = matchSignatureInSystem(pkgSetting, disabledPkgSetting);
            }

            if (!match) {
                throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                        "Package " + packageName +
                        " signatures do not match previously installed version; ignoring!");
            }
        }
        // Check for shared user signatures
        if (pkgSetting.sharedUser != null
                && pkgSetting.sharedUser.signatures.mSigningDetails
                        != PackageParser.SigningDetails.UNKNOWN) {

            // Already existing package. Make sure signatures match.  In case of signing certificate
            // rotation, the packages with newer certs need to be ok with being sharedUserId with
            // the older ones.  We check to see if either the new package is signed by an older cert
            // with which the current sharedUser is ok, or if it is signed by a newer one, and is ok
            // with being sharedUser with the existing signing cert.
            boolean match =
                    parsedSignatures.checkCapability(
                            pkgSetting.sharedUser.signatures.mSigningDetails,
                            PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)
                    || pkgSetting.sharedUser.signatures.mSigningDetails.checkCapability(
                            parsedSignatures,
                            PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
            if (!match && compareCompat) {
                match = matchSignaturesCompat(
                        packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
            }
            if (!match && compareRecover) {
                match =
                        matchSignaturesRecover(packageName,
                                pkgSetting.sharedUser.signatures.mSigningDetails,
                                parsedSignatures,
                                PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)
                        || matchSignaturesRecover(packageName,
                                parsedSignatures,
                                pkgSetting.sharedUser.signatures.mSigningDetails,
                                PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
                compatMatch |= match;
            }
            if (!match) {
                throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
                        "Package " + packageName
                        + " has no signatures that match those in shared user "
                        + pkgSetting.sharedUser.name + "; ignoring!");
            }
        }
        return compatMatch;
    }

7.3.5 FileInstallArgs.doRename - 重命名临时目录

doRename 重命名文件,之前我们的临时目录为 /data/app/tmpl[SessionId].tmp,这里会将其重命名为 /data/app/packageName-X

java 复制代码
        boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
            if (status != PackageManager.INSTALL_SUCCEEDED) {
                cleanUp();
                return false;
            }
					//【1】获得改名前的临时目录 targetDir 就是 /data/app/tmpl[SessionId].tmp
            final File targetDir = codeFile.getParentFile();
            final File beforeCodeFile = codeFile;
            //【7.3.5.1】获得改名后的目录:/data/app/packageName-X,策略取决为 getNextCodePath
            final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
					
            if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
            try {
                Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
            } catch (ErrnoException e) {
                Slog.w(TAG, "Failed to rename", e);
                return false;
            }
					//【2】恢复默认的安全上下文
            if (!SELinux.restoreconRecursive(afterCodeFile)) {
                Slog.w(TAG, "Failed to restorecon");
                return false;
            }
					//【3】更新 FileInstallArgs 的目录为最终目录
            // Reflect the rename internally
            codeFile = afterCodeFile;
            resourceFile = afterCodeFile;

            // Reflect the rename in scanned details
            try {
                pkg.setCodePath(afterCodeFile.getCanonicalPath());
            } catch (IOException e) {
                Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
                return false;
            }
            //【4】更新扫描到的应用的 Package 中的目录数据
            // 以及 Application 中的数据
            pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
                    afterCodeFile, pkg.baseCodePath));
            pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
                    afterCodeFile, pkg.splitCodePaths));

            // Reflect the rename in app info
            pkg.setApplicationVolumeUuid(pkg.volumeUuid);
            pkg.setApplicationInfoCodePath(pkg.codePath);
            pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
            pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
            pkg.setApplicationInfoResourcePath(pkg.codePath);
            pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
            pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);

            return true;
        }
7.3.5.1 getNextCodePath

getNextCodePath 方法用于获得最终的目录

java 复制代码
    private File getNextCodePath(File targetDir, String packageName) {
        File result;
        SecureRandom random = new SecureRandom();
        byte[] bytes = new byte[16];
        do {
            //【1】最终目录为 /data/app/packageName-X(X=1,2,3...)
	          // suffix 从 1 开始,如果 suffix 已存在,那就 +1
            random.nextBytes(bytes);
            String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
            result = new File(targetDir, packageName + "-" + suffix);
        } while (result.exists());
        return result;
    }

7.3.7 freezePackageForInstall - 冻结应用

该方法用于冻结应用:

java 复制代码
    public PackageFreezer freezePackageForInstall(String packageName, int installFlags,
            String killReason) {
        return freezePackageForInstall(packageName, UserHandle.USER_ALL, installFlags, killReason);
    }

    public PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags,
            String killReason) {
        if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
        		//【1】如果指定了卸载时不 kill app,就用默认的参数(卸载时才会进入)
            return new PackageFreezer();
        } else {
        		//【2】默认是需要 kill app 的,调用 freezePackage
            return freezePackage(packageName, userId, killReason);
        }
    }

继续调用 freezePackage 方法:

java 复制代码
    public PackageFreezer freezePackage(String packageName, int userId, String killReason) {
    		 //【×7.3.7.1】创建了一个 PackageFreezer 实例
        return new PackageFreezer(packageName, userId, killReason);
    }

7.3.7.1 new PackageFreezer

如果不杀进程,那就只创建一个 PackageFreezer 实例,并返回,不做任何事情

java 复制代码
        public PackageFreezer() {
            mPackageName = null;
            mChildren = null;
            mWeFroze = false;
            mCloseGuard.open("close");
        }
//如果要 kill app,那么会创建 PackageFreezer(父包和子包),并且会杀掉进程
        public PackageFreezer(String packageName, int userId, String killReason) {
            synchronized (mPackages) {
                mPackageName = packageName;
                mWeFroze = mFrozenPackages.add(mPackageName);

                final PackageSetting ps = mSettings.mPackages.get(mPackageName);
                if (ps != null) {
                	 //【1】杀掉父包的进程
                    killApplication(ps.name, ps.appId, userId, killReason);
                }

                final PackageParser.Package p = mPackages.get(packageName);
                if (p != null && p.childPackages != null) {
                    final int N = p.childPackages.size();
                    mChildren = new PackageFreezer[N];
                    for (int i = 0; i < N; i++) {
                    		 //【2】为子包创建 PackageFreezer,并杀掉子包的进程
                        mChildren[i] = new PackageFreezer(p.childPackages.get(i).packageName,
                                userId, killReason);
                    }
                } else {
                    mChildren = null;
                }
            }
            mCloseGuard.open("close");
        }

7.4 FileInstallArgs.doPostInstall

清理操作,正常情况不会触发

java 复制代码
        int doPostInstall(int status, int uid) {
        		//【1】如果安装前的状态不是 PackageManager.INSTALL_SUCCEEDED
            if (status != PackageManager.INSTALL_SUCCEEDED) {
            		//【7.2.1】执行清理操作
                cleanUp();
            }
            return status;
        }

7.5 new PostInstallData

又创建了一个 PostInstallData 对象,对 PackageInstalledInfo 做了再次封装:

java 复制代码
    static class PostInstallData {
        public InstallArgs args;
        public PackageInstalledInfo res;

        PostInstallData(InstallArgs _a, PackageInstalledInfo _r) {
            args = _a;
            res = _r;
        }
    }

八、PackageHandler.doHandleMessage[POST_INSTALL] - 安装收尾

PackageHandler 会处理 POST_INSTALL 消息,此时已经处于安装收尾阶段:

java 复制代码
                case POST_INSTALL: {
                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
					//【1】我们在安装开始前,会用 PostInstallData 封装安装结果,并保存到 mRunningInstalls 中
					// 在安装结束后,会处理本次的安装结果
                    PostInstallData data = mRunningInstalls.get(msg.arg1);
                    final boolean didRestore = (msg.arg2 != 0);
                    mRunningInstalls.delete(msg.arg1);		// 删除掉

                    if (data != null) {
                        InstallArgs args = data.args;
                        PackageInstalledInfo parentRes = data.res;
						//【2】本次安装是否授予运行时权限
                        final boolean grantPermissions = (args.installFlags
                                & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
                        //【2】本次安装是否 kill app
                        final boolean killApp = (args.installFlags
                                & PackageManager.INSTALL_DONT_KILL_APP) == 0;
                        final boolean virtualPreload = ((args.installFlags
                                & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
                        final String[] grantedPermissions = args.installGrantPermissions;

                        // Handle the parent package
                        //【×8.1】调用 handlePackagePostInstall 继续处理收尾工作
                        handlePackagePostInstall(parentRes, grantPermissions, killApp,
                                virtualPreload, grantedPermissions, didRestore,
                                args.installerPackageName, args.observer);

                        // Handle the child packages
                        //【3】处理子包
                        final int childCount = (parentRes.addedChildPackages != null)
                                ? parentRes.addedChildPackages.size() : 0;
                        for (int i = 0; i < childCount; i++) {
                            PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
                            //【×8.1】调用 handlePackagePostInstall 继续处理收尾工作
                            handlePackagePostInstall(childRes, grantPermissions, killApp,
                                    virtualPreload, grantedPermissions, false /*didRestore*/,
                                    args.installerPackageName, args.observer);
                        }

                        // Log tracing if needed
                        if (args.traceMethod != null) {
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
                                    args.traceCookie);
                        }
                    } else {
                        Slog.e(TAG, "Bogus post-install token " + msg.arg1);
                    }

                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
                } break;

8.1 PackageManagerS.handlePackagePostInstall

处理安装收尾工作:

java 复制代码
    private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
            boolean killApp, boolean virtualPreload, String[] grantedPermissions,
            boolean launchedForRestore, String installerPackage,
            IPackageInstallObserver2 installObserver) {
        //【1】当安装结果为 success 后,会进入后续的处理
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
            // Send the removed broadcasts
            //【1.1】如果是 move pacakge,那么发送 removed 广播
            if (res.removedInfo != null) {
                res.removedInfo.sendPackageRemovedBroadcasts(killApp);
            }

            // Now that we successfully installed the package, grant runtime
            // permissions if requested before broadcasting the install. Also
            // for legacy apps in permission review mode we clear the permission
            // review flag which is used to emulate runtime permissions for
            // legacy apps.
            //【1.2】如果安装时指定了授予运行时权限,并且应用的目标 sdk 支持运行时权限,那就授予运行时权限
            if (grantPermissions) {
                final int callingUid = Binder.getCallingUid();
                mPermissionManager.grantRequestedRuntimePermissions(
                        res.pkg, res.newUsers, grantedPermissions, callingUid,
                        mPermissionCallback);
            }
			//【1.3】判断安装方式,是更新安装,还是全新安装!
        	// 我们知道,如果 res.removedInfo 不为 null 的话,一定是覆盖更新
            final boolean update = res.removedInfo != null
                    && res.removedInfo.removedPackage != null;
            final String installerPackageName =
                    res.installerPackageName != null
                            ? res.installerPackageName
                            : res.removedInfo != null
                                    ? res.removedInfo.installerPackageName
                                    : null;

            // If this is the first time we have child packages for a disabled privileged
            // app that had no children, we grant requested runtime permissions to the new
            // children if the parent on the system image had them already granted.
            //【1.4】如果被 disable 的特权应用之前没有子包,这是第一次有子包,那么我们会授予新的子包
	        // 运行时权限,如果旧的特权应用之前已经授予
            if (res.pkg.parentPackage != null) {
                final int callingUid = Binder.getCallingUid();
                mPermissionManager.grantRuntimePermissionsGrantedToDisabledPackage(
                        res.pkg, callingUid, mPermissionCallback);
            }

            synchronized (mPackages) {
                mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
            }

            final String packageName = res.pkg.applicationInfo.packageName;

            // Determine the set of users who are adding this package for
            // the first time vs. those who are seeing an update.
            //【1.5】决定在那些 user 下是第一次安装,那些用户下是覆盖更新
            int[] firstUserIds = EMPTY_INT_ARRAY;
            int[] firstInstantUserIds = EMPTY_INT_ARRAY;
            int[] updateUserIds = EMPTY_INT_ARRAY;
            int[] instantUserIds = EMPTY_INT_ARRAY;
            final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
            final PackageSetting ps = (PackageSetting) res.pkg.mExtras;
            for (int newUser : res.newUsers) {
                final boolean isInstantApp = ps.getInstantApp(newUser);
                if (allNewUsers) {
                    if (isInstantApp) {
                        firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
                    } else {
                        firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
                    }
                    continue;
                }
                // res.newUsers 表示本次安装新增加的目标 user
	            // res.origUsers 标志之前安装的目标 user
                boolean isNew = true;
                for (int origUser : res.origUsers) {
                    if (origUser == newUser) {
                        isNew = false;
                        break;
                    }
                }
                if (isNew) {
                    if (isInstantApp) {
                        firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
                    } else {
                        firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
                    }
                } else {
                    if (isInstantApp) {
                        instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
                    } else {
                        updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
                    }
                }
            }

            // Send installed broadcasts if the package is not a static shared lib.
            if (res.pkg.staticSharedLibName == null) {
                mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);

                // Send added for users that see the package for the first time
                // sendPackageAddedForNewUsers also deals with system apps
                int appId = UserHandle.getAppId(res.uid);
                boolean isSystem = res.pkg.applicationInfo.isSystemApp();
                sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
                        virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);

                // Send added for users that don't see the package for the first time
                //【1.5.1】给第一次安装的用户发送 ACTION_PACKAGE_ADDED 广播
                Bundle extras = new Bundle(1);
                extras.putInt(Intent.EXTRA_UID, res.uid);
                if (update) {
                	 //【1.5.2】给覆盖更新的用户发送 ACTION_PACKAGE_ADDED 广播,带 EXTRA_REPLACING 属性
                    extras.putBoolean(Intent.EXTRA_REPLACING, true);
                }
                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, 0 /*flags*/,
                        null /*targetPackage*/, null /*finishedReceiver*/,
                        updateUserIds, instantUserIds);
                if (installerPackageName != null) {
                    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                            extras, 0 /*flags*/,
                            installerPackageName, null /*finishedReceiver*/,
                            updateUserIds, instantUserIds);
                }
                // if the required verifier is defined, but, is not the installer of record
                // for the package, it gets notified
                final boolean notifyVerifier = mRequiredVerifierPackage != null
                        && !mRequiredVerifierPackage.equals(installerPackageName);
                if (notifyVerifier) {
                    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                            extras, 0 /*flags*/,
                            mRequiredVerifierPackage, null /*finishedReceiver*/,
                            updateUserIds, instantUserIds);
                }

                // Send replaced for users that don't see the package for the first time
                //【1.5.3】给覆盖更新的用户发送 ACTION_PACKAGE_REPLACED / ACTION_MY_PACKAGE_REPLACED 广播
                if (update) {
                    sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                            packageName, extras, 0 /*flags*/,
                            null /*targetPackage*/, null /*finishedReceiver*/,
                            updateUserIds, instantUserIds);
                    if (installerPackageName != null) {
                        sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
                                extras, 0 /*flags*/,
                                installerPackageName, null /*finishedReceiver*/,
                                updateUserIds, instantUserIds);
                    }
                    if (notifyVerifier) {
                        sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
                                extras, 0 /*flags*/,
                                mRequiredVerifierPackage, null /*finishedReceiver*/,
                                updateUserIds, instantUserIds);
                    }
                    sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                            null /*package*/, null /*extras*/, 0 /*flags*/,
                            packageName /*targetPackage*/,
                            null /*finishedReceiver*/, updateUserIds, instantUserIds);
                } else if (launchedForRestore && !isSystemApp(res.pkg)) {
                    // First-install and we did a restore, so we're responsible for the
                    // first-launch broadcast.
                    //【1.5.4】如果是第一次安装,同时我们要做一个恢复操作,并且 apk 不是系统应用
                	// 那么我们会发送 ACTION_PACKAGE_FIRST_LAUNCH 广播
                    if (DEBUG_BACKUP) {
                        Slog.i(TAG, "Post-restore of " + packageName
                                + " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
                    }
                    sendFirstLaunchBroadcast(packageName, installerPackage,
                            firstUserIds, firstInstantUserIds);
                }

                // Send broadcast package appeared if forward locked/external for all users
                // treat asec-hosted packages like removable media on upgrade
                if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
                    if (DEBUG_INSTALL) {
                        Slog.i(TAG, "upgrading pkg " + res.pkg
                                + " is ASEC-hosted -> AVAILABLE");
                    }
                    final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
                    ArrayList<String> pkgList = new ArrayList<>(1);
                    pkgList.add(packageName);
                    sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
                }
            }

            // Work that needs to happen on first install within each user
            //【1.6】针对 firstUsers 做一些权限恢复和默认浏览器设置
            if (firstUserIds != null && firstUserIds.length > 0) {
                synchronized (mPackages) {
                    for (int userId : firstUserIds) {
                        // If this app is a browser and it's newly-installed for some
                        // users, clear any default-browser state in those users. The
                        // app's nature doesn't depend on the user, so we can just check
                        // its browser nature in any user and generalize.
                        //【1.6.1】默认浏览器设置
                        if (packageIsBrowser(packageName, userId)) {
                            mSettings.setDefaultBrowserPackageNameLPw(null, userId);
                        }

                        // We may also need to apply pending (restored) runtime
                        // permission grants within these users.
                        //【1.6.2】处理那些正在等待或者需要恢复的运行时权限授予
                        mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
                    }
                }
            }

            if (allNewUsers && !update) {
                notifyPackageAdded(packageName);
            }

            // Log current value of "unknown sources" setting
            EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
                    getUnknownSourcesSettings());

            // Remove the replaced package's older resources safely now
            // We delete after a gc for applications  on sdcard.
            if (res.removedInfo != null && res.removedInfo.args != null) {
            	// 触发 GC 回收资源
                Runtime.getRuntime().gc();
                synchronized (mInstallLock) {
                	//【5.8.1.1】移除掉更新后的旧 apk
                    res.removedInfo.args.doPostDeleteLI(true);
                }
            } else {
                // Force a gc to clear up things. Ask for a background one, it's fine to go on
                // and not block here.
                VMRuntime.getRuntime().requestConcurrentGC();
            }

            // Notify DexManager that the package was installed for new users.
            // The updated users should already be indexed and the package code paths
            // should not change.
            // Don't notify the manager for ephemeral apps as they are not expected to
            // survive long enough to benefit of background optimizations.
            for (int userId : firstUserIds) {
                PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
                // There's a race currently where some install events may interleave with an uninstall.
                // This can lead to package info being null (b/36642664).
                if (info != null) {
                    mDexManager.notifyPackageInstalled(info, userId);
                }
            }
        }

        // If someone is watching installs - notify them
        //【*8.2】通知观察者安装的结果,这里的 installObserver 是我们之前创建的 localObsever
        if (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.");
            }
        }
    }

我们看到,这里涉及到了几个重要的广播:

  • Intent.ACTION_PACKAGE_ADDED:当有应用程序第一次安装时,会发送该广播给对应的 firstUsers!
    • 携带数据:Intent.EXTRA_UID,值为 apk uid;
  • Intent.ACTION_PACKAGE_REPLACED:当有应用程序被覆盖安装时,会发送该广播给对应的 updateUsers!
    • 携带数据:Intent.EXTRA_UID,
    • 携带数据:Intent.EXTRA_REPLACING,置为 true;
  • Intent.ACTION_MY_PACKAGE_REPLACED:当有应用程序被覆盖安装时,会发送该广播给对应的 updateUsers 下被更新的 pkg!
    • 携带数据:packageName,被更新的应用包;

8.1.1 FileInstallArgs.doPostDeleteLI - 删除被更新的旧 apk

java 复制代码
        boolean doPostDeleteLI(boolean delete) {
            // XXX err, shouldn't we respect the delete flag?
            //【*8.1.2】清除 apk 文件 和 dex 文件
            cleanUpResourcesLI();
            return true;
        }

8.1.2 FileInstallArgs.cleanUpResourcesLI

java 复制代码
        void cleanUpResourcesLI() {
            // Try enumerating all code paths before deleting
            List<String> allCodePaths = Collections.EMPTY_LIST;
            if (codeFile != null && codeFile.exists()) {
                try {
                	//【1】收集 apk path
                    final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);
                    allCodePaths = pkg.getAllCodePaths();
                } catch (PackageParserException e) {
                    // Ignored; we tried our best
                }
            }
			//【2】清除 apk
            cleanUp();
            //【3】清除 dex files
            removeDexFiles(allCodePaths, instructionSets);
        }

8.2 IPackageInstallObserver2.onPackageInstalled

这里的 installObserver 是我们在 4.3 PackageInstallerSession.commitLocked 中创建的另一个 Observer

位置:./frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java

java 复制代码
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
            @Override
            public void onUserActionRequired(Intent intent) {
                throw new IllegalStateException();
            }

            @Override
            public void onPackageInstalled(String basePackageName, int returnCode, String msg,
                    Bundle extras) {
                destroyInternal();
                dispatchSessionFinished(returnCode, msg, extras);
            }
        };

8.2.1 PackageInstallerSession.destroyInternal

关闭文件桥,删除文件拷贝:

java 复制代码
    private void destroyInternal() {
        synchronized (mLock) {
            mSealed = true;
            mDestroyed = true;

            // Force shut down all bridges
            for (RevocableFileDescriptor fd : mFds) {
                fd.revoke();
            }
            //【1】关闭之前打开的文件桥对象
            for (FileBridge bridge : mBridges) {
                bridge.forceClose();
            }
        }
        if (stageDir != null) {
            try {
            	//【2】删除之前的文件拷贝目录
                mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
            } catch (InstallerException ignored) {
            }
        }
    }

8.2.2 PackageInstallerSession.dispatchSessionFinished

处理回调,通知监听者:

java 复制代码
    private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
        final IPackageInstallObserver2 observer;
        final String packageName;
        synchronized (mLock) {
            mFinalStatus = returnCode;
            mFinalMessage = msg;

            observer = mRemoteObserver;
            packageName = mPackageName;
        }

        if (observer != null) {
            // Execute observer.onPackageInstalled on different tread as we don't want callers
            // inside the system server have to worry about catching the callbacks while they are
            // calling into the session
            final SomeArgs args = SomeArgs.obtain();
            args.arg1 = packageName;
            args.arg2 = msg;
            args.arg3 = extras;
            args.arg4 = observer;
            args.argi1 = returnCode;
			//【*4.1.2】触发 mRemoteObserver 回调
            mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
        }

        final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);

        // Send broadcast to default launcher only if it's a new install
        final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
        if (success && isNewInstall) {
            mPm.sendSessionCommitBroadcast(generateInfo(), userId);
        }
		//【*8.2.2.2】回调触发
        mCallback.onSessionFinished(this, success);
    }

在前面 4.1 commit 事务的时候,我们创建了一个 PackageInstallObserverAdapter,并将其保存到了 PackageInstallerSession.mRemoteObserver 中,这里首先会触发 mRemoteObserver 的回调

在 3.1.4.1 new InternalCallback 的时候,我们在创建 PackageInstallerSession 时,传入了一个回调对象 InternalCallback:

java 复制代码
private final InternalCallback mInternalCallback = new InternalCallback();

InternalCallback 类定义在 PackageInstallerService 中,该对象的引用会被保存到 PackageInstallerSession.mCallback 变量中

8.2.2.2 InternalCallback.onSessionFinished

这里我们重点关于 onSessionFinished 方法:

java 复制代码
        public void onSessionFinished(final PackageInstallerSession session, boolean success) {
        	//【×8.2.2.2.1】注册者回调
            mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);

            mInstallHandler.post(new Runnable() {
                @Override
                public void run() {
                    synchronized (mSessions) {
                    	//【1】从 PackageInstallerService 中的 mSessions 移除了该 Session;
                        mSessions.remove(session.sessionId);
                        //【2】将该 Sesssion 添加到历史中;
                        addHistoricalSessionLocked(session);

                        final File appIconFile = buildAppIconFile(session.sessionId);
                        if (appIconFile.exists()) {
                            appIconFile.delete();
                        }
						//【×3.1.6.1】持久化事务记录文件
                        writeSessionsLocked();
                    }
                }
            });
        }

我们看到,在 InternalCallback 中又回调了另外一个 Callback mCallbacks,它也是 PackageInstallerService 的内部类:

8.2.2.2.1 Callback.notifySessionFinished

前面我们分析过,Callback 本质上就是一个 Handler,这里就是向其所在的线程发送消息:

java 复制代码
        public void notifySessionFinished(int sessionId, int userId, boolean success) {
            obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
        }

在 3.1.4.2 Callbacks.notifySessionXXXX 中,我们分析过,最终其实是很将安装的结果分发给了注册在 Callback 中的所有远程回调:

java 复制代码
private final RemoteCallbackList<IPackageInstallerCallback>
        mCallbacks = new RemoteCallbackList<>();
相关推荐
Geeker555 小时前
如何在忘记密码的情况下解锁Android手机?
android·网络·macos·华为·智能手机·电脑·手机
wxx21506 小时前
【android】【adb shell】写一个shell脚本,监听进程pid变化
android·adb
心死翼未伤8 小时前
【MySQL基础篇】多表查询
android·数据结构·数据库·mysql·算法
喂_balabala8 小时前
Android手机拍照或从本地相册选取图片设置头像-高版本适配
android·开发语言
_小马快跑_9 小时前
Android | StandardCharsets.UTF_8.toString() 遇到的兼容问题记录
android
wxx215010 小时前
【Android】【多屏】多屏异显异触调试技巧总结
android
胡子洲11 小时前
Windows电脑PC使用adb有线跟无线安装apk包
windows·adb·电脑
人民的石头12 小时前
Android增量更新----java版
android
Geeker5514 小时前
如何在忘记密码的情况下删除华为ID激活锁
android·运维·服务器·网络·macos·华为·智能手机
XD74297163615 小时前
【Android】ADB 使用指南
android·adb