Android -- PackageManagerService APK安装流程简要分析

Android — PackageManagerService APK安装流程简要分析

在Android系统下,我们一般会使用”adb install -r”命令来安装应用;此时应用会被安装到/data/app/下。这篇文章,我们就简要分析PackageManagerService安装apk的中间处理过程。

在进入PackageManager之前,我们先看下有关adb安装应用的内容。在android中,adbd以后台进程运行。当我们输入”adb install”命令时,/syste/core/adb/目录下commandline.cpp文件会被执行,其中adb_commandline()函数会接受该条指令,并进行处理,这里只看install命令的执行:

int adb_commandline(int argc, const char **argv) {
......

else if (!strcmp(argv[0], "install")) {
        if (argc < 2) return usage();
        if (_use_legacy_install()) {
            return install_app_legacy(transport_type, serial, argc, argv);
        }
        return install_app(transport_type, serial, argc, argv);
    }

......
}

这里以legacy模式为例:

static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
    static const char *const DATA_DEST = "/data/local/tmp/%s";//安装到data目录下时,会将apk先拷贝一份到该目录下
    static const char *const SD_DEST = "/sdcard/tmp/%s";//安装到SD卡上时,会将apk先拷贝一份到/sdcard/tmp/目录下;一般带参数-s
    const char* where = DATA_DEST;
    int i;
    struct stat sb;

    for (i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "-s")) {
            where = SD_DEST;
        }
    }

    // Find last APK argument.
    // All other arguments passed through verbatim.
    int last_apk = -1;
    for (i = argc - 1; i >= 0; i--) {
        const char* file = argv[i];
        const char* dot = strrchr(file, '.');
        if (dot && !strcasecmp(dot, ".apk")) {
            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
                fprintf(stderr, "Invalid APK file: %s\n", file);
                return EXIT_FAILURE;
            }

            last_apk = i;
            break;
        }
    }

    if (last_apk == -1) {
        fprintf(stderr, "Missing APK file\n");
        return EXIT_FAILURE;
    }

    int result = -1;
    std::vector<const char*> apk_file = {argv[last_apk]};
    std::string apk_dest = android::base::StringPrintf(
        where, adb_basename(argv[last_apk]).c_str());
    if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;//我们即将安装的apk文件也许会在客户机上,这里会先将该apk文件推送到系统的/data/local/tmp/目录下
    argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
    result = pm_command(transport, serial, argc, argv);//执行pm脚本,进行安装

cleanup_apk:
    delete_file(transport, serial, apk_dest);//安装过程结束后,会清掉事先拷贝的那一份apk
    return result;
}

由于我们使用adb安装的apk有可能会在客户机上,所以这里会先将apk文件拷贝一份到系统的/data/local/tmp/目录下。然后,流程会去执行pm脚本进行安装操作。手机的端的adbd程序接收到客户机发送的shell pm命令后,会开启一个shell去执行pm脚本。pm脚本的内容如下:

# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/pm.jar
exec app_process $base/bin com.android.commands.pm.Pm "$@"

该脚本在系统编译时会被打包成/system/bin/pm可执行程序,执行pm可执行程序其实就是执行这段脚本。我们知道,app_process在系统启动过程中会去启动Zygote系统进程;同时,它也可以被用来启动一些其他的普通进程,比如此时的pm。我们直接看启动pm时调用的main()函数,com.android.commands.pm.Pm::main():

    public static void main(String[] args) {
        int exitCode = 1;
        try {
            exitCode = new Pm().run(args);
        } catch (Exception e) {
            Log.e(TAG, "Error", e);
            System.err.println("Error: " + e);
            if (e instanceof RemoteException) {
                System.err.println(PM_NOT_RUNNING_ERR);
            }
        }
        System.exit(exitCode);
    }

创建Pm实例并调用它的run()接口:

    public int run(String[] args) throws RemoteException {
        boolean validCommand = false;
        if (args.length < 1) {
            return showUsage();
        }
        mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
        mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
        mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));//IPackageManager实例,通过它可以调用到PackageManagerServcie中

        if (mPm == null) {//IPackageManager实例为空,即返回
            System.err.println(PM_NOT_RUNNING_ERR);
            return 1;
        }
        mInstaller = mPm.getPackageInstaller();//IPackageInstaller实例,它会管理android中的应用安装状态

        mArgs = args;
        String op = args[0];
        mNextArg = 1;

        if ("list".equals(op)) {
            return runList();
        }

        if ("path".equals(op)) {
            return runPath();
        }

        if ("dump".equals(op)) {
            return runDump();
        }

        if ("install".equals(op)) {//此处分析的是install命令,走这条分支
            return runInstall();
        }
......
}

因为我们传入的是install命令,所以执行runInstall()函数;至此,安装过程就即将进入PackageManagerService了。

同时,我们也可以调用PackageManager::installPackage()函数安装应用,这种方式的安装与adb install的安装流程再走进PackageManagerService之后,都是一致地。

PackageManager的家族类图结构如下所示:

《Android -- PackageManagerService APK安装流程简要分析》

PackageManager的功能由ApplicationPackageManager实现,ApplicationPackageManager内部持有一个指向PackageManagerService的mPM对象来传递函数调用。当我们调用PackageManager::installPackage()时,实际调用调用ApplicationPackageManager中的实现函数:

    @Override
    public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
                               String installerPackageName) {
        installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
                installerPackageName, mContext.getUserId());
    }

    @Override
    public void installPackage(Uri packageURI, PackageInstallObserver observer,
            int flags, String installerPackageName) {
        installCommon(packageURI, observer, flags, installerPackageName, mContext.getUserId());
    }

    private void installCommon(Uri packageURI,
            PackageInstallObserver observer, int flags, String installerPackageName,
            int userId) {
        if (!"file".equals(packageURI.getScheme())) {
            throw new UnsupportedOperationException("Only file:// URIs are supported");
        }

        final String originPath = packageURI.getPath();
        try {
            mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
                    userId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

方法中传入了一个PackageInstallObserver对象,它是用户用来监听APK安装的最后结果的。PackageInstallObserver的定义如下:

public class PackageInstallObserver {
    private final IPackageInstallObserver2.Stub mBinder = new IPackageInstallObserver2.Stub() {
        @Override
        public void onUserActionRequired(Intent intent) {
            PackageInstallObserver.this.onUserActionRequired(intent);
        }

        @Override
        public void onPackageInstalled(String basePackageName, int returnCode,
                String msg, Bundle extras) {
            PackageInstallObserver.this.onPackageInstalled(basePackageName, returnCode, msg,
                    extras);
        }
    };

    /** {@hide} */
    public IPackageInstallObserver2 getBinder() {
        return mBinder;
    }

    public void onUserActionRequired(Intent intent) {
    }

    /**
     * This method will be called to report the result of the package
     * installation attempt.
     *
     * @param basePackageName Name of the package whose installation was
     *            attempted
     * @param extras If non-null, this Bundle contains extras providing
     *            additional information about an install failure. See
     *            {@link android.content.pm.PackageManager} for documentation
     *            about which extras apply to various failures; in particular
     *            the strings named EXTRA_FAILURE_*.
     * @param returnCode The numeric success or failure code indicating the
     *            basic outcome
     * @hide
     */
    public void onPackageInstalled(String basePackageName, int returnCode, String msg,
            Bundle extras) {
    }
}

其中,当apk安装结束时,系统会回调onPackageInstalled()接口通知用户当前apk安装的结果信息。

接着分析APK安装的流程,系统会调用PMS的installPackageAsUser()接口,将安装流程带入到PMS中:

    @Override
    public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, int userId) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);

        final int callingUid = Binder.getCallingUid();
        enforceCrossUserPermission(callingUid, userId,
                true /* requireFullPermission */, true /* checkShell */, "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;

        } 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) {//如果带有ISNASLL_ALL_USERS标记,则给所有用户安装
            user = UserHandle.ALL;
        } else {
            user = new UserHandle(userId);
        }

        // Only system components can circumvent runtime permissions when installing.
        if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
                && mContext.checkCallingOrSelfPermission(Manifest.permission
                .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
            throw new SecurityException("You need the "
                    + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
                    + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
        }

        final File originFile = new File(originPath);
        final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);

        final Message msg = mHandler.obtainMessage(INIT_COPY);//要发送INIT_COPY消息,开始拷贝需要安装的Apk
		
        final VerificationInfo verificationInfo = new VerificationInfo(
                null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);

	     //将安装参数信息保存到InstallParams对象中
        final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
                installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
                null /*packageAbiOverride*/, null /*grantedPermissions*/,
                null /*certificates*/);
        params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
        msg.obj = params;

        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",
                System.identityHashCode(msg.obj));
        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                System.identityHashCode(msg.obj));

        mHandler.sendMessage(msg);//发送消息到PackageHandler中
    }

首先是一些安装权限检查,之后会创建一个InstallParams实例,它里面封装了此次安装APK的各项参数;接着会发送INIT_COPY消息到Handler进行处理。

我们先总体看一下PMS应用安装过程中会涉及到的一些类型:

《Android -- PackageManagerService APK安装流程简要分析》

这些类型的作用就是封装一次应用安装过程的一些基本信息,我们只要注意它们的使用场景即可。INIT_COPY消息会触发APK文件的拷贝动作,它会由PMS::PackageHandler接收,而PackageHandler在PMS初始化时会被创建。PackageHandler主要负责这些APK安装消息的接收处理。我们先看INIT_COPY消息的处理过程:

                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;//获取Apk安装参数
                    int idx = mPendingInstalls.size();//mPendingInstalls保存所有的需要安装的APk的安装信息
                    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) {//如果没有绑定DefaultContainerService服务;服务连接成功后,会置为true
                        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.
                        if (!connectToService()) {//异步过程.去绑定DefaultContainerService服务,绑定失败,需要报告错误信息;绑定成功后,会发送MCS_BOUND消息
                            Slog.e(TAG, "Failed to bind to media container service");
                            params.serviceError();
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                    System.identityHashCode(mHandler));
                            if (params.traceMethod != null) {
                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
                                        params.traceCookie);
                            }
                            return;
                        } else {//绑定服务成功后,将当前的安装参数请求保存到mPendingInstalls
                            // Once we bind to the service, the first
                            // pending request will be processed.
                            mPendingInstalls.add(idx, params);
                        }
                    } else {
                        mPendingInstalls.add(idx, params);//服务已经绑定,也会将安装信息保存到mPendingInstalls中
                        // 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;
                }

mPendingInstalls是PackageHandler的一个成员,它保存所有的APK安装的InstallParams对象。mBound标识当前有没有绑定DefaultContainerService服务,之后的安装流程会调用它的一些方法。绑定DCS服务的处理由PackageHandler::connectToService()函数提供:

    static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
            DEFAULT_CONTAINER_PACKAGE,
            "com.android.defcontainer.DefaultContainerService");

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

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

        private boolean connectToService() {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
                    " DefaultContainerService");
            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
            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;
        }

如果服务绑定成功,mBound会置为true,并会发送MCS_BOUND消息,并附带DCS服务的Binder实例发送给PackageHandler。

接着看MCS_BOUND消息的处理:

                case MCS_BOUND: {
                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
                    if (msg.obj != null) {
                        mContainerService = (IMediaContainerService) msg.obj;//DefaultContainerService服务的代理
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                                System.identityHashCode(mHandler));
                    }
                    if (mContainerService == null) {
                        if (!mBound) {//如果服务没有连接成功,则需要报告错误
                            // Something seriously wrong since we are not bound and we are not
                            // waiting for connection. Bail out.
                            Slog.e(TAG, "Cannot bind to media container service");
                            for (HandlerParams params : mPendingInstalls) {
                                // Indicate service bind 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);
                                }
                                return;
                            }
                            mPendingInstalls.clear();//情况mPendingInstalls
                        } else {
                            Slog.w(TAG, "Waiting to connect to media container service");
                        }
                    } else if (mPendingInstalls.size() > 0) {//DefaultContainerService服务连接正常
                        HandlerParams params = mPendingInstalls.get(0);//从首部拿出需要执行的安装参数信息
                        if (params != null) {
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                    System.identityHashCode(params));
                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                            if (params.startCopy()) {//调用HandlerParrams接口,去执行apk的拷贝工作;此处是调用HandlerParrams::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首部内容,因为我们是从首部开始执行的
                                    mPendingInstalls.remove(0);
                                }
                                if (mPendingInstalls.size() == 0) {//如果mPendingInstalls已经没有内容,说明安装任务已经全部执行完毕,则会延迟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 {//否则,会再次发送MCS_BOUND消息,处理下一个安装请求
                                    // There are more pending requests in queue.
                                    // Just post MCS_BOUND message to trigger processing
                                    // of next pending install.
                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
                                            "Posting MCS_BOUND for next work");
                                    mHandler.sendEmptyMessage(MCS_BOUND);//发送消息,处理下一个安装请求
                                }
                            }
                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                        }
                    } else {
                        // Should never happen ideally.
                        Slog.w(TAG, "Empty queue");
                    }
                    break;
                }

mContainerService对象保存了DefaultContainerService服务的Binder实例,它将被用来调用一些该服务中提供的方法。如果该实例为空,则表明服务连接异常,则需要对外报告错误,并清空mPendingInstalls集合;如果非空,则要处理APK的安装请求:

  • 从mPendingInstalls首部取出要处理的安装参数对象,并调用InstallParams::startCopy()函数,开始进行APK的拷贝工作
  • 如果拷贝工作完成,则会移除mPendingInstalls首部的对象
  • 如果此时mPendingInstalls队列为空,表明所有的请求已经处理完了;则会通过发送MCS_UNBIND消息,延迟10s去断开与DCS服务的连接
  • 如果此时mPendingInstalls对比不为空,表明当前还有安装请求需要处理,则会再次发送MCS_BOUND消息;进行新一轮的安装处理流程

因为传入的安装参数对象是InstallParams,根据之前的图示,我们直接看它父类的HandlerParams::startCopy()函数:

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

                if (++mRetries > MAX_RETRIES) {//会尝试安装4次,如果4次都没有安装成功,则会退出
                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                    mHandler.sendEmptyMessage(MCS_GIVE_UP);//尝试4次后,都没有安装成功,则发送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;
        }

HandlerParams::startCopy()为HandlerParams的子类所共有。首先一次apk的安装操作总共会尝试四次,如果四次都安装失败,则会发送MCS_GIVE_UP消息,放弃这次安装请求,并调用子类实现的handleServiceError()处理错误,然后直接返回;否则,调用子类实现的handleStartCopy()函数进程copy流程。handleStartCopy()处理成功后,还会调用子类实现的handleReturnCode()处理最后的结果。我们看InstallParams::handleStartCopy()的实现:

        /*
         * Invoke remote method to get package information and install
         * location values. Override install location based on default
         * policy if needed and then create install arguments based
         * on the install location.
         */
        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;
            final boolean ephemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 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 if (onSd && ephemeral) {//此处与上述类似
                Slog.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            } else {
                pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                        packageAbiOverride);//获取安装包包含有应用信息的PacageInfoLite对象

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

                /*
                 * 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);
                    final long lowThreshold = storage.getStorageLowBytes(
                            Environment.getDataDirectory());

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

                    try {
                        mInstaller.freeCache(null, sizeBytes + lowThreshold);
                        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.
                     */
                    if (pkgLite.recommendedInstallLocation
                            == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                        pkgLite.recommendedInstallLocation
                            = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
                    }
                }
            }

            if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果该标志位依然是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.
                    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
                        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_EPHEMERAL) {
                                Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
                            }
                            installFlags |= PackageManager.INSTALL_EPHEMERAL;
                            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;
                        }
                    }
                }
            }

            final InstallArgs args = createInstallArgs(this);//函数中会有分支处理,这里考虑FileInstallArgs实例创建情况,并会保存一份到InstallParams::mArgs
            mArgs = args;

            if (ret == PackageManager.INSTALL_SUCCEEDED) {//如果该标志位依然是INSTALL_SUCCEEDED,则说明前面的校验都通过
                // TODO: http://b/22976637
                // Apps installed for "all" users use the device owner to verify the app
                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.
                 */
                final int requiredUid = mRequiredVerifierPackage == null ? -1
                        : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
                                verifierUser.getIdentifier());
				//if部分是一段执行应用校验的代码,如果需要校验,则通过向系统中所有带有校验功能的组件发送Intent.ACTION_PACKAGE_NEEDS_VERIFICATION广播来完成
                if (!origin.existing && requiredUid != -1
                        && isVerificationEnabled(verifierUser.getIdentifier(), installFlags)) {
                    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);
                    verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

                    // Query all live verifiers based on current user state
                    final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
                            PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());

                    if (DEBUG_VERIFY) {
                        Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
                                + verification.toString() + " with " + pkgLite.verifiers.length
                                + " optional verifiers");
                    }

                    final int verificationId = mPendingVerificationToken++;

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);

                    verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
                            installerPackageName);

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

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

                    final PackageVerificationState verificationState = new PackageVerificationState(
                            requiredUid, args);

                    mPendingVerification.append(verificationId, verificationState);

                    final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                            receivers, verificationState);

                    /*
                     * 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);

                                final Intent sufficientIntent = new Intent(verification);
                                sufficientIntent.setComponent(verifierComponent);
                                mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
                            }
                        }
                    }

                    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.
                         */
                        verification.setComponent(requiredVerifierComponent);
                        mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
                                android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
                                new BroadcastReceiver() {
                                    @Override
                                    public void onReceive(Context context, Intent intent) {
                                        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 {//不需要校验,则调用FileInstallArgs::copyApk()继续后续的处理
                    /*
                     * No package verification is enabled, so immediately start
                     * the remote call to initiate copy using temporary file.
                     */
                    ret = args.copyApk(mContainerService, true);
                }
            }

            mRet = ret;
        }

这里总结下这段代码处理:

  • 首先会进行一些安装标志的判断
  • 调用DCS::getMinimalPackageInfo()方法获取该apk安装需要的大小及其他信息,信息会封装到PackageInfoLite对象中
  • 如果检测到当前的目录下的大小不足以安装应用,还回去进行cache的清理工作
  • 随后会以当前的InstallParams实例,创建FileInstallArgs对象,并保存一份到InstallParams对象的mArgs字段中
  • 后续是一段组件校验工作,这里不做分析
  • 最后FileInstallArgs::copyApk()函数,进行下一步处理

接着看FileInstallArgs::copyApk()函数:

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

            try {
                final boolean isEphemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
                final File tempDir =
                        mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);//通过PackageInstallService在/data/app/下生成临时文件
                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());
                    }
                }
            };

            int ret = PackageManager.INSTALL_SUCCEEDED;

			//使用DefaultContainerService::copyPackage()方法执行apk文件的复制
            ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
            if (ret != PackageManager.INSTALL_SUCCEEDED) {
                Slog.e(TAG, "Failed to copy package");
                return ret;
            }

			//安装应用中存在的native动态库,主要是从Apk打包文件中将它们提取出来放置
            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;
        }

这里的处理有如下几个:

  • 通过PackageInstallService为要安装的apk在/data/app/下生成一个零时文件tempDir,它的命名并不以.apk结尾
  • 为该tempDir创建IParcelFileDescriptorFactory文件描述符,它可以在进程间传递
  • 调用DefaultContainerService::copyPackage()方法执行apk临时文件的复制
  • 最后再将apk中包含的一些库文件提取出来,放置到对应的lib/目录下

生成apk临时文件的调用是PackageInstallService::allocateStageDirLegacy():

    @Deprecated
    public File allocateStageDirLegacy(String volumeUuid, boolean isEphemeral) throws IOException {
        synchronized (mSessions) {
            try {
                final int sessionId = allocateSessionIdLocked();
                mLegacySessions.put(sessionId, true);
                final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
                prepareStageDir(stageDir);
                return stageDir;
            } catch (IllegalStateException e) {
                throw new IOException(e);
            }
        }
    }

    private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
        final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
        return new File(stagingDir, "vmdl" + sessionId + ".tmp");
    }

临时文件的名称格式大致是:’vmdl-随机数.tmp’的形式。

如果一切过程都正常,至此,APK安装的第一部分的工做:APK文件的拷贝,就结束了;根据前面的流程,最后会调用InstallParams::handleReturnCode()执行返回结果的处理:

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

因为InstallParams::mArgs我们之前赋值过,所以肯定不为空;继续调用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.setReturnCode(currentStatus);
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = null;
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//如果之前的处理顺利完成
                    args.doPreInstall(res.returnCode);
                    synchronized (mInstallLock) {
                        installPackageTracedLI(args, res);//则需要去解析、装载应用
                    }
                    args.doPostInstall(res.returnCode, res.uid);
                }

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

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

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

                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
                    // Pass responsibility to the Backup Manager.  It will perform a
                    // restore if appropriate, then pass responsibility back to the
                    // Package Manager to run the post-install observer callbacks
                    // and broadcasts.
                    IBackupManager bm = IBackupManager.Stub.asInterface(
                            ServiceManager.getService(Context.BACKUP_SERVICE));
                    if (bm != null) {
                        if (DEBUG_INSTALL) Log.v(TAG, "token " + token
                                + " to BM for possible restore");
                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
                        try {
                            // TODO: http://b/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;
                    }
                }

                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);//此处发送POST_INSTALL消息,继续处理流程
                    mHandler.sendMessage(msg);
                }
            }
        });
    }

函数内会调用FileInstallArgs的doPreInstall()/doPostInstall()函数进行一些清理工作。其中PMS::installPackageTracedLI()函数的主要功能就是将当前安装的apk加入到它的管理体系中,以便之后统一管理;特殊的,该函数内部会调用FileInstallArgs::doReanme()函数将之前的apk备份文件重命名。具体的实现是扫描APK的过程,这部分之前已经有介绍过。略去之后的备份工作后,最后会发送POST_INSTALL消息,依旧是PackageHandler处理:

case POST_INSTALL: {//应用安装的收尾处理:主要动作是发送广播,通知系统中其他应用,开始某些处理工作:如果Launcher添加应用图标等
                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);

                    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;

                        final boolean grantPermissions = (args.installFlags
                                & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
                        final boolean killApp = (args.installFlags
                                & PackageManager.INSTALL_DONT_KILL_APP) == 0;
                        final String[] grantedPermissions = args.installGrantPermissions;

                        // Handle the parent package
                        handlePackagePostInstall(parentRes, grantPermissions, killApp,
                                grantedPermissions, didRestore, args.installerPackageName,
                                args.observer);//各种广播的发送处理

                        // Handle the child packages
                        final int childCount = (parentRes.addedChildPackages != null)
                                ? parentRes.addedChildPackages.size() : 0;
                        for (int i = 0; i < childCount; i++) {
                            PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
                            handlePackagePostInstall(childRes, grantPermissions, killApp,
                                    grantedPermissions, false, 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;

由于需要安装的apk文件已经拷贝到了系统中,并且PMS也已经对它进行了统一管理;到此,APK的安装工作就基本完成了。但是,此时系统其它组件并不知道此时有新的APK安装进了系统中,所以这里需要发送一些广播给感兴趣的接收者,通知它们当前有新的apk安装完成了。这一部分最明显的就是Launcher了,我们安装apk后,Launcher上要添加图标,就是根据这部分内容来的。发送广播的主要函数是handlePackagePostInstall(),它的实现如下:

    private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
            boolean killApp, String[] grantedPermissions,
            boolean launchedForRestore, String installerPackage,
            IPackageInstallObserver2 installObserver) {
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
            // Send the removed broadcasts
            if (res.removedInfo != null) {
                res.removedInfo.sendPackageRemovedBroadcasts(killApp);
            }

            // Now that we successfully installed the package, grant runtime
            // permissions if requested before broadcasting the install.
            if (grantPermissions && res.pkg.applicationInfo.targetSdkVersion
                    >= Build.VERSION_CODES.M) {
                grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
            }

            final boolean update = res.removedInfo != null
                    && res.removedInfo.removedPackage != 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.
            if (res.pkg.parentPackage != null) {
                synchronized (mPackages) {
                    grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(res.pkg);
                }
            }

            synchronized (mPackages) {
                mEphemeralApplicationRegistry.onPackageInstalledLPw(res.pkg);
            }

            final String packageName = res.pkg.applicationInfo.packageName;
            Bundle extras = new Bundle(1);
            extras.putInt(Intent.EXTRA_UID, res.uid);

            // Determine the set of users who are adding this package for
            // the first time vs. those who are seeing an update.
            int[] firstUsers = EMPTY_INT_ARRAY;
            int[] updateUsers = EMPTY_INT_ARRAY;
            if (res.origUsers == null || res.origUsers.length == 0) {
                firstUsers = res.newUsers;
            } else {
                for (int newUser : res.newUsers) {
                    boolean isNew = true;
                    for (int origUser : res.origUsers) {
                        if (origUser == newUser) {
                            isNew = false;
                            break;
                        }
                    }
                    if (isNew) {
                        firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
                    } else {
                        updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
                    }
                }
            }

            // Send installed broadcasts if the install/update is not ephemeral
            if (!isEphemeral(res.pkg)) {
                mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);

                // Send added for users that see the package for the first time
                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, 0 /*flags*/, null /*targetPackage*/,
                        null /*finishedReceiver*/, firstUsers);//首先要发送Intent.ACTION_PACKAGE_ADDED广播,表明系统中有新的apk被安装了

                // Send added for users that don't see the package for the first time
                if (update) {
                    extras.putBoolean(Intent.EXTRA_REPLACING, true);
                }
                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, 0 /*flags*/, null /*targetPackage*/,
                        null /*finishedReceiver*/, updateUsers);

                // Send replaced for users that don't see the package for the first time
                if (update) {//如果当前安装是升级,则还需要发送更多的广播:Intent.ACTION_PACKAGE_REPLACED/Intent.ACTION_MY_PACKAGE_REPLACED
                    sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                            packageName, extras, 0 /*flags*/,
                            null /*targetPackage*/, null /*finishedReceiver*/,
                            updateUsers);
                    sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                            null /*package*/, null /*extras*/, 0 /*flags*/,
                            packageName /*targetPackage*/,
                            null /*finishedReceiver*/, updateUsers);
                } else if (launchedForRestore && !isSystemApp(res.pkg)) {
                    // First-install and we did a restore, so we're responsible for the
                    // first-launch broadcast.
                    if (DEBUG_BACKUP) {
                        Slog.i(TAG, "Post-restore of " + packageName
                                + " sending FIRST_LAUNCH in " + Arrays.toString(firstUsers));
                    }
                    sendFirstLaunchBroadcast(packageName, installerPackage, firstUsers);
                }

                // 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)) {//如果安装的是foreword lock应用或是安装在SD卡上的应用,也有相关的广播要发送
                    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
            if (firstUsers != null && firstUsers.length > 0) {
                synchronized (mPackages) {
                    for (int userId : firstUsers) {
                        // 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.
                        if (packageIsBrowser(packageName, userId)) {
                            mSettings.setDefaultBrowserPackageNameLPw(null, userId);
                        }

                        // We may also need to apply pending (restored) runtime
                        // permission grants within these users.
                        mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
                    }
                }
            }

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

            // Force a gc to clear up things
            Runtime.getRuntime().gc();

            // 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) {
                synchronized (mInstallLock) {
                    res.removedInfo.args.doPostDeleteLI(true);
                }
            }
        }

        // If someone is watching installs - notify them
        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:通知系统其它组件,当前有新的apk安装成功了,例如Launcher;Launcher再去向PMS查询所有带有主Activity的应用信息,更新显示。

最后再通过用户注册的Observer回调对象将安装结果回调给监听者。

分析到这里,一个APK的安装过程就简要地分析完成了。

http://m.blog.csdn.net/csdn_of_coder/article/details/74025409

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