Android应用管理二 --APK包的安装、卸载和优化(PackageManagerService)

继续上一章讲解。

在Android中,通过发送Intent,就可以启动应用的安装过程,如下所示:

Uri uri = Uri.fromFile(new File(fileName));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri, "application/vnd.android.package-archive");
startActivity(intent);

在Android的系统应用PackageInstaller中有一个PackageInstallerActivity会响应这个Intent。在这个Activity中,有两个重要的成员变量mPm,是ApplicationPackageManager的实例对象,也是PackageManagerService在应用中的代理对象。创建代码如下:

mPm = getPackageManager();

一、管理“安装会话”—-PackageInstallerService

PackageInstallerService是Android5.0新加入的服务,主要用于管理“安装会话(Installer Session)”。在Android5.0中,可以通过PackageInstallerService来分配一个SessionId,这个系统唯一的ID代表一次安装过程,如果一个应用的安装必须分成几个阶段来完成,即使设备重启了,也可以通过这个ID来继续安装过程。

PackageInstallerService中提供了接口createSession()创建一个Session:

    public int createSession(SessionParams params, String installerPackageName, int userId) {
        try {
            return createSessionInternal(params, installerPackageName, userId);
        } catch (IOException e) {
            throw ExceptionUtils.wrap(e);
        }
    }

createSession方法将返回一个系统唯一值作为SessionID。如果希望再次使用这个Session,可以通过接口openSession打开它,代码如下:

    public IPackageInstallerSession openSession(int sessionId) {
        try {
            return openSessionInternal(sessionId);
        } catch (IOException e) {
            throw ExceptionUtils.wrap(e);
        }
    }

    private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
        synchronized (mSessions) {
            final PackageInstallerSession session = mSessions.get(sessionId);
            if (session == null || !isCallingUidOwner(session)) {
                throw new SecurityException("Caller has no access to session " + sessionId);
            }
            session.open();
            return session;
        }
    }

openSession方法返回一个IPackageInstallerSession对象,它是Binder服务PackageInstallerSession的IBinder对象。在PackageInstallerService中mSessions数组保存了所有PackageInstallerSession对象,代码如下:

private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();

当系统启动时,PackageManagerService初始化时会创建PackageInstallerService服务,在这个服务的初始化函数中,会读取/data/system目录下install_sessions.xml文件,这个文件中保存了系统中未完成的Install Session。PackageInstallerService会根据文件的内容创建PackageInstallerSession对象并插入到mSessions中。

PacakgeInstallerSession中保存了应用安装相关的数据,如,安装包的路径、安装的进度、中间数据保存的目录等。

二、应用安装第一阶段:复制文件

应用中可以调用PackageManager的installPackage()方法来开始安装过程,这个方法会调用PackageManagerService的installPackage()方法或installPackageAsUser()接口来执行安装过程。整个过程比较复杂,我们先看看安装序列图,如下:

应用安装的过程大概分成两个阶段,第一阶段把需要安装的应用复制到/data/app目录下,第二阶段是对apk文件进行扫描优化,然后装载到内存中。

PackageManagerService的installPackage方法用来给当前用户安装应用,而installPackageAsUser()方法给指定的用户安装应用。installPackage()方法只是使用当前用户的uid来调用installPackageAsUser()方法。代码如下:

    @Override
    public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, VerificationParams verificationParams,
            String packageAbiOverride, int userId) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);//检查调用进程的权限

        final int callingUid = Binder.getCallingUid();//检查调用进程的用户是否有权限安装应用
        enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");

        if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {//检查指定的用户是否被限制安装应用
            try {
                if (observer != null) {
                    observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
                }
            } catch (RemoteException re) {
            }
            return;
        }

        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
            installFlags |= PackageManager.INSTALL_FROM_ADB;//调用进程uid为0或2000,设置installFlags

        } else {
            // Caller holds INSTALL_PACKAGES permission, so we're less strict
            // about installerPackageName.

            installFlags &= ~PackageManager.INSTALL_FROM_ADB;
            installFlags &= ~PackageManager.INSTALL_ALL_USERS;
        }

        UserHandle user;
        if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {//如果installFlags带有标记INSTALL_ALL_USERS,则给所有用户安装
            user = UserHandle.ALL;
        } else {
            user = new UserHandle(userId);
        }

        verificationParams.setInstallerUid(callingUid);

        final File originFile = new File(originPath);
        final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
        //保存参数到InstallParams对象并发送消息
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        msg.obj = new InstallParams(origin, observer, installFlags,
                installerPackageName, verificationParams, user, packageAbiOverride);
        mHandler.sendMessage(msg);
    }

installPackageAsUser()方法首先检查调用进程是否有安装应用的权限,再检查调用进程的所属用户是否有权限安装应用,

最后检查指定的用户是否被限制安装应用。如果参数installFlags带有标记INSTALL_ALL_USERS,则该应用将给系统中

所有用户安装,否则只给指定的用户安装。

installPackageAsUser()方法,把调用的参数保存在InstallParams对象中,然后发送INIT_COPY消息。

InstallParams是安装过程中主要的数据结构,从HandleParams类派生,用来记录安装应用的参数

从HandleParams派生的还有MoveParams和MeasureParams,MoveParams用于将应用移动到SD卡,

MeasureParams用于方法getPackageSizeInfo中。InstallParams成员变量mArgs,是FileInstallArgs类型,用来执行

apk文件的复制。

我们看下INIT_COPY消息的处理,在doHandleMessage()方法中,如下:

                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
                    int idx = mPendingInstalls.size();
                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
                    // If a bind was already initiated we dont really
                    // need to do anything. The pending install
                    // will be processed later on.
                    if (!mBound) {
                        // If this is the only one pending we might
                        // have to bind to the service again.
                        if (!connectToService()) {//绑定DefaultContainerService服务
                            Slog.e(TAG, "Failed to bind to media container service");
                            params.serviceError();
                            return;//连接服务失败,退出
                        } else {
                            // Once we bind to the service, the first连接成功,把安装信息保存到mPedingInstalls中
                            // pending request will be processed.
                            mPendingInstalls.add(idx, params);//待收到连接的返回消息后再继续安装
                        }
                    } else {
                        mPendingInstalls.add(idx, params);//插入安装信息
                        // Already bound to the service. Just make
                        // sure we trigger off processing the first request.
                        if (idx == 0) {//如果mPendingInstalls只有一项,立刻发MCS_BOUND消息
                            mHandler.sendEmptyMessage(MCS_BOUND);
                        }
                    }
                    break;
                }

在INIT_COPY消息的处理中
将绑定DefaultContainerService,因为这是一个异步的过程,要等待绑定的结果通过onServiceConnected()返回,所以,这里将安装的参数信息放到mPendingInstalls列表中。如果这个service以前就绑定好了,现在不在需要再绑定,安装信息也会先放到mPendingInstalls中。如果有多个安装请求同时到达,通过mPendingInstalls列表可以对它们进行排队。如果列表中只有一项,说明没有更多的安装请求,此时会立即
发送MCS_BOUND消息,进入下一步的处理。而onServiceConnected()方法的处理同样是发送MCS_BOUND消息,如下:

    class DefaultContainerConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName name, IBinder service) {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
            IMediaContainerService imcs =
                IMediaContainerService.Stub.asInterface(service);
            mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
        }

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

我们看下MCS_BOUND消息是怎么处理的,如下:

                case MCS_BOUND: {
                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
                    if (msg.obj != null) {
                        mContainerService = (IMediaContainerService) msg.obj;
                    }
                    if (mContainerService == null) {//如果DefaultContainerService没有连接成功
                        // Something seriously wrong. Bail out
                        Slog.e(TAG, "Cannot bind to media container service");
                        for (HandlerParams params : mPendingInstalls) {
                            // Indicate service bind error
                            params.serviceError();//通过参数中带的回调接口通知调用者出错了
                        }
                        mPendingInstalls.clear();
                    } else if (mPendingInstalls.size() > 0) {
                        HandlerParams params = mPendingInstalls.get(0);
                        if (params != null) {
                            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
                                if (mPendingInstalls.size() > 0) {
                                    mPendingInstalls.remove(0);//工作完成,删除第一项
                                }
                                if (mPendingInstalls.size() == 0) {
                                    if (mBound) {//如果没有安装信息了,发送延时10秒的MCS_UNBIND消息
                                        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.mPendingInstalls还有安装信息,发送MCS_BOUND消息
                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
                                            "Posting MCS_BOUND for next work");
                                    mHandler.sendEmptyMessage(MCS_BOUND);
                                }
                            }
                        }
                    } else {
                        // Should never happen ideally.
                        Slog.w(TAG, "Empty queue");
                    }
                    break;
                }

MCS_BOUND消息的处理过程就是调用InstallParams类的startCopy()方法来执行安装。只要mPendingInstalls中还有安装信息,就会重复发送MCS_BOUND消息,直到所有的应用都安装完毕,然后发送一个延时10秒的MCS_UNBIND消息。

MCS_UNBIND消息的处理如下:

                case MCS_UNBIND: {
                    // If there is no actual work left, then time to unbind.
                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");

                    if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
                        if (mBound) {
                            if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");

                            disconnectService();//断开与DefaultContainerService的连接
                        }
                    } else if (mPendingInstalls.size() > 0) {
                        // There are more pending requests in queue.
                        // Just post MCS_BOUND message to trigger processing
                        // of next pending install.
                        mHandler.sendEmptyMessage(MCS_BOUND);
                    }

                    break;
                }

处理MCS_UNBIND消息时,如果发现mPendingInstalls列表中又有数据了,则发送MCS_BOUND消息继续安装;否则断开和DefaultContainerService的连接,安装过程就此结束。

继续分析下start_copy()方法,InstallParams类继承HandlerParams抽象类,InstallParams类没有重写startCopy方法,因此调用HandlerParams的startCopy方法,如下:

        final boolean startCopy() {
            boolean res;
            try {
                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);

                if (++mRetries > MAX_RETRIES) {//如果重试超过4次,退出;MAX_RETRIES=4
                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                    mHandler.sendEmptyMessage(MCS_GIVE_UP);//发送MCS_GIVE_UP消息
                    handleServiceError();
                    return false;
                } else {
                    handleStartCopy();//执行安装
                    res = true;
                }
            } catch (RemoteException e) {
                if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
                mHandler.sendEmptyMessage(MCS_RECONNECT);//安装出错,发送MCS_RECONNECT消息,重新连接
                res = false;
            }
            handleReturnCode();
            return res;
        }

startCopy()方法通过调用handleStartCopy方法来完成安装过程。但是考虑到安装过程的不确定性,
startCopy()主要的工作是进行错误处理,如果捕获到handleStartCopy()方法抛出的异常,startCopy方法将发送消息MCS_RECONNECT

                case MCS_RECONNECT: {
                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect");
                    if (mPendingInstalls.size() > 0) {
                        if (mBound) {
                            disconnectService();
                        }
                        if (!connectToService()) {
                            Slog.e(TAG, "Failed to bind to media container service");
                            for (HandlerParams params : mPendingInstalls) {
                                // Indicate service bind error
                                params.serviceError();
                            }
                            mPendingInstalls.clear();
                        }
                    }
                    break;
                }

在MCS_RECONNECT的处理中,会重新绑定DefaultContainerService,如果绑定成功,安装过程就会重新开始,startCopy方法会被再次调用。重试的次数记录在mRetries变量中,
如果超过4次,安装失败。如果安装成功,调用handleReturnCode方法继续处理。先分析下handleStartCopy方法,如下:

        public void handleStartCopy() throws RemoteException {
            int ret = PackageManager.INSTALL_SUCCEEDED;

            // If we're already staged, we've firmly committed to an install location
            if (origin.staged) {
                if (origin.file != null) {
                    installFlags |= PackageManager.INSTALL_INTERNAL;
                    installFlags &= ~PackageManager.INSTALL_EXTERNAL;
                } else if (origin.cid != null) {
                    installFlags |= PackageManager.INSTALL_EXTERNAL;
                    installFlags &= ~PackageManager.INSTALL_INTERNAL;
                } else {
                    throw new IllegalStateException("Invalid stage location");
                }
            }

            final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
            final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;

            PackageInfoLite pkgLite = null;

            if (onInt && onSd) {//如果既有安装在内部的标志,又有安装在SD卡上的标志,设置错误后返回
                // Check if both bits are set.
                Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else {
                pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                        packageAbiOverride);//获取安装包包含有应用信息的PackageInfoLite对象

                /*
                 * If we have too little free space, try to free cache
                 * before giving up.如果安装的位置空间不够,释放cache空间
                 */
                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);
                    long lowThreshold = storage.getStorageLowBytes(
                            Environment.getDataDirectory());

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

                    if (mInstaller.freeCache(sizeBytes + lowThreshold) >= 0) {
                        pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
                                installFlags, packageAbiOverride);
                    }

                    /*
                     * 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.
                     */
                    if (pkgLite.recommendedInstallLocation
                            == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                        pkgLite.recommendedInstallLocation
                            = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
                    }
                }
            }
            ......

            final InstallArgs args = createInstallArgs(this);
            mArgs = args;

            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                 /*
                 * ADB installs appear as UserHandle.USER_ALL, and can only be performed by
                 * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
                 */
                int userIdentifier = getUser().getIdentifier();
                if (userIdentifier == UserHandle.USER_ALL
                        && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) {
                    userIdentifier = UserHandle.USER_OWNER;
                }

                /*
                 * Determine if we have any installed package verifiers. If we
                 * do, then we'll defer to them to verify the packages.
                 */
                final int requiredUid = mRequiredVerifierPackage == null ? -1
                        : getPackageUid(mRequiredVerifierPackage, userIdentifier);
                if (!origin.existing && requiredUid != -1
                        && isVerificationEnabled(userIdentifier, installFlags)) {//执行应用的校验,方法是通过向带校验功能的组件发Intent来完成。

…… } else { /* * No package verification is enabled, so immediately start * the remote call to initiate copy using temporary file. *///如果无需校验,调用IntallArgs的copyApk方法继续处理 ret = args.copyApk(mContainerService, true); } } mRet = ret; }

handleStartCopy()方法先调用getMinimalPackageInfo()来确定安装位置是否还有足够空间,并在PackageInfoLite对象的recommendedInstallLocation变量中记录错误原因。发现安装空间不够后,handleStartCopy()方法会调用installer的freeCache()方法来释放一部分空间

接下来handleStartCopy()方法会调用createInstallArgs()来创建InstallArgs对象在createInstallArgs()方法中,如果应用要求安装在SD卡上,或者是一个forward lock的应用,则创建AsecInstallArgs对象,否则创建FileInstallArgs对象。这样安装流程将会分化,这里主要分析下FileInstallArgs。如下:

    private InstallArgs createInstallArgs(InstallParams params) {
        if (installOnSd(params.installFlags) || params.isForwardLocked()) {
            return new AsecInstallArgs(params);
        } else {
            return new FileInstallArgs(params);
        }
    }

接下来handleStartCopy()方法处理APK的校验,这个校验的过程是通过发送Intent.ACTION_PACKAGE_NEEDS_VERIFICATION给系统中所有接收该Intent的应用来完成的。如果无需校验,则直接调用InstallArgs对象的copyApk()方法,FileInstallArgs继承了InstallArgs类,这里调用的是FileInstallArgs类的copyApk()方法,如下:

        int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
            if (origin.staged) {
                Slog.d(TAG, origin.file + " already staged; skipping copy");
                codeFile = origin.file;
                resourceFile = origin.file;
                return PackageManager.INSTALL_SUCCEEDED;
            }

            try {//在/data/app/下生成临时文件
                final File tempDir = mInstallerService.allocateInternalStageDirLegacy();
                codeFile = tempDir;
                resourceFile = tempDir;
            } catch (IOException e) {
                Slog.w(TAG, "Failed to create copy file: " + e);
                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
            }
            //为临时文件创建文件描述符ParcelFileDescriptor,它能通过Binder传递
            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 {
                        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());
                    }
                }
            };
            //使用服务DefaultContainerService的copyPackage()方法复制文件
            int ret = PackageManager.INSTALL_SUCCEEDED;
            ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
            if (ret != PackageManager.INSTALL_SUCCEEDED) {
                Slog.e(TAG, "Failed to copy package");
                return ret;
            }
            //安装应用中自带的native的动态库
            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;
        }

copyApk()同样是
调用DefaultContainerService的copyPackage()将应用的文件复制到/data/app下。如果应用中还有native的动态库,也会把包在apk文件中的动态库的文件提取出来。执行完copyApk后,安装的第一阶段工作就完成了,
应用安装到了/data/app目录下

三、装载应用

第二阶段就是将应用的格式转化为oat格式,为应用创建数据目录,最后把应用的信息装载进PMS的数据结构中。

在前面的startCopy()方法中已经看到,最后它会调用handleReturnCode()方法,如下:

        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.
            if (mArgs != null) {
                processPendingInstall(mArgs, mRet);
            }
        }

handleReturnCode()方法只是调用了processpendingInstall()方法,如下:

    private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        // Queue up an async operation since the package installation may take a little while.
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
                 // Result object to be returned
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.returnCode = currentStatus;
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = new PackageRemovedInfo();
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//如果应用安装成功了
                    args.doPreInstall(res.returnCode);
                    synchronized (mInstallLock) {
                        installPackageLI(args, res);//装载安装的应用
                    }
                    args.doPostInstall(res.returnCode, res.uid);
                }

                // A restore should be performed at this point if (a) the install
                // succeeded, (b) the operation is not an update, and (c) the new
                // package has not opted out of backup participation.
                final boolean update = res.removedInfo.removedPackage != null;
                final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
                boolean doRestore = !update
                        && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);

                // Set up the post-install work request bookkeeping.  This will be used
                // and cleaned up by the post-install event handling regardless of whether
                // there's a restore pass performed.  Token values are >= 1.
                int token;
                if (mNextInstallToken < 0) mNextInstallToken = 1;
                token = mNextInstallToken++;

                PostInstallData data = new PostInstallData(args, res);
                mRunningInstalls.put(token, data);
                if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);

                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
                    // Pass responsibility to the Backup Manager.  It will perform a
                    // restore if appropriate, then pass responsibility back to the
                    // Package Manager to run the post-install observer callbacks
                    // and broadcasts.
                    IBackupManager bm = IBackupManager.Stub.asInterface(
                            ServiceManager.getService(Context.BACKUP_SERVICE));
                    if (bm != null) {
                        if (DEBUG_INSTALL) Log.v(TAG, "token " + token
                                + " to BM for possible restore");
                        try {
                            if (bm.isBackupServiceActive(UserHandle.USER_OWNER)) {
                                bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
                            } else {
                                doRestore = false;
                            }
                        } catch (RemoteException e) {
                            // can't happen; the backup manager is local
                        } catch (Exception e) {
                            Slog.e(TAG, "Exception trying to enqueue restore", e);
                            doRestore = false;
                        }
                    } else {
                        Slog.e(TAG, "Backup Manager not found!");
                        doRestore = false;
                    }
                }

                if (!doRestore) {//发送POST_INSTALL消息
                    // 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);
                    Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
                    mHandler.sendMessage(msg);
                }
            }
        });
    }

processPendingInstall()方法中
post了一个消息,这样安装过程将以异步的方式继续执行。在post消息的处理中,首先调用installPackageLI()来装载应用,接下来的一大段代码都是执行备份操作,备份是通过BackupManagerService来完成的。备份完成后,通过
发送POST_INSTALL消息来继续处理。先分析下installPackageLI()方法,如下:

    private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
        final int installFlags = args.installFlags;
        String installerPackageName = args.installerPackageName;
        File tmpPackageFile = new File(args.getCodePath());
        boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
        boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);
        boolean replace = false;
        final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;
        // Result object to be returned
        res.returnCode = PackageManager.INSTALL_SUCCEEDED;

        if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
        if (true != mSecurityBridge.approveAppInstallRequest(
                        args.getResourcePath(),
                        Uri.fromFile(args.origin.file).toSafeString())) {
            res.returnCode = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
            return;
        }

        // Retrieve PackageSettings and parse package创建apk文件的解析器
        final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
                | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
                | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
        PackageParser pp = new PackageParser();
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setDisplayMetrics(mMetrics);

        final PackageParser.Package pkg;
        try {//解析apk文件
            pkg = pp.parsePackage(tmpPackageFile, parseFlags);
        } catch (PackageParserException e) {
            res.setError("Failed parse during installPackageLI", e);
            return;
        }

        // Mark that we have an install time CPU ABI override.
        pkg.cpuAbiOverride = args.abiOverride;

        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;
            }
        }

        if (android.app.AppOpsManager.isStrictEnable()
                && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)
                && Secure.getInt(mContext.getContentResolver(),
                        Secure.INSTALL_NON_MARKET_APPS, 0) <= 0) {
            res.returnCode = PackageManager.INSTALL_FAILED_UNKNOWN_SOURCES;
            return;
        }
        //收集应用的签名
        try {
            pp.collectCertificates(pkg, parseFlags);
            pp.collectManifestDigest(pkg);
        } catch (PackageParserException e) {
            res.setError("Failed collect during installPackageLI", e);
            return;
        }

        /* If the installer passed in a manifest digest, compare it now. */
        if (args.manifestDigest != null) {
            if (DEBUG_INSTALL) {
                final String parsedManifest = pkg.manifestDigest == null ? "null"
                        : pkg.manifestDigest.toString();
                Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
                        + parsedManifest);
            }

            if (!args.manifestDigest.equals(pkg.manifestDigest)) {
                res.setError(INSTALL_FAILED_PACKAGE_CHANGED, "Manifest digest changed");
                return;
            }
        } else if (DEBUG_INSTALL) {
            final String parsedManifest = pkg.manifestDigest == null
                    ? "null" : pkg.manifestDigest.toString();
            Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);
        }

        // 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如果安装的升级应用,继续使用以前老的包名
            if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                String oldName = mSettings.mRenamedPackages.get(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.
                    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.
                    replace = true;
                    if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
                }
            }

           PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);

                // 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.
                if (!ps.keySetData.isUsingUpgradeKeySets() || ps.sharedUser != null) {
                    try {
                        verifySignaturesLP(ps, pkg);
                    } catch (PackageManagerException e) {
                        res.setError(e.error, e.getMessage());
                        return;
                    }
                } else {
                    if (!checkUpgradeKeySetLP(ps, pkg)) {
                        res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                                + pkg.packageName + " upgrade keys do not match the "
                                + "previously installed version");
                        return;
                    }
                }
//判断安装的应用是否存在同名的应用,如果存在,检查应用是否带有系统标志
                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);
            } 

。。。。。。

installPackageLI()方法首先解析了安装的应用文件,得到解析的结果后,主要是判断新安装的应用是否和系统中已安装的应用构成升级关系,如果是,调用replacePackageLI()方法继续处理,否则调用installNewPackageLI()方法处理。

再接着看下POST_INSTALL消息是如何处理的:

                case POST_INSTALL: {
                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
                    PostInstallData data = mRunningInstalls.get(msg.arg1);
                    mRunningInstalls.delete(msg.arg1);
                    boolean deleteOld = false;

                    if (data != null) {
                        InstallArgs args = data.args;
                        PackageInstalledInfo res = data.res;

                        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                            res.removedInfo.sendBroadcast(false, true, false);
                            Bundle extras = new Bundle(1);
                            extras.putInt(Intent.EXTRA_UID, res.uid);
                            。。。。。。
                            sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                                    res.pkg.applicationInfo.packageName,
                                    extras, null, null, firstUsers);//发送ACTION_PACKAGE_ADDED广播
                            final boolean update = res.removedInfo.removedPackage != null;
                            if (update) {
                                extras.putBoolean(Intent.EXTRA_REPLACING, true);
                            }
                            sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                                    res.pkg.applicationInfo.packageName,
                                    extras, null, null, updateUsers);
                            if (update) {//如果是升级包,还会发送更多的广播
                                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                                        res.pkg.applicationInfo.packageName,
                                        extras, null, null, updateUsers);
                                sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                                        null, null,
                                        res.pkg.applicationInfo.packageName, null, updateUsers);

                                // treat asec-hosted packages like removable media on upgrade
                                if (isForwardLocked(res.pkg) || isExternal(res.pkg)) {//如果是forward lock应用,或安装在SD卡上的应用,发送广播
                                    if (DEBUG_INSTALL) {
                                        Slog.i(TAG, "upgrading pkg " + res.pkg
                                                + " is ASEC-hosted -> AVAILABLE");
                                    }
                                    int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
                                    ArrayList<String> pkgList = new ArrayList<String>(1);
                                    pkgList.add(res.pkg.applicationInfo.packageName);
                                    sendResourcesChangedBroadcast(true, true,
                                            pkgList,uidArray, null);
                                }
                            }
                            if (res.removedInfo.args != null) {
                                // Remove the replaced package's older resources safely now
                                deleteOld = true;
                            }

                            // Log current value of "unknown sources" setting
                            EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
                                getUnknownSourcesSettings());
                        }
                        // Force a gc to clear up things
                        Runtime.getRuntime().gc();

                        // We delete after a gc for applications  on sdcard.
                        if (deleteOld) {
                            synchronized (mInstallLock) {
                                res.removedInfo.args.doPostDeleteLI(true);
                            }
                        }
                        if (args.observer != null) {
                            try {//调用参数中的回调接口,通知调用者安装的结果
                                Bundle extras = extrasForInstallResult(res);
                                args.observer.onPackageInstalled(res.name, res.returnCode,
                                        res.returnMsg, extras);
                            } catch (RemoteException e) {
                                Slog.i(TAG, "Observer no longer exists.");
                            }
                        }
                    } else {
                        Slog.e(TAG, "Bogus post-install token " + msg.arg1);
                    }
                    sLatestSecureContainerList = PackageHelper.getSecureContainerList();
                }

POST_INSTALL消息的处理主要就是发送广播,应用安装完成后要通知系统中其他的应用开始处理,例如,Launcher中需要增加应用的图标等。发完广播安装也就结束了。
最后通过参数中的回调接口通知调用者安装的结果

四、卸载应用

PMS还会监视应用目录的变化,做出相应的处理。

卸载应用的接口是deletePackage(),如下:

    public void deletePackage(final String packageName,
            final IPackageDeleteObserver2 observer, final int userId, final int flags) {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.DELETE_PACKAGES, null);//检查执行权限
        final int uid = Binder.getCallingUid();
        if (UserHandle.getUserId(uid) != userId) {
            mContext.enforceCallingPermission(
                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                    "deletePackage for user " + userId);
        }
        if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
            try {//如果用户权限不够,发送错误信息
                observer.onPackageDeleted(packageName,
                        PackageManager.DELETE_FAILED_USER_RESTRICTED, null);
            } catch (RemoteException re) {
            }
            return;
        }

        boolean uninstallBlocked = false;
        if ((flags & PackageManager.DELETE_ALL_USERS) != 0) {
            int[] users = sUserManager.getUserIds();
            for (int i = 0; i < users.length; ++i) {
                if (getBlockUninstallForUser(packageName, users[i])) {
                    uninstallBlocked = true;
                    break;
                }
            }
        } else {
            uninstallBlocked = getBlockUninstallForUser(packageName, userId);
        }
        if (uninstallBlocked) {
            try {
                observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED,
                        null);
            } catch (RemoteException re) {
            }
            return;
        }

        if (DEBUG_REMOVE) {
            Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId);
        }
        // Queue up an async operation since the package deletion may take a little while.
        mHandler.post(new Runnable() {//post消息,在消息处理方法中执行卸载应用的操作
            public void run() {
                mHandler.removeCallbacks(this);
                final int returnCode = deletePackageX(packageName, userId, flags);
                if (observer != null) {
                    try {
                        observer.onPackageDeleted(packageName, returnCode, null);//发送卸载应用的结果
                    } catch (RemoteException e) {
                        Log.i(TAG, "Observer no longer exists.");
                    } //end catch
                } //end if
            } //end run
        });
    }

deletePackage()方法检查调用者的权限后,post了一个消息。在消息的处理方法中继续执行卸载操作,这样就避免了Binder调用时间过长。实际的卸载是通过调用deletePackageX()方法完成的,如下:

    private int deletePackageX(String packageName, int userId, int flags) {
        final PackageRemovedInfo info = new PackageRemovedInfo();
        final boolean res;

        final UserHandle removeForUser = (flags & PackageManager.DELETE_ALL_USERS) != 0
                ? UserHandle.ALL : new UserHandle(userId);
        //检查userId代表的用户是否有权限删除这个应用
        if (isPackageDeviceAdmin(packageName, removeForUser.getIdentifier())) {
            Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
            return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
        }

        boolean removedForAllUsers = false;
        boolean systemUpdate = false;

        // for the uninstall-updates case and restricted profiles, remember the per-
        // userhandle installed state
        int[] allUsers;
        boolean[] perUserInstalled;
        synchronized (mPackages) {
            PackageSetting ps = mSettings.mPackages.get(packageName);//获取应用在mSettings中的包的信息
            allUsers = sUserManager.getUserIds();
            perUserInstalled = new boolean[allUsers.length];
            for (int i = 0; i < allUsers.length; i++) {//检查并记录系统中所有用户是否都安装了这个应用
                perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
            }
        }

        synchronized (mInstallLock) {
            if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
            res = deletePackageLI(packageName, removeForUser,
                    true, allUsers, perUserInstalled,
                    flags | REMOVE_CHATTY, info, true);//调用deletePackageLI方法来卸载应用
            systemUpdate = info.isRemovedPackageSystemUpdate;
            if (res && !systemUpdate && mPackages.get(packageName) == null) {
                removedForAllUsers = true;
            }
            if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
                    + " removedForAllUsers=" + removedForAllUsers);
        }

        if (res) {
            info.sendBroadcast(true, systemUpdate, removedForAllUsers);

            // If the removed package was a system update, the old system package
            // was re-enabled; we need to broadcast this information
            if (systemUpdate) {//如果卸载的应用是某个系统应用的升级包,卸载它将导致低版本的系统应用重新使用;因此需要发送广播通知这种变化
                Bundle extras = new Bundle(1);
                extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
                        ? info.removedAppId : info.uid);
                extras.putBoolean(Intent.EXTRA_REPLACING, true);

                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, null, null, null);
                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
                        extras, null, null, null);
                sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
                        null, packageName, null, null);
            }
        }
        // Force a gc here.
        Runtime.getRuntime().gc();
        // Delete the resources here after sending the broadcast to let
        // other processes clean up before deleting resources.
        if (info.args != null) {
            synchronized (mInstallLock) {
                info.args.doPostDeleteLI(true);//调用FileInstallArgs的方法做清理工作
            }
        }

        return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
    }

deletePackageX()方法收集了应用在不同用户下的安装情况后,调用deletePackageLI方法继续卸载。
如果删除的是某个系统应用的升级包,这里还会发出广播通知以前的应用又重新使用了。deletePackageLI方法如下:

    private boolean deletePackageLI(String packageName, UserHandle user,
            boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled,
            int flags, PackageRemovedInfo outInfo,
            boolean writeSettings) {
        if (packageName == null) {
            Slog.w(TAG, "Attempt to delete null packageName.");
            return false;
        }
        if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
        PackageSetting ps;
        boolean dataOnly = false;
        int removeUser = -1;
        int appId = -1;
        synchronized (mPackages) {
            ps = mSettings.mPackages.get(packageName);
            if (ps == null) {
                Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
                return false;
            }
            if ((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null
                    && user.getIdentifier() != UserHandle.USER_ALL) {
                // 如果调用者只要求卸载某个用户下的应用
                if (DEBUG_REMOVE) Slog.d(TAG, "Only deleting for single user");
                ps.setUserState(user.getIdentifier(),
                        COMPONENT_ENABLED_STATE_DEFAULT,
                        false, //installed
                        true,  //stopped
                        true,  //notLaunched
                        false, //hidden
                        null, null, null,
                        false // blockUninstall
                        );
                if (!isSystemApp(ps)) {
                    if (ps.isAnyInstalled(sUserManager.getUserIds())) {
                        // 如果还有其他用户在使用这个应用,删除应用在这个被删除用户下的数据
                        if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
                        removeUser = user.getIdentifier();
                        appId = ps.appId;
                        mSettings.writePackageRestrictionsLPr(removeUser);
                    } else {
                        // We need to set it back to 'installed' so the uninstall
                        // broadcasts will be sent correctly.没有用户使用了,全部删除应用
                        if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");
                        ps.setInstalled(true, user.getIdentifier());
                    }
                } else {
                    // 系统应用,可能别的用户还在使用它;因此,这里只清除应用在需要删除的用户目录下的数据目录;
                    if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
                    removeUser = user.getIdentifier();
                    appId = ps.appId;
                    mSettings.writePackageRestrictionsLPr(removeUser);
                }
            }
        }

        。。。。。。
        if (dataOnly) {
            // Delete application data first,先删除应用的数据
            if (DEBUG_REMOVE) Slog.d(TAG, "Removing package data only");
            removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);
            return true;
        }

        boolean ret = false;
        if (isSystemApp(ps)) {//删除系统应用
            if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name);
            // When an updated system application is deleted we delete the existing resources as well and
            // fall back to existing code in system partition
            ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled,
                    flags, outInfo, writeSettings);
        } else {//停止应用进程,删除文件
            if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name);
            // Kill application pre-emptively especially for apps on sd.
            killApplication(packageName, ps.appId, "uninstall pkg");
            ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,
                    allUserHandles, perUserInstalled,
                    outInfo, writeSettings);
        }

        return ret;
    }

deletePackageLI方法根据不同用户的安装情况来删除应用的apk文件和数据。

五、通过Intent查询组件

PMS在系统运行过程中,很重要的一项工作就是根据Intent来查询处理Intent的组件信息。处理Intent查询的接口如下:

  • queryIntentActivities():查询处理Intent的Activity列表。
  • queryIntentServices():查询处理Intent的Service列表。
  • queryIntentReceivers():查询处理Intent的Receiver列表。
  • queryIntentConentProviders():查询处理Intent的ContentProvider列表。

系统中响应某个Intent的组件可能有多个,因此,这些接口返回的是列表。查询到的组件信息都是用类ResolverInfo来表示的。Android定义了ResolveInfo类来表示所有组件。 以queryIntentActivities()为例分析查询过程。

    public List<ResolveInfo> queryIntentActivities(Intent intent,
            String resolvedType, int flags, int userId) {
        if (!sUserManager.exists(userId)) return Collections.emptyList();//检查调用接口的用户的权限
        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (intent.getSelector() != null) {
                intent = intent.getSelector();
                comp = intent.getComponent();
            }
        }

        if (comp != null) {//如果Intent中已经指定了模块和组件名称,则只会有一个匹配
            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
            final ActivityInfo ai = getActivityInfo(comp, flags, userId);//通过模块信息得到ActivityInfo
            if (ai != null) {
                final ResolveInfo ri = new ResolveInfo();
                ri.activityInfo = ai;
                list.add(ri);
            }
            return list;
        }

        // reader
        synchronized (mPackages) {
            final String pkgName = intent.getPackage();
            if (pkgName == null) {//如果intent中没有包名,则在系统所有包中查找
                List<CrossProfileIntentFilter> matchingFilters =
                        getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);//匹配所有的IntertFilter
                // Check for results that need to skip the current profile.首先检查带有SKIP_CURRENT_PROFILE标志的filter
                ResolveInfo resolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,
                        resolvedType, flags, userId);
                if (resolveInfo != null) {
                    List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
                    result.add(resolveInfo);
                    return result;
                }
                // Check for cross profile results.
                resolveInfo = queryCrossProfileIntents(
                        matchingFilters, intent, resolvedType, flags, userId);

                // Check for results in the current profile.在当前的profile下查找
                List<ResolveInfo> result = mActivities.queryIntent(
                        intent, resolvedType, flags, userId);
                if (resolveInfo != null) {
                    result.add(resolveInfo);
                    Collections.sort(result, mResolvePrioritySorter);
                }
                return result;
            }
            final PackageParser.Package pkg = mPackages.get(pkgName);
            if (pkg != null) {//如果Intent中有包名,则在指定的包中查找
                return mActivities.queryIntentForPackage(intent, resolvedType, flags,
                        pkg.activities, userId);
            }
            return new ArrayList<ResolveInfo>();
        }
    }

queryIntentActivities()方法会根据Intent中的信息来分别处理。如果Intent中有包名和Activity的信息,在调用getActivityInfo()直接返回ActivityInfo。如果只有包名,调用queryIntentForPackage方法在指定的包中查找Activity。如果包名也没有,调用queryIntent()方法来搜索所有安装包。

        下面我们再看下installd进程的理解:
Android应用管理三 — APK包的安装、卸载和优化(PackageManagerService)

    原文作者:Kitty_London
    原文地址: https://blog.csdn.net/kitty_landon/article/details/46503459
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞