Framework篇 - APK 安装流程简介

本文源代码基于 Android 7.0。 

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

 

目录:

  1. 安装流程图
  2. adb 方式安装 APK
  3. PackageManager 安装 APK

 

 

1. 安装流程图

 

 

2. adb 方式安装 APK

在进入 PackageManager 之前,我们先看下有关 adb 安装应用的内容。在 Android 中,adbd 以后台进程运行 (init 进程解析 init.rc 生成的进程,Installer 中真正干活的进程)。

当我们输入 "adb install" 命令时,/system/core/adb/ 目录下 commandline.cpp 文件会被执行,其中 adb_commandline() 函数会接受该条指令,并进行处理,这里只看 install 命令的执行:

else if (!strcmp(argv[0], "install")) {
        if (argc < 2) return usage();
        if (_use_legacy_install()) {
            // 安装应用(legacy模式)
            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());
    // 我们即将安装的 apk 文件也许会在客户机上, 这里会先将该apk文件推送到系统的 /data/local/tmp/目录下
    if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;
    argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
    // 执行 pm 脚本, 进行安装
    result = pm_command(transport, serial, argc, argv);

cleanup_apk:
    // 安装过程结束后,会清掉事先拷贝的那一份apk
    delete_file(transport, serial, apk_dest);
    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));
        // IPackageManager实例,通过它可以调用到PackageManagerServcie中,就是binder的客户端
        mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
 
        // IPackageManager实例为空,即返回
        if (mPm == null) {
            System.err.println(PM_NOT_RUNNING_ERR);
            return 1;
        }
        // IPackageInstaller实例,它会管理android中的应用安装状态
        mInstaller = mPm.getPackageInstaller();
 
        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 之后,都是一样的。

 

 

3. PackageManager 安装 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) {
    }

    public void onPackageInstalled(String basePackageName, int returnCode, String msg,
            Bundle extras) {
    }
}

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

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

    @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 进行处理。

这些类型的作用就是封装一次应用安装过程的一些基本信息,我们只要注意它们的使用场景即可。INIT_COPY 消息会触发 APK 文件的拷贝动作,它会由 PMS::PackageHandler 接收,而 PackageHandler 在 PkMS 初始化时会被创建。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() 的实现:

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/ 目录下。
    @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 文件已经拷贝到了系统中,并且 PKMS 也已经对它进行了统一管理,到此 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);
     
                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 (packageIsBrowser(packageName, userId)) {
                                mSettings.setDefaultBrowserPackageNameLPw(null, userId);
                            }
     
                            mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
                        }
                    }
                }
     
                EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
                        getUnknownSourcesSettings());
     
                Runtime.getRuntime().gc();
     
                if (res.removedInfo != null && res.removedInfo.args != null) {
                    synchronized (mInstallLock) {
                        res.removedInfo.args.doPostDeleteLI(true);
                    }
                }
            }
     
            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 再去向 PKMS 查询所有带有主 Activity 的应用信息,更新显示。最后再通过用户注册的 Observer 回调对象将安装结果回调给监听者。

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

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: robotframework-ride是一个基于Python编写的自动化测试工具,它可以帮助测试人员快速创建和运行自动化测试用例。安装robotframework-ride需要先安装Python和pip,然后使用pip命令安装robotframework-ride。具体步骤如下: 1. 安装Python:从Python官网下载并安装Python,建议安装最新版本的Python。 2. 安装pip:pip是Python的包管理工具,可以使用pip安装和管理Python包。在安装Python时,pip已经被自动安装了。可以通过运行pip --version命令来检查pip是否已经安装。 3. 安装robotframework-ride:使用pip命令安装robotframework-ride,可以使用以下命令: pip install robotframework-ride 4. 启动robotframework-ride:安装完成后,可以通过运行ride.py文件启动robotframework-ride。可以在命令行中输入以下命令: python -m robotide.__init__ 或者直接双击ride.py文件启动。 安装完成后,就可以使用robotframework-ride创建和运行自动化测试用例了。 ### 回答2: Robot Framework是一个通用的自动化测试框架,可以用来测试各种应用程序和Web应用程序。RIDE(Robot Framework Integrated Development Environment)是一个基于Python的集成开发环境,使用RIDE工具可以大大减轻测试用例的编写和管理负担。RIDE支持使用Python或Robot Framework的打印输出,实时编辑测试数据和测试套件,以便于开发人员和测试人员开发和维护测试用例。 安装RIDE有几种不同的方法,可以选择最适合你的环境的方法。以下是安装RIDE的步骤: 1. 安装Python:在安装RIDE之前,需要在计算机上安装Python 2.7版本或Python 3.X版本,根据需要选择版本。 2. 安装wxPython:RIDE使用wxPython提供GUI,因此需要安装wxPython库。可以在官网下载:https://www.wxpython.org/pages/downloads/。根据需要选择相应的版本,下载完之后直接运行安装程序进行安装即可。 3. 安装Robot Framework:在安装RIDE之前,需要安装Robot Framework。可以使用pip命令进行安装。在命令提示符中输入以下命令即可:pip install robotframework 4. 安装RIDE:在安装完上述软件之后,就可以开始安装RIDE了。可以从官方网站下载RIDE,下载地址为:http://code.google.com/p/robotframework-ride/downloads/list。在下载完成之后,解压缩文件并运行RIDE.bat文件即可启动RIDE。这里需要注意的是,必须使用管理员身份运行RIDE.bat。 5. 配置RIDE:在RIDE启动后,需要进行一些配置。首先,需要配置Robot Framework的路径。在菜单中选择“Tools” > “Preferences”,然后在“Plugins”选项卡中选择“RobotFramework”,在“Executable”字段中输入Robot Framework安装目录的完整路径。然后,可以选择“Editor”选项卡来配置编辑器首选项。此外,还可以在其他选项卡中配置更多选项,如自动保存机制等。 以上就是Robot Framework- RIDE安装的步骤,根据这些步骤进行安装,可以使您简单高效地进行测试用例的管理和编写,提交测试工作效率。 ### 回答3: Robot Framework是一种通用的自动化测试框架,它支持各种不同类型的测试,包括Web、移动、API等。Robot Framework的优点在于它可以轻松地创建可读性强、易于维护的测试用例。 同时,Robot Framework也提供了许多工具来简化测试执行,其中一个常用的工具就是RIDE。RIDE是Robot Framework的官方开发IDE,它提供了一个用户友好的界面,使得创建、编辑和运行测试用例变得更加容易。 下面我们来看一下如何安装RIDE: 1. 安装Python 首先需要安装Python 2.7.x 版本的解释器,请从Python官方网站 https://www.python.org/downloads/ 下载Python 2.7.x版本的32位或64位安装程序,根据自己的操作系统和PC硬件配置选择对应的版本。 2. 安装wxPython RIDE使用wxPython实现了它的用户界面。你需要安装wxPython来运行RIDE。可以使用Python的包管理器pip来安装wxPython,如下: 打开控制台并执行以下命令: pip install wxPython 3. 安装Robot Framework和RIDE 接下来我们需要安装Robot Framework和RIDE。同样可以使用pip命令管理器完成安装。在控制台输入以下命令: pip install robotframework pip install robotframework-ride 4. 运行RIDE 安装完成后,在文件资源管理器中定位到安装目录,双击‘ride.py’文件运行RIDE。如果RIDE成功启动,你将会看到RIDE的主界面。 5. 创建测试用例 点击‘Create a new test case file’按钮,输入文件名并以“.txt”为文件扩展名。文件将保存在你选择的路径下。使用文本编辑器的语法,你可以轻松地创建测试用例。 以上就是Robot Framework-RIDE的安装过程,通过这教程,你应该可以轻松地完成一个新的测试项目并开始优化你的测试流程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值