• android 9 adb安装过程学习(一)


    参考资料PMS 第 7 篇 - 通过 pm 指令分析 Install 过程

    一、前期知识准备

    1.1 包管理机制

    所谓包,其实是一种文件格式,比如apk包、jar包等。包管理者一个职能就是识别不同的包,维护这些包的信息。当有一个新的包进入或离开Android世界,都需要向包管理者申报一下,其他管理部分要获取包的具体信息,也都需要向包管理者申请。包管理机制的核心是PackageManagerService(下文称PMS),它负责对包进行管理。

    1.2 关注点

    Android P 上采用类似 socket 的方式与 server 端通信完成安装,其中Session是重点
    其中有如下几个点是我们要重点关注的如下:

    • PackageInstaller:
      根据官方文档,PackageInstaller 提供了安装、更新以及卸载等功能,其中包括单 APK 和多 APK 安装。
      具体的安装行为是通过 PackageInstaller 内部的 Session 完成的。所有的应用都有权限创建这个 Session,但是可能会需要用户的确认才能完成安装(权限不足)。
    • Session:
      创建 Session 可以为其指定参数 SessionParams,其中一个作用就是要全部替换还是局部替换 MODE_FULL_INSTALL 和 MODE_INHERIT_EXISTING

    1.3 如何安装

    通过 IO 流的方式向 Session 内输送 apk 数据。具体代码可以看下文。需要注意的是,PackageInsatller 对于安装结果回调没有采用普通的函数回调,而是采用 Intent 的方式完成回调,比如 广播等(可以参考下面两个实例)。

    apk的安装方法

    1. 开机过程中安装:系统在每次开机会安装系统应用
    2. adb工具安装:adb命令安装apk
    3. 手动安装:平时下载的apk,通过系统安装器PackageInstaller(它是系统内置的应用程序,用于安装和卸载应用程序)来安装apk,是有安装界面的
    4. 商店应用安装:商店上安装app,没有安装界面

    二、代码分析

    adb inatsll ***.apk 命令对应的代码位置:system/core/adb/commandline.cpp

    int adb_commandline(int argc, const char** argv) {
    	//...各种参数输入的处理
    
        /* adb_connect() commands */
        if (!strcmp(argv[0], "devices")) {
    		//...
        }
        else if (!strcmp(argv[0], "connect")) {
    		//..
        }
        else if (!strcmp(argv[0], "disconnect")) {
    		//...
        }
        else if (!strcmp(argv[0], "emu")) {
            //...
        }
        else if (!strcmp(argv[0], "shell")) {
            //...
        }
        else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
    		//...
        }
        else if (!strcmp(argv[0], "kill-server")) {
            return adb_kill_server() ? 0 : 1;
        }
        else if (!strcmp(argv[0], "sideload")) {
    		//...
        } else if (!strcmp(argv[0], "tcpip")) {
    		//...
        }
        else if (!strcmp(argv[0], "remount") ||
    		//...
        } else if (!strcmp(argv[0], "root") || !strcmp(argv[0], "unroot")) {
            return adb_root(argv[0]) ? 0 : 1;
        } else if (!strcmp(argv[0], "bugreport")) {
    		//...
        } else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
    		//...
        }
        /* do_sync_*() commands */
        else if (!strcmp(argv[0], "ls")) {
    		//...
        }
        else if (!strcmp(argv[0], "push")) {
    		//...
        }
        else if (!strcmp(argv[0], "pull")) {
    		//...
        }
        else if (!strcmp(argv[0], "install")) {
            if (argc < 2) return syntax_error("install requires an argument");
            if (_use_legacy_install()) {		//android 9使用旧的pm install
                return install_app_legacy(argc, argv);
            }	//如果支持FeatureCmd,那就调用install_app
            return install_app(argc, argv);
        }
        else if (!strcmp(argv[0], "install-multiple")) {
    		//...
    	} 		//...
    	else {
    		//...
    	}
    
        syntax_error("unknown command %s", argv[0]);
        return 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    这里看到:

    • 如果支持 cmd 命令的情况下,会调用 install_app;
    • 如果不支持,执行 install_app_legacy 方法!

    2.1 cmd install - 支持cmd命令

    commandline::install_app
    static int install_app(int argc, const char** argv) {
        // The last argument must be the APK file
        const char* file = argv[argc - 1];
        if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
            return syntax_error("filename doesn't end .apk: %s", file);
        }
    
        struct stat sb;
        if (stat(file, &sb) == -1) {
            fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno));
            return 1;
        }
    	//打开apk文件,获取localFD的文件描述符
        int localFd = adb_open(file, O_RDONLY);
        if (localFd < 0) {
            fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
            return 1;
        }
    	//【1】使用 cmd package 命令!
        std::string error;
        std::string cmd = "exec:cmd package";
    
        // don't copy the APK name, but, copy the rest of the arguments as-is
        while (argc-- > 1) {
            cmd += " " + escape_arg(std::string(*argv++));
        }
    
        // add size parameter [required for streaming installs]
        // do last to override any user specified value
        cmd += " " + android::base::StringPrintf("-S %" PRIu64, static_cast<uint64_t>(sb.st_size));
    	//使用连接到设备上的adb服务,获取远程描述符
        int remoteFd = adb_connect(cmd, &error);
        if (remoteFd < 0) {
            fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
            adb_close(localFd);
            return 1;
        }
    	//这里只是把文件复制过去,并没有进行安装
        char buf[BUFSIZ];
        copy_to_file(localFd, remoteFd);			
        read_status_line(remoteFd, buf, sizeof(buf));	//读取复制结果
    
        adb_close(localFd);
        adb_close(remoteFd);
    
        if (!strncmp("Success", buf, 7)) {
            fputs(buf, stdout);
            return 0;
        }
        fprintf(stderr, "adb: failed to install %s: %s", file, buf);
        return 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    需要注意的是,这段代码中的实际应用程序的安装操作并没有完成,只是将文件内容从本地复制到了远程。实际的安装步骤可能在后续的代码中执行。

    2.2 pm install - 不支持 cmd 指令

    当使用adb install时,在android 9 的情况下会使用旧的安装方式,进行安装。回到用install_app_legacy(),最终调用pm_command

    static int install_app_legacy(int argc, const char** argv) {
    	// 此时我们需要先将 apk 将拷贝到手机的指定目录下!
        //【1】如果是要安装到内部存储,目标路径是 DATA_DEST,如果是存储则是 SD_DEST!
    	static const char *const DATA_DEST = "/data/local/tmp/%s";
        static const char *const SD_DEST = "/sdcard/tmp/%s";
        const char* where = DATA_DEST;
    	//【2】如果 adb 指令设置了 -s 参数,那就安装到外置存储,默认是内置存储!
        for (int i = 1; i < argc; i++) {
            if (!strcmp(argv[i], "-s")) {
                where = SD_DEST;
            }
        }
    
    	//【3】判断是否有 apk 文件参数!
        int result = -1;
        std::vector<const char*> apk_file = {argv[last_apk]};
        //【4】计算目标位置,将要安装的 apk 拷贝到目标缓存位置
        // 同时将 adb 命令的最后一个参数改为 apk 拷贝后的目标缓存位置!
        // 目标位置:/data/local/tmp/name.apk!
        std::string apk_dest = android::base::StringPrintf(
            where, android::base::Basename(argv[last_apk]).c_str());
        // do_sync_push 将此 apk 文件传输到目标路径,失败的话将跳转到 clenaup_apk
        if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk;
        // 设置新位置!
        argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
        //执行安装
        result = pm_command(argc, argv);
    
    cleanup_apk:
    // 删除目标缓存 apk 文件,PMS 会把该 apk 拷贝到 /data/app 目录下,所以这个缓存中的 apk 没用了!
        delete_file(apk_dest);
        return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    comandline::pm_command

    static int pm_command(int argc, const char** argv) {
    	// 我们看到,这里会将 adb install 命令和参数,转为 pm 指令!
        std::string cmd = "pm";
    
        while (argc-- > 0) {
            cmd += " " + escape_arg(*argv++);
        }
    	// 继续调用 send_shell_command 方法!
        return send_shell_command(cmd, false);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    commandline::send_shell_command

    int send_shell_command(const std::string& command, bool disable_shell_protocol,
                           StandardStreamsCallbackInterface* callback) {
        int fd;
        bool use_shell_protocol = false;
    
        while (true) {
            bool attempt_connection = true;
    
            // 使用 shell protocol
            if (!disable_shell_protocol) {
                FeatureSet features;
                std::string error;
                if (adb_get_feature_set(&features, &error)) {
                	// 如果定义了 feature,则替换 shell protocol!
                    use_shell_protocol = CanUseFeature(features, kFeatureShell2);
                } else {
                    // Device was unreachable.
                    attempt_connection = false;
                }
            }
    
            if (attempt_connection) {
                std::string error;
                // 此时 command 中携带的就是以 pm 开头的命令
                std::string service_string = ShellServiceString(use_shell_protocol, "", command);
    			// 向 shell protocol 发送命令
                fd = adb_connect(service_string, &error);
                if (fd >= 0) {
                    break;
                }
            }
    
            fprintf(stderr, "- waiting for device -\n");
            if (!wait_for_device("wait-for-device")) {
                return 1;
            }
        }
    	// 处理命令执行结果!
        int exit_code = read_and_dump(fd, use_shell_protocol, callback);
    
        if (adb_close(fd) < 0) {
            PLOG(ERROR) << "failure closing FD " << fd;
        }
    
        return exit_code;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    到这里,我们知道,最后其实是向 shell 服务发送 pm 命令,触发 apk 的安装!

    三、pm install

    cmd 的调用上面已经分析了,其实和 pm install 没有区别!
    这里我们来看下 pm 命令的主要用法,通过 pm install 继续分析安装:

    usage: pm path [--user USER_ID] PACKAGE
           pm dump PACKAGE
           pm install [-lrtsfd] [-i PACKAGE] [--user USER_ID] [PATH]
           pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]
                   [--install-location 0/1/2]
                   [--force-uuid internal|UUID]
           pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]
           pm install-commit SESSION_ID
           pm install-abandon SESSION_ID
           pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE
           pm set-installer PACKAGE INSTALLER
           pm move-package PACKAGE [internal|UUID]
           pm move-primary-storage [internal|UUID]
           pm clear [--user USER_ID] PACKAGE
           pm enable [--user USER_ID] PACKAGE_OR_COMPONENT
           pm disable [--user USER_ID] PACKAGE_OR_COMPONENT
           pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT
           pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT
           pm default-state [--user USER_ID] PACKAGE_OR_COMPONENT
           pm set-user-restriction [--user USER_ID] RESTRICTION VALUE
           pm hide [--user USER_ID] PACKAGE_OR_COMPONENT
           pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT
           pm grant [--user USER_ID] PACKAGE PERMISSION
           pm revoke [--user USER_ID] PACKAGE PERMISSION
           pm reset-permissions
           pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}
           pm get-app-link [--user USER_ID] PACKAGE
           pm set-install-location [0/auto] [1/internal] [2/external]
           pm get-install-location
           pm set-permission-enforced PERMISSION [true|false]
           pm trim-caches DESIRED_FREE_SPACE [internal|UUID]
           pm create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral] [--guest] USER_NAME
           pm remove-user USER_ID
           pm get-max-users
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    pm 命令的源码位于 frameworks/base/cmds/pm 中,我们直接去看下目录结构:

    chen@ubuntu:~/Mygit/Android$ ls frameworks/base/cmds/pm/
    Android.mk              MODULE_LICENSE_APACHE2  NOTICE                  pm
    
    • 1
    • 2

    看看Android.mk中的内容:

    chen@ubuntu:~/Mygit/Android$ cat frameworks/base/cmds/pm/Android.mk
    # Copyright 2007 The Android Open Source Project
    #
    LOCAL_PATH:= $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE := pm
    LOCAL_SRC_FILES := pm 	#定义了该模块的源文件为 "pm",意味着要编译构建的文件名为 "pm"
    LOCAL_MODULE_CLASS := EXECUTABLES	#表示该模块是一个可执行文件
    LOCAL_MODULE_TAGS := optional	#表示该模块是一个可选项
    include $(BUILD_PREBUILT)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    接着,来看看 pm 脚本的内容:

    chen@ubuntu:~/Mygit/Android$ cat frameworks/base/cmds/pm/pm
    #!/system/bin/sh
    cmd package "$@"
    
    • 1
    • 2
    • 3

    这看着像封装了一下调用/system/bin/cmd package,只是简化使用 “cmd package” 命令的流程

    3.1 app_process::main

    app_process 其实就是 Zygote 的源码,在开机篇我们已经分析过了 Zygote 的启动,这里略过和 Zygote 相关的代码:
    位置:frameworks/base/cmds/app_process/app_main.cpp

    int main(int argc, char* const argv[])
    {
    	//...
    
        ++i;  // Skip unused "parent dir" argument.
        while (i < argc) {
            const char* arg = argv[i++];
            if (strcmp(arg, "--zygote") == 0) {
                zygote = true;
                niceName = ZYGOTE_NICE_NAME;
            } else if (strcmp(arg, "--start-system-server") == 0) {
                startSystemServer = true;
            } else if (strcmp(arg, "--application") == 0) {
                application = true;
            } else if (strncmp(arg, "--nice-name=", 12) == 0) {
                niceName.setTo(arg + 12);
            } else if (strncmp(arg, "--", 2) != 0) {
            	//【1】获得要启动的 java 进程的 className
                className.setTo(arg);
                break;
            } else {
                --i;
                break;
            }
        }
    
        Vector<String8> args;
        if (!className.isEmpty()) {
            //【2】根据 application 的取值,判断我们启动的是应用类型进程,还是工具类型进程!
            args.add(application ? String8("application") : String8("tool"));
            runtime.setClassNameAndArgs(className, argc - i, argv + i);
    
            if (!LOG_NDEBUG) {
              String8 restOfArgs;
              char* const* argv_new = argv + i;
              int argc_new = argc - i;
              for (int k = 0; k < argc_new; ++k) {
                restOfArgs.append("\"");
                restOfArgs.append(argv_new[k]);
                restOfArgs.append("\" ");
              }
              ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
            }
        } else {	// zygote 启动才会进入!
    		//...
        }
        
        if (zygote) {
            runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
        } else if (className) {
        	//【2.2】非 Zygote 进程的启动方式如下
            runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
        } else {
            fprintf(stderr, "Error: no class name or --zygote supplied.\n");
            app_usage();
            LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    接下来,会进入 AndroidRuntime 中去!!

    3.2 AndroidRuntime::start

    这里的 className 传入的值为 com.android.internal.os.RuntimeInit
    位置:"frameworks/base/core/jni/AndroidRuntime.cpp"

    void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
    {
        ALOGD(">>>>>> START %s uid %d <<<<<<\n",
                className != NULL ? className : "(unknown)", getuid());
    
        static const String8 startSystemServer("start-system-server");
    
        /*
         * 'startSystemServer == true' means runtime is obsolete and not run from
         * init.rc anymore, so we print out the boot start event here.
         */
        for (size_t i = 0; i < options.size(); ++i) {
            if (options[i] == startSystemServer) {
               /* track our progress through the boot sequence */
               const int LOG_BOOT_PROGRESS_START = 3000;
               LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
            }
        }
    
        const char* rootDir = getenv("ANDROID_ROOT");
        if (rootDir == NULL) {
            rootDir = "/system";
            if (!hasDir("/system")) {
                LOG_FATAL("No root directory specified, and /android does not exist.");
                return;
            }
            setenv("ANDROID_ROOT", rootDir, 1);
        }
    
        //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
        //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
    
        /* start the virtual machine */  //【1】启动虚拟机!
        JniInvocation jni_invocation;
        jni_invocation.Init(NULL);
        JNIEnv* env;
        if (startVm(&mJavaVM, &env, zygote) != 0) {
            return;
        }
        onVmCreated(env);
    
        /*
         * Register android functions.
         */ //【2】注册 Android 函数!
        if (startReg(env) < 0) {
            ALOGE("Unable to register all android natives\n");
            return;
        }
    
        /*
         * We want to call main() with a String array with arguments in it.
         * At present we have two arguments, the class name and an option string.
         * Create an array to hold them.
         */ //【3】创建一个 String 数组来保存传递进来的参数!
        jclass stringClass;
        jobjectArray strArray;
        jstring classNameStr;
    
        stringClass = env->FindClass("java/lang/String");
        assert(stringClass != NULL);
        strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
        assert(strArray != NULL);
        classNameStr = env->NewStringUTF(className);
        assert(classNameStr != NULL);
        env->SetObjectArrayElement(strArray, 0, classNameStr);
    
        for (size_t i = 0; i < options.size(); ++i) {
            jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
            assert(optionsStr != NULL);
            env->SetObjectArrayElement(strArray, i + 1, optionsStr);
        }
    
        /*
         * Start VM.  This thread becomes the main thread of the VM, and will
         * not return until the VM exits.
         */  //【4】启动虚拟机的主线程,该主线程不会退出,直到虚拟机退出!
        char* slashClassName = toSlashClassName(className != NULL ? className : "");
        jclass startClass = env->FindClass(slashClassName);
        if (startClass == NULL) {
            ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
            /* keep going */
        } else {	//【2.3】反射调用 RuntimeInit.main 函数,从 native 层进入 java 世界!
            jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
                "([Ljava/lang/String;)V");
            if (startMeth == NULL) {
                ALOGE("JavaVM unable to find main() in '%s'\n", className);
                /* keep going */
            } else {
                env->CallStaticVoidMethod(startClass, startMeth, strArray);
    
    #if 0
                if (env->ExceptionCheck())
                    threadExitUncaughtException(env);
    #endif
            }
        }
        free(slashClassName);
    
        ALOGD("Shutting down VM\n");
        if (mJavaVM->DetachCurrentThread() != JNI_OK)
            ALOGW("Warning: unable to detach main thread\n");
        if (mJavaVM->DestroyJavaVM() != 0)
            ALOGW("Warning: VM did not shut down cleanly\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104

    通过反射,进入 RuntimeInit 中!

    3.3 RuntimeInit.main

    位置:.frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

    public static final void main(String[] argv) {
            enableDdms();
            if (argv.length == 2 && argv[1].equals("application")) {
                if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
                redirectLogStreams();
            } else {
                if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
            }
    		//【1】进程一些初始化的操作,比如设置线程的默认异常处理 Handler,设置 Log 系统等等,在进程的启动时,我们分析过!!
            commonInit();
    
            /*
             * Now that we're running in interpreted code, call back into native code
             * to run the system.
             */		//【2.4】这里的关键点在这里!
            nativeFinishInit();
    
            if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    nativeFinishInit 调用的是 native 方法,位于 AndroidRuntime.cpp 文件中!

    3.4 com_android_internal_os_RuntimeInit_nativeFinishInit

    位置:frameworks/base/core/jni/AndroidRuntime.cpp

    static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jobject clazz)
    {
    	//【2.5】gCurRuntime 是 AndroidRuntime 子类 AppRuntime 的实例!
        gCurRuntime->onStarted();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    实际上 AndroidRuntime 并没有实现 onStarted 方法,真正是实现是在 App_main.cpp 中的 AppRuntime 类中,他是 AndroidRuntime 的子类!

    3.5 AndroidRuntime

    位置:./frameworks/base/cmds/app_process/app_main.cpp

        virtual void onStarted()
        {
            sp<ProcessState> proc = ProcessState::self();
            ALOGV("App process: starting thread pool.\n");
            proc->startThreadPool();
    		//【2.6】执行 AndroidRuntime 的 callMain 方法!
            AndroidRuntime* ar = AndroidRuntime::getRuntime();
            ar->callMain(mClassName, mClass, mArgs);
    
            IPCThreadState::self()->stopProcess();
            hardware::IPCThreadState::self()->stopProcess();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.6 AndroidRuntime::callMain

    位置:"frameworks/base/core/jni/AndroidRuntime.cpp"

    status_t AndroidRuntime::callMain(const String8& className, jclass clazz,
        const Vector<String8>& args)
    {
        JNIEnv* env;
        jmethodID methodId;
    
        ALOGD("Calling main entry %s", className.string());
    
        env = getJNIEnv();
        if (clazz == NULL || env == NULL) {
            return UNKNOWN_ERROR;
        }
    
        methodId = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
        if (methodId == NULL) {
            ALOGE("ERROR: could not find method %s.main(String[])\n", className.string());
            return UNKNOWN_ERROR;
        }
    
        /*
         * We want to call main() with a String array with our arguments in it.
         * Create an array and populate it.
         */		//【1】创建一个 String 数组来封装参数!
        jclass stringClass;
        jobjectArray strArray;
    
        const size_t numArgs = args.size();
        stringClass = env->FindClass("java/lang/String");
        strArray = env->NewObjectArray(numArgs, stringClass, NULL);
    
        for (size_t i = 0; i < numArgs; i++) {
            jstring argStr = env->NewStringUTF(args[i].string());
            env->SetObjectArrayElement(strArray, i, argStr);
        }
    	//【*2.7】最终反射调用了 Pm.main 方法!
        env->CallStaticVoidMethod(clazz, methodId, strArray);
        return NO_ERROR;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    四、命令安装

    之前是用adb shell pm …命令
    现在是用adb shell cmd package …命令,
    也可用adb install 命令安装应用。
    cmd package命令通过binder的shell cmd 调用

    位置:frameworks/native/cmds/cmd/cmd.cpp

    int main(int argc, char* const argv[])
    {
    	//...
        // TODO: block until a result is returned to MyResultReceiver.
        //参数service即传入的package服务,经过Binder的一些传递(CPP 通过binder调用JAVA Binder服务)最终调用onShellCommand()
        status_t err = IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,
                cb, result);
    	//...
        return res;
    }
    //位置:./frameworks/base/core/java/android/os/Binder.java
        public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
                @Nullable FileDescriptor err,
                @NonNull String[] args, @Nullable ShellCallback callback,
                @NonNull ResultReceiver resultReceiver) throws RemoteException {
            onShellCommand(in, out, err, args, callback, resultReceiver);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    对用package来说,即调用到

    //位置:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
        @Override
        public void onShellCommand(FileDescriptor in, FileDescriptor out,
                FileDescriptor err, String[] args, ShellCallback callback,
                ResultReceiver resultReceiver) {
            (new PackageManagerShellCommand(this)).exec(
                    this, in, out, err, args, callback, resultReceiver);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在PackageManagerShellCommand中,调用exec会调用onCommand我觉得
    位置:frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java

    public int onCommand(String cmd) {
            if (cmd == null) {
                return handleDefaultCommands(cmd);
            }
    
            final PrintWriter pw = getOutPrintWriter();
            try {
                switch(cmd) {
                    case "path":
                        return runPath();
                    case "dump":
                        return runDump();
                    case "list":
                        return runList();
    				//...
                    case "install":		//如果参数是install就调用runInstall
                        return runInstall();
    
                    case "preinstall":
    
                         return preInstall();
    
    				//...
                    case "uninstall":
                        return runUninstall();
                    case "clear":
                        return runClear();
                    case "enable":
                        return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
                    case "disable":
                        return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
    				//...
                    default: {
                        String nextArg = getNextArg();
                        if (nextArg == null) {
                            if (cmd.equalsIgnoreCase("-l")) {
                                return runListPackages(false);
                            } else if (cmd.equalsIgnoreCase("-lf")) {
                                return runListPackages(true);
                            }
                        } else if (getNextArg() == null) {
                            if (cmd.equalsIgnoreCase("-p")) {
                                return displayPackageFilePath(nextArg, UserHandle.USER_SYSTEM);
                            }
                        }
                        return handleDefaultCommands(cmd);		//如果啥参数都没有,就调用onHelp
                    }
                }
            } catch (RemoteException e) {
                pw.println("Remote exception: " + e);
            }
            return -1;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    4.1 runInstall

    大体的安装流程:

    IBinder::shellCommand()/cmd.cpp --> .... --> onShellCommand()/PackageManagerService.java --> exec()/ShellCommand.java
    --> onCommand()/PackageManagerShellCommand.java -->
    runInstall() 
    	+--> doCreateSession() 
    	 |     +--> mInterface.getPackageInstaller().createSession(params, installerPackageName, userId);
        +--> doCommitSession()
              +--> new PackageInstaller.Session(mInterface.getPackageInstaller().openSession(sessionId));
              +--> session.commit(receiver.getIntentSender())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    private int runInstall() throws RemoteException {
            final PrintWriter pw = getOutPrintWriter();
            final InstallParams params = makeInstallParams();
            final String inPath = getNextArg();
    
            setParamsSize(params, inPath);
            final int sessionId = doCreateSession(params.sessionParams,
                    params.installerPackageName, params.userId);		//创建安装的session
            boolean abandonSession = true;
            try {
                if (inPath == null && params.sessionParams.sizeBytes == -1) {
                    pw.println("Error: must either specify a package size or an APK file");
                    return 1;
                }
                //该过程其实是将inPath指向apk写入到.tmp目录下,指定文件名是base.apk
                if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
                        false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
                    return 1;
                }
                //提交Session触发安装
                if (doCommitSession(sessionId, false /*logSuccess*/)
                        != PackageInstaller.STATUS_SUCCESS) {
                    return 1;
                }
                abandonSession = false;
                pw.println("Success");
                return 0;
            } finally {
                if (abandonSession) {
                    try {
                    	//如果安装异常,忽视本次事务
                        doAbandonSession(sessionId, false /*logSuccess*/);
                    } catch (Exception ignore) {
                    }
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    4.2.1 makeInstallParams

    Pm 中会根据传入的安装参数,创建 InstallParams,封装安装参数!
    位置:./frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java

        private InstallParams makeInstallParams() {
        	//【*2.9.1.1】创建 SessionParams 实例,封装安装参数!
            final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
            //【*2.9.1.2】创建 InstallParams,解耦合!
            final InstallParams params = new InstallParams();
            params.sessionParams = sessionParams;	// 设置引用关系!
            String opt;
            boolean replaceExisting = true;
            //【1】根据额外的参数,设置安装参数!
            while ((opt = getNextOption()) != null) {
                switch (opt) {
                    case "-l":
                    //【1.1】该应用以 forward locked 方式安装,在该模式下,只有应用自己能够访问自己的代码和非资源文件!
                        sessionParams.installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
                        break;
                    case "-r": // ignore	//【1.2】替换已存在的 apk
                        break;
                    case "-R":
                        replaceExisting = false;
                        break;
                    case "-i":	// 显式指定安装器
                        params.installerPackageName = getNextArg();
                        if (params.installerPackageName == null) {
                            throw new IllegalArgumentException("Missing installer package");
                        }
                        break;
                    case "-t":	// 允许测试应用安装(设置了 android:testOnly)
                        sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
                        break;
                    case "-s":	// 安装到外置存储
                        sessionParams.installFlags |= PackageManager.INSTALL_EXTERNAL;
                        break;
                    case "-f":	// 安装到内置存储
                        sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL;
                        break;
                    case "-d":	//【1.3】允许降级安装!
                        sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
                        break;
                    case "-g":	//【1.4】授予运行时权限
                        sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
                        break;
                    case "--dont-kill":
                        sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
                        break;
                    case "--originating-uri":	// 安装不会杀 app 进程
                        sessionParams.originatingUri = Uri.parse(getNextArg());
                        break;
                    case "--referrer":
                        sessionParams.referrerUri = Uri.parse(getNextArg());
                        break;
                    case "-p":	//【1.5】继承已存在的 apk,appPackageName 用以保存要继承的包名,也就是主 apk 的包名!
                        sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING;
                        sessionParams.appPackageName = getNextArg();
                        if (sessionParams.appPackageName == null) {
                            throw new IllegalArgumentException("Missing inherit package name");
                        }
                        break;
                    case "--pkg":
                        sessionParams.appPackageName = getNextArg();
                        if (sessionParams.appPackageName == null) {
                            throw new IllegalArgumentException("Missing package name");
                        }
                        break;
                    case "-S":	// 显式指定应用的大小
                        final long sizeBytes = Long.parseLong(getNextArg());
                        if (sizeBytes <= 0) {
                            throw new IllegalArgumentException("Size must be positive");
                        }
                        sessionParams.setSize(sizeBytes);
                        break;
                    case "--abi":	// 显式指定 abi
                        sessionParams.abiOverride = checkAbiArgument(getNextArg());
                        break;
                    case "--ephemeral":	// 作为一个 lightweight "ephemeral" 应用!
                    case "--instant":
                    case "--instantapp":
                        sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
                        break;
                    case "--full":
                        sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);
                        break;
                    case "--preload":
                        sessionParams.setInstallAsVirtualPreload();
                        break;
                    case "--user":	// 指定安装的 userId
                        params.userId = UserHandle.parseUserArg(getNextArgRequired());
                        break;
                    case "--install-location":	// 指定安装位置
                        sessionParams.installLocation = Integer.parseInt(getNextArg());
                        break;
                    case "--force-uuid":
                        sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
                        sessionParams.volumeUuid = getNextArg();
                        if ("internal".equals(sessionParams.volumeUuid)) {
                            sessionParams.volumeUuid = null;
                        }
                        break;
                    case "--force-sdk":
                        sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
                        break;
                    default:
                        throw new IllegalArgumentException("Unknown option " + opt);
                }
                if (replaceExisting) {
                    sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
                }
            }
            return params;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    额外的参数很多,根据额外的参数,对 SessionParams 进行了属性设置!

    sessionParams.installFlags 会根据不同的额外参数,设置不同的二进制位,具体的含义我上面也简单的注释了下。大家可以自己去看源码!
    这里我们要注意下:
    - 如果我们安装的是 split apk 的话,那么我们可以指定 -p 参数,后面指定主 apk 的包名,后面我们会分析其作用!

    4.2.2 doCreateSession

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

        private int doCreateSession(SessionParams params, String installerPackageName, int userId)
                throws RemoteException {
            userId = translateUserId(userId, true /*allowAll*/, "runInstallCreate");
            if (userId == UserHandle.USER_ALL) {
                userId = UserHandle.USER_SYSTEM;
                params.installFlags |= PackageManager.INSTALL_ALL_USERS;
            }
    		//【*3.1】进入 PackageInstallerService!
            final int sessionId = mInterface.getPackageInstaller()
                    .createSession(params, installerPackageName, userId);
            return sessionId;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    进入了 PackageInstallerService 服务,创建 Session 对象

    4.2.3 doWriteSplit - 写入事务

    回顾下参数:

    if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
    		false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
    		return 1;
    	}
    
    • 1
    • 2
    • 3
    • 4

    这里的 splitName 值为 “base.apk”;
    位置:./frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java

    private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
                boolean logSuccess) throws RemoteException {
            //【1】这里的 inPath 就是前面创建的 /data/local/tmp/ 目录!
            final PrintWriter pw = getOutPrintWriter();
            final ParcelFileDescriptor fd;
            //【3】 定义输入流对象,指向待安装 APK 对应文件的源地址
            if (STDIN_PATH.equals(inPath)) {
                fd = new ParcelFileDescriptor(getInFileDescriptor());
            } else if (inPath != null) {
                fd = openFileForSystem(inPath, "r");
                if (fd == null) {
                    return -1;
                }
                sizeBytes = fd.getStatSize();
                if (sizeBytes < 0) {
                    getErrPrintWriter().println("Unable to get size of: " + inPath);
                    return -1;
                }
            } else {
                fd = new ParcelFileDescriptor(getInFileDescriptor());
            }
            if (sizeBytes <= 0) {
                getErrPrintWriter().println("Error: must specify a APK size");
                return 1;
            }
    
            PackageInstaller.Session session = null;
            try {
            	//【*3.3.2】根据前面创建的 Session id,获得本次安装事务对象!
            	//【*3.2.1】通过 PackageInstallerService.openSession 获得对应的 PackageInstallerSession 对象!
            	//【*2.9.3.1】封装成 Session 实例!
                session = new PackageInstaller.Session(
                        mInterface.getPackageInstaller().openSession(sessionId));
                //【*2.9.3.1.1】 定义输出流对象,指向待安装 APK 对应文件的源地址!
                session.write(splitName, 0, sizeBytes, fd);
    
                if (logSuccess) {
                    pw.println("Success: streamed " + sizeBytes + " bytes");
                }
                //【3】拷贝完成,返回 STATUS_SUCCESS!
                return 0;
            } catch (IOException e) {
                getErrPrintWriter().println("Error: failed to write; " + e.getMessage());
                return 1;
            } finally {
                IoUtils.closeQuietly(session);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    doWriteSession 整个流程其实就是进行 apk 的拷贝操作!

    4.2.3.1 new PackageInstaller.Session

    位置:./frameworks/base/core/java/android/content/pm/PackageInstaller.java
    Session 是对 PackageInstallerSession 的简单封装

    	public static class Session implements Closeable {
            private IPackageInstallerSession mSession;
    
            /** {@hide} */
            public Session(IPackageInstallerSession session) {
                mSession = session;
            }
    
    		public void setProgress(float progress) {
    			//...
    		}
    		public void setStagingProgress(float progress) {
    			//...
    		}
    		public void addProgress(float progress) {
    			//...
    		}
    		public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
                    long lengthBytes) throws IOException {
    			//...
    		}
    		public void write(@NonNull String name, long offsetBytes, long lengthBytes,
                    @NonNull ParcelFileDescriptor fd) throws IOException {
    			//...
    		}
    		public void fsync(@NonNull OutputStream out) throws IOException {
                if (ENABLE_REVOCABLE_FD) {
    			//...
    		}
    		public @NonNull String[] getNames() throws IOException {
    			//...
    		}
    		public @NonNull InputStream openRead(@NonNull String name) throws IOException {
    			//...
    		}
    		public void removeSplit(@NonNull String splitName) throws IOException {
    			//...
    		}
    		public void commit(@NonNull IntentSender statusReceiver) {
    			//...
    		}
    		@SystemApi
            @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
            public void commitTransferred(@NonNull IntentSender statusReceiver) {
            	//...
    		}
            public void transfer(@NonNull String packageName)
                    throws PackageManager.NameNotFoundException {
            	//...
    		}
            @Override
            public void close() {
            	//...
    		}
            public void abandon() {
            	//...
    		}
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    mSession 指向了对应的 PackageInstallerSession 实例

    同时其还提供了很多借口,来操作 PackageInstallerSession,这里我们用一张图先简单的看下:

    Session.setProgress -> PackageInstallerSession.setClientProgress
    Session.setStagingProgress -> PackageInstallerSession.setClientProgress
    Session.addProgress -> PackageInstallerSession.addClientProgress
    Session.openWrite -> PackageInstallerSession.openWrite
    Session.openRead -> PackageInstallerSession.openRead
    Session.commit -> PackageInstallerSession.commit
    Session.abandon -> PackageInstallerSession.abandon
    … … …

    2.4.3.1.1 Session.openWrite

    这里的 name 传入的是 base.apk:

            public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
                    long lengthBytes) throws IOException {
                try {
                    if (ENABLE_REVOCABLE_FD) {
                        return new ParcelFileDescriptor.AutoCloseOutputStream(
                                mSession.openWrite(name, offsetBytes, lengthBytes));
                    } else {
                    	//【*4.1】这里会调用 PackageInstallerSession 的 openWrite 方法
                    	// 将前面创建 Session 的文件目录 /data/app/vmdl[sessionId].tmp 封装成一个文件描述符对象!
                        final ParcelFileDescriptor clientSocket = mSession.openWrite(name,
                                offsetBytes, lengthBytes);
                        //【2】获得该文件描述符输出流
                        return new FileBridge.FileBridgeOutputStream(clientSocket);
                    }
                } catch (RuntimeException e) {
                    ExceptionUtils.maybeUnwrapIOException(e);
                    throw e;
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    mSession.openWrite 方法涉及到了文件相关处理,这里就不过多关注

    2.4.3.1.2 Session.addProgress
            public void addProgress(float progress) {
                try {
                //这里会调用 PackageInstallerSession 的 addClientProgress 方法
    	        // 更新文件读写进度!
                    mSession.addClientProgress(progress);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

    @Override
        public void addClientProgress(float progress) {
            synchronized (mLock) {
                assertCallerIsOwnerOrRootLocked();
    			//调用了 setClientProgress 方法
                setClientProgress(mClientProgress + progress);
            }
        }
    
    	@Override
        public void setClientProgress(float progress) {
            synchronized (mLock) {
                assertCallerIsOwnerOrRootLocked();
    
                // Always publish first staging movement	//【1】用于第一次更新进度
                final boolean forcePublish = (mClientProgress == 0);
                mClientProgress = progress;
                //最终,调用 computeProgressLocked 方法
                computeProgressLocked(forcePublish);
            }
        }
        
        @GuardedBy("mLock")
        private void computeProgressLocked(boolean forcePublish) {
        	//【1】计算进度
            mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
                    + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
    		//【2】更新进度
            // Only publish when meaningful change
            if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
                mReportedProgress = mProgress;
                //同时通知事务观察者,进度的变化
                mCallback.onSessionProgressChanged(this, mProgress);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    2.4.4 Pm.doCommitSession - 提交事务

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

    private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
            final PrintWriter pw = getOutPrintWriter();
            PackageInstaller.Session session = null;
            try {
            	//获得前面创建的 Session 对象
                session = new PackageInstaller.Session(
                        mInterface.getPackageInstaller().openSession(sessionId));
    
                // Sanity check that all .dm files match an apk.
                // (The installer does not support standalone .dm files and will not process them.)
                try {
                    DexMetadataHelper.validateDexPaths(session.getNames());
                } catch (IllegalStateException | IOException e) {
                    pw.println("Warning [Could not validate the dex paths: " + e.getMessage() + "]");
                }
    			//创建了一个 LocalIntentReceiver
                final LocalIntentReceiver receiver = new LocalIntentReceiver();
                //将 receiver.getIntentSender() 传递给 pms,用户客户端进程获得安装结果
                //调用 PackageInstallerSession 的 commit 方法,提交事务
                session.commit(receiver.getIntentSender());
    			//处理返回结果
                final Intent result = receiver.getResult();
                final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                        PackageInstaller.STATUS_FAILURE);
                if (status == PackageInstaller.STATUS_SUCCESS) {
                    if (logSuccess) {
                        pw.println("Success");
                    }
                } else {
                    pw.println("Failure ["
                            + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
                }
                return status;
            } finally {
                IoUtils.closeQuietly(session);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    到这里,提交过程就结束了,最终的逻辑是在 PackageInstallerService 中实现

    2.4.4.1 LocalIntentReceiver - 跨进程返回结果

    LocalIntentReceiver 用来接收安装结果

    private static class LocalIntentReceiver {
    		//以 Intent 的方式保存安装结果
            private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();
    
            private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
                @Override
                public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
                        IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
                    try {
                    	//将结果保存到 mResult 中
                        mResult.offer(intent, 5, TimeUnit.SECONDS);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            };
    		//getIntentSender 将 getIntentSender 封装到 IntentSender 中,由于 IntentSender 实现了 Parcelable,所以可以跨进程传递:
            public IntentSender getIntentSender() {
                return new IntentSender((IIntentSender) mLocalSender);
            }
    
            public Intent getResult() {
                try {
                	//返回安装结果
                    return mResult.take();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    LocalIntentReceiver 有一个内部成员 mLocalSender,实现了 IIntentSender.Stub,用于跨进程通信。
    系统进程会持有 mLocalSender 对应的代理对象,通过 send 方法,将安装的状态或者结果返回保存到 mResult 中。

    2.4.4.2 LocalIntentReceiver.getIntentSender

    上面写了

    2.4.4.3 Session.commit

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

            public void commit(@NonNull IntentSender statusReceiver) {
                try {
                	//最终,调用了 PackageInstallerSession 的 commit 方法,进入系统进程
                    mSession.commit(statusReceiver, false);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    2.4.4.4 LocalIntentReceiver.getResult

    上面写了

  • 相关阅读:
    【无标题】
    高分辨率格式理论
    前后端分离项目,vue+uni-app+php+mysql订座预约系统(H5移动项目) 开题报告
    渤、黄海的潮汐特征
    03 【Nginx虚拟主机和域名解析】
    pytorch的buffer学习整理
    Linux内核移植之主频设置
    大数据分析师职业技能提升好考吗?含金量高不高
    无法加载文件 C:\Users\haoqi\Documents\WindowsPowerShell\profile.ps1,因为在此系统上禁止运行脚本
    剑指offer——JZ32 从上往下打印二叉树 解题思路与具体代码【C++】
  • 原文地址:https://blog.csdn.net/ch122633/article/details/134214542