【Android12】Android Framework系列---Adb和PMS安装apk源码流程

news2024/11/15 22:25:48

Adb和PMS安装apk源码流程

adb install命令

通过adb install命令可以将apk安装到Android系统(注意:特定类型的apk,比如persist类型是无法通过adb安装的)

下述命令中adb解析install命令,并调用Android PackageManagerService进行apk安装。

# -r : replace existing application
# -t : allow test packages\n"
# -d : allow version code downgrade (debuggable packages only)
adb install -r -t -d  linduo_test.apk

基于Android12,分析从adb install到 PakcageManagerService安装apk的流程。
在这里插入图片描述

源码流程分析

adb install命令的源码实现

Android中adb的源码被放在 “packages/modules/adb”这个仓库中,这个仓库编译后的主要成果物是adbd和**adb。**adbd是a服务端进程,adb是提供的客户端工具。adb和adbd两者间,通过socket完成相互间的通信。

# packages/modules/adb/Android.bp
# adbd,在Android系统中运行
cc_binary {
    name: "adbd",
    defaults: ["adbd_defaults", "host_adbd_supported", "libadbd_binary_dependencies"],
    recovery_available: true,
    apex_available: ["com.android.adbd"],

    srcs: [
        "daemon/main.cpp",
    ],
	# 省略...
}
# adb,提供给Host端(就是主机PC)
cc_binary_host {
    name: "adb",

    stl: "libc++_static",
    defaults: ["adb_defaults"],

    srcs: [
        "client/adb_client.cpp",
        "client/bugreport.cpp",
        "client/commandline.cpp",
        "client/file_sync_client.cpp",
        "client/main.cpp",
        "client/console.cpp",
        "client/adb_install.cpp",
        "client/line_printer.cpp",
        "client/fastdeploy.cpp",
        "client/fastdeploycallbacks.cpp",
        "client/incremental.cpp",
        "client/incremental_server.cpp",
        "client/incremental_utils.cpp",
        "shell_service_protocol.cpp",
    ],
    
    # 省略...
}

这里关注adb install命令对应的源码实现,adb这个bin程序对应的main函数定义在“packages/modules/adb/client/main.cpp”,main函数中调用adb_trace_init进行Trace(记录运行Log)的初始化,然后调用adb_commandline解析adb命令参数。

int main(int argc, char* argv[], char* envp[]) {
    __adb_argv = const_cast<const char**>(argv);
    __adb_envp = const_cast<const char**>(envp);
    adb_trace_init(argv);
	// 这里忽略了第一个入参(程序名自己)
    return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
}

adb_commandline函数在"packages/modules/adb/client/commandline.cpp"中实现,在这个函数中解析adb命令的参数。如果是adb install命令,会调用install_app函数进行APK安装的相关流程。

int adb_commandline(int argc, const char** argv) {
	// 省略...
	// 解析各个参数
    while (argc > 0) {
		// 解析第一个参数。就是adb命令后第一个参数
        if (!strcmp(argv[0], "server")) {
			// 省略了很多代码...
        } else {
			// adb install 的情况下走这里,跳出循环
            /* out of recognized modifiers and flags */
            break;
        }
        argc--;
        argv++;
    }

    // 省略...
    /* adb_connect() commands */
    if (!strcmp(argv[0], "devices")) {
		// 省略了很多代码(对各个命令的判断)
    } else if (!strcmp(argv[0], "install")) {
		// 判断参数为install,执行app安装相关函数
        if (argc < 2) error_exit("install requires an argument");
        return install_app(argc, argv);
    } else if (!strcmp(argv[0], "install-multiple")) {
        if (argc < 2) error_exit("install-multiple requires an argument");
        return install_multiple_app(argc, argv);
    } else if (!strcmp(argv[0], "install-multi-package")) {
        if (argc < 2) error_exit("install-multi-package requires an argument");
        return install_multi_package(argc, argv);
    } else if (!strcmp(argv[0], "uninstall")) {
        if (argc < 2) error_exit("uninstall requires an argument");
        return uninstall_app(argc, argv);
    } else if (!strcmp(argv[0], "sync")) {
		// 省略...
    }
	
	// 省略...
	// 如果输入了错误的参数,会报下面的错误,并结束此次adb命令的执行
    error_exit("unknown command %s", argv[0]);
    __builtin_unreachable();
}

install_app函数在“packages/modules/adb/client/adb_install.cpp”中定义。该函数先判断APK的安装模式是

INSTALL_PUSH/INSTALL_STREAM/INSTALL_INCREMENTAL中哪一种。默认情况下是INSTALL_PUSH模式,然后调用install_app_legacy函数进行APK安装。

  • INSTALL_PUSH:通过推送的方式安装APK,将APK整个推送到设置上进行安装。
  • INSTALL_STREAM:流式传输安装APK,APK被分割成多份并在安装过程中逐个传输到系统设置上进行组装和安装,这种方式可以减少安装的时间(如果系统支持,默认会使用这种方式安装)
  • INSTALL_INCREMENTAL:增量方式安装APK,仅安装差异的部分不需要重新安装整个Apk,加速apk安装时间。大型的APK(如GB级别)应用较多(需要系统支持)
int install_app(int argc, const char** argv) {
    InstallMode install_mode = INSTALL_DEFAULT;
    auto incremental_request = CmdlineOption::None;
    bool incremental_wait = false;

    bool use_fastdeploy = false;
    FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
	// 进行安装默认的判断,通过parse_install_mode/parse_fast_deploy_mode/calculate_install_mode实现
	// 具体实现方式请自行查看源码,这里就不关注了
    auto unused_argv = parse_install_mode({argv, argv + argc}, &install_mode, &incremental_request,
                                          &incremental_wait);
    auto passthrough_argv =
            parse_fast_deploy_mode(std::move(unused_argv), &use_fastdeploy, &agent_update_strategy);

    auto [primary_mode, fallback_mode] =
            calculate_install_mode(install_mode, use_fastdeploy, incremental_request);
	// 省略...
	// adb install默认使用INSTALL_PUSH方式安装
    auto run_install_mode = [&](InstallMode install_mode, bool silent) {
        switch (install_mode) {
            case INSTALL_PUSH:
                return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(),
                                          use_fastdeploy);
            case INSTALL_STREAM:
                return install_app_streamed(passthrough_argv.size(), passthrough_argv.data(),
                                            use_fastdeploy);
            case INSTALL_INCREMENTAL:
                return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(),
                                               incremental_wait, silent);
            case INSTALL_DEFAULT:
            default:
                error_exit("invalid install mode");
        }
    };
	// 如果安装失败,会使用fallback mode再次安装。默认情况下,fallback mode是空(不进行安装)
    auto res = run_install_mode(primary_mode, fallback_mode.has_value());
    if (res && fallback_mode.value_or(primary_mode) != primary_mode) {
        res = run_install_mode(*fallback_mode, false);
    }
    return res;
}

install_app_legacy函数定义在"packages/modules/adb/client/adb_install.cpp"中。函数执行时,会在终端输出"Performing Push Install"提示使用者。函数中判断adb install命令是否以.apk字符结束,并将apk文件push到/data/local/tmp/目录下。然后调用pm_command函数安装/data/local/tmp/目录下的apk文件。最后将/data/local/tmp/下面的apk文件删除。

static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy) {
    printf("Performing Push Install\n");

	// 这里判断 adb install命令是否以 .apk结尾。如果没有就认为没有提供待安装apk
    // Find last APK argument.
    // All other arguments passed through verbatim.
    int last_apk = -1;
    for (int i = argc - 1; i >= 0; i--) {
        if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
            error_exit("APEX packages are only compatible with Streamed Install");
        }
        if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) {
            last_apk = i;
            break;
        }
    }
	
	// 如果在adb install的命令最后字符 不是.apk的形式,报错。
    if (last_apk == -1) error_exit("need APK file on command line");

	// 创建临时目录 /data/local/tmp/xxx.apk,存放待安装的apk
    int result = -1;
    std::vector<const char*> apk_file = {argv[last_apk]};
    std::string apk_dest = "/data/local/tmp/" + android::base::Basename(argv[last_apk]);
	// 注意,这里将adb install 中apk文件的路径,换成了 /data/local/tmp/xxx.apk
    argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
	// 如果使用快速部署(默认为false)
    if (use_fastdeploy) {
		// 省略 ...
    }

	// 将Apk push到/data/local/tmp/目录下
    if (do_sync_push(apk_file, apk_dest.c_str(), false, CompressionType::Any, false)) {
		// 执行安装
        result = pm_command(argc, argv);
		// 安装完成后,删除临时目录/data/local/tmp/下的apk文件。
        delete_device_file(apk_dest);
    }

    return result;
}

pm_command函数,顾名思义给执行pm(PackageManager)相关的命令。所以在函数中,为字符串拼接了 "pm"字符(aosp提供的pm命令)

// packages/modules/adb/client/adb_install.cpp
static int pm_command(int argc, const char** argv) {
    std::string cmd = "pm";

    while (argc-- > 0) {
        cmd += " " + escape_arg(*argv++);
    }

    return send_shell_command(cmd);
}

// packages/modules/adb/client/commandline.cpp

int send_shell_command(const std::string& command, bool disable_shell_protocol,
                       StandardStreamsCallbackInterface* callback) {
    unique_fd fd;
    bool use_shell_protocol = false;

    while (true) {
        bool attempt_connection = true;

        // Use shell protocol if it's supported and the caller doesn't explicitly
        // disable it.
        if (!disable_shell_protocol) {
            auto&& features = adb_get_feature_set(nullptr);
            if (features) {
                use_shell_protocol = CanUseFeature(*features, kFeatureShell2);
            } else {
                // Device was unreachable.
                attempt_connection = false;
            }
        }

        if (attempt_connection) {
            std::string error;
            std::string service_string = ShellServiceString(use_shell_protocol, "", command);
			// 将命令发送给adbd,由adbd执(注意adb运行在Host端,比如PC。adbd才是运行在Android系统上的服务)
            fd.reset(adb_connect(service_string, &error));
            if (fd >= 0) {
                break;
            }
        }

        fprintf(stderr, "- waiting for device -\n");
        if (!wait_for_device("wait-for-device")) {
            return 1;
        }
    }

    return read_and_dump(fd.get(), use_shell_protocol, callback);
}

adbd服务端的处理流程

adbd(daemon进程)在收到Client端(adb)请求,并执行相关动作。在函数StartCommandInProcess中,执行客户端发过来的 “shell pm … /data/local/temp/xxx.apk"命令。

int main(int argc, char* const argv[]) {
    signal(SIGPIPE, SIG_IGN);

    int fd = STDIN_FILENO;
    std::string data;
    while (true) {
        std::string error;
		// 读取客户端的请求
        if (!ReadProtocolString(fd, &data, &error)) {
            PLOG(ERROR) << "Failed to read message: " << error;
            break;
        }

        std::string_view name = data;
        auto protocol = SubprocessProtocol::kShell;
        if (android::base::ConsumePrefix(&name, "abb:")) {
            protocol = SubprocessProtocol::kShell;
        } else if (android::base::ConsumePrefix(&name, "abb_exec:")) {
            protocol = SubprocessProtocol::kNone;
        } else {
            LOG(FATAL) << "Unknown command prefix for abb: " << data;
        }
	
		// 处理请求命令,具体实现可以参考源码。
		// 基本上就是创建了一个Process,在Process中执行传过来的命令。
        unique_fd result = StartCommandInProcess(std::string(name), &execCmd, protocol);
        int max_buf = LINUX_MAX_SOCKET_SIZE;
        adb_setsockopt(result, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
		// 处理结果发送给客户端
        if (android::base::SendFileDescriptors(fd, "", 1, result.get()) != 1) {
            PLOG(ERROR) << "Failed to send an inprocess fd for command: " << data;
            break;
        }
    }
}

pm命令的处理流程

上述流程中最终执行的是 pm install -r -t -d /data/local/tmp/linduo.apk。Android pm命令实际上是一段bash程序。实现在frameworks/base/cmds/pm/pm中,只是简单的调用了cmd package,并将入参传了进去。

#!/system/bin/sh
cmd package "$@"

cmd是一个bin程序,其实现在frameworks/native/cmds/cmd/中。

# frameworks/native/cmds/cmd/Android.bp
package {
    default_applicable_licenses: ["frameworks_native_cmds_cmd_license"],
}

// Added automatically by a large-scale-change
// See: http://go/android-license-faq
license {
    name: "frameworks_native_cmds_cmd_license",
    visibility: [":__subpackages__"],
    license_kinds: [
        "SPDX-license-identifier-Apache-2.0",
    ],
    license_text: [
        "NOTICE",
    ],
}

cc_library_static {
    name: "libcmd",

    srcs: ["cmd.cpp"],
    export_include_dirs: ["."],

    shared_libs: [
        "libutils",
        "liblog",
        "libselinux",
        "libbinder",
    ],

    cflags: [
        "-Wall",
        "-Werror",
        "-DXP_UNIX",
    ],
}

cc_binary {
    name: "cmd",

    srcs: ["main.cpp"],

    static_libs: [
        "libcmd",
    ],

    shared_libs: [
        "libutils",
        "liblog",
        "libselinux",
        "libbinder",
    ],

    cflags: [
        "-Wall",
        "-Werror",
        "-DXP_UNIX",
    ],
}

如果调用的是cmd package,cmd程序中会通过Android 的ServiceManager连接到PMS服务。然后将命令通过binder发送给PMS服务。

// frameworks/native/cmds/cmd/main.cpp
#include <unistd.h>

#include "cmd.h"

int main(int argc, char* const argv[]) {
    signal(SIGPIPE, SIG_IGN);
	
	// 这里将入参的第一个参数去掉。比如 cmd package xxxxx,去掉后就是 package xxxx
    std::vector<std::string_view> arguments;
    arguments.reserve(argc - 1);
    // 0th argument is a program name, skipping.
    for (int i = 1; i < argc; ++i) {
        arguments.emplace_back(argv[i]);
    }
	// main程序中调用cmdMain
    return cmdMain(arguments, android::aout, android::aerr, STDIN_FILENO, STDOUT_FILENO,
                   STDERR_FILENO, RunMode::kStandalone);
}

// frameworks/native/cmds/cmd/cmd.cpp
int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, TextOutput& errorLog,
            int in, int out, int err, RunMode runMode) {
    sp<ProcessState> proc = ProcessState::self();
    proc->startThreadPool();

#if DEBUG
    ALOGD("cmd: starting");
#endif
	// 获取ServiceManager对象
    sp<IServiceManager> sm = defaultServiceManager();
   
    // 这里判断一下,cmd命令中想要调用的服务在当前系统中是否存在。不存在则返回
    if ((argc == 1) && (argv[0] == "-l")) {
        Vector<String16> services = sm->listServices();
        services.sort(sort_func);
        outputLog << "Currently running services:" << endl;

        for (size_t i=0; i<services.size(); i++) {
            sp<IBinder> service = sm->checkService(services[i]);
            if (service != nullptr) {
                outputLog << "  " << services[i] << endl;
            }
        }
        return 0;
    }

	// 判断是否输入了-w选项。
    bool waitForService = ((argc > 1) && (argv[0] == "-w"));
    int serviceIdx = (waitForService) ? 1 : 0;
    const auto cmd = argv[serviceIdx];

    Vector<String16> args;
    String16 serviceName = String16(cmd.data(), cmd.size());
    for (int i = serviceIdx + 1; i < argc; i++) {
        args.add(String16(argv[i].data(), argv[i].size()));
    }
    sp<IBinder> service;
    if(waitForService) {
        service = sm->waitForService(serviceName);
    } else {
        service = sm->checkService(serviceName);
    }

    if (service == nullptr) {
        if (runMode == RunMode::kStandalone) {
            ALOGW("Can't find service %.*s", static_cast<int>(cmd.size()), cmd.data());
        }
        errorLog << "cmd: Can't find service: " << cmd << endl;
        return 20;
    }

    sp<MyShellCallback> cb = new MyShellCallback(errorLog);
    sp<MyResultReceiver> result = new MyResultReceiver();

#if DEBUG
    ALOGD("cmd: Invoking %.*s in=%d, out=%d, err=%d",
          static_cast<int>(cmd.size()), cmd.data(), in, out, err);
#endif


	// 这里将命令发送给对应的服务端执行。
    // TODO: block until a result is returned to MyResultReceiver.
    status_t error = IBinder::shellCommand(service, in, out, err, args, cb, result);
	
	// 省略...
}

PackageManagerService接收安装Apk的请求,将Apk安装到Android系统

adb将安装apk的命令发送到adbd(服务端),adbd通过binder调用PMS服务安装APK。PMS接收到shell调用后,会创建PackageManagerShellCommand对象并调用它exec函数的进行处理。

@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
		FileDescriptor err, String[] args, ShellCallback callback,
		ResultReceiver resultReceiver) {
	(new PackageManagerShellCommand(this, mContext,mDomainVerificationManager.getShell()))
			.exec(this, in, out, err, args, callback, resultReceiver);
}

PackageManagerShellCommand的exec函数,有其继承的父类定义。该函数中会调用onCommand解析命令并调用不同的处理分支。对于本文中的情况(执行INSTALL_PUSH方式安装)会调用runInstall函数进行处理。runInstall函数中调用makeInstallParams将组织APK安装的参数,然后调用doRunInstall进程安装。

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@Override
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 "resolve-activity":
				return runResolveActivity();
			case "query-activities":
				return runQueryIntentActivities();
			case "query-services":
				return runQueryIntentServices();
			case "query-receivers":
				return runQueryIntentReceivers();
			case "install":
				return runInstall();
			case "install-streaming":
				return runStreamingInstall();
			case "install-incremental":
				return runIncrementalInstall();
			// 省略...
	} catch (RemoteException e) {
		pw.println("Remote exception: " + e);
	}
	return -1;
}

private int runInstall() throws RemoteException {
	return doRunInstall(makeInstallParams());
}

makeInstallParams函数会根据adb install [apk相关参数] 时输入的参数进行组织。其实现如下

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
// 例如: adb install -t -r -d linduo.apk(注意安装路径会被替换成  /data/local/temp/linduo.apk )
private InstallParams makeInstallParams() {
	final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
	final InstallParams params = new InstallParams();

	params.sessionParams = sessionParams;
	// Allowlist all permissions by default
	sessionParams.installFlags |= PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;

	String opt;
	boolean replaceExisting = true;
	boolean forceNonStaged = false;
	while ((opt = getNextOption()) != null) {
		switch (opt) {
			case "-r": // ignore
				break;
			case "-R":
				replaceExisting = false;
				break;
			case "-i":
				params.installerPackageName = getNextArg();
				if (params.installerPackageName == null) {
					throw new IllegalArgumentException("Missing installer package");
				}
				break;
			case "-t":  
				sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
				break;
			case "-f":
				sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL;
				break;
			case "-d":
				sessionParams.installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE;
				break;
			case "-g":
				sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
				break;
			case "--restrict-permissions":
				sessionParams.installFlags &=
						~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
				break;
			case "--dont-kill":
				sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
				break;
			case "--originating-uri":
				sessionParams.originatingUri = Uri.parse(getNextArg());
				break;
			case "--referrer":
				sessionParams.referrerUri = Uri.parse(getNextArg());
				break;
			case "-p":
				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":
				sessionParams.abiOverride = checkAbiArgument(getNextArg());
				break;
			case "--ephemeral":
			case "--instant":
			case "--instantapp":
				sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
				break;
			case "--full":
				sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);
				break;
			case "--preload":
				sessionParams.setInstallAsVirtualPreload();
				break;
			case "--user":
				params.userId = UserHandle.parseUserArg(getNextArgRequired());
				break;
			case "--install-location":
				sessionParams.installLocation = Integer.parseInt(getNextArg());
				break;
			case "--install-reason":
				sessionParams.installReason = 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": // ignore
				break;
			case "--apex":
				sessionParams.setInstallAsApex();
				sessionParams.setStaged();
				break;
			case "--force-non-staged":
				forceNonStaged = true;
				break;
			case "--multi-package":
				sessionParams.setMultiPackage();
				break;
			case "--staged":
				sessionParams.setStaged();
				break;
			case "--force-queryable":
				sessionParams.setForceQueryable();
				break;
			case "--enable-rollback":
				if (params.installerPackageName == null) {
					// com.android.shell has the TEST_MANAGE_ROLLBACKS
					// permission needed to enable rollback for non-module
					// packages, which is likely what the user wants when
					// enabling rollback through the shell command. Set
					// the installer to com.android.shell if no installer
					// has been provided so that the user doesn't have to
					// remember to set it themselves.
					params.installerPackageName = "com.android.shell";
				}
				sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
				break;
			case "--staged-ready-timeout":
				params.stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
				break;
			case "--skip-verification":
				sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
				break;
			default:
				throw new IllegalArgumentException("Unknown option " + opt);
		}
	}
	if (replaceExisting) {
		sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
	}
	if (forceNonStaged) {
		sessionParams.isStaged = false;
	}
	return params;
}

doRunInstall函数根据安装参数进行APK的安装,该函数主要做了两个事情。一个是通过doCreateSession函数,创建了PackageInstallerSession对象,做了些Apk安装准工作。另一个是通过doCommitSession函数,利用PackageInstaller.Session对象进行apk的安装。

private int doRunInstall(final InstallParams params) throws RemoteException {
	final PrintWriter pw = getOutPrintWriter();
	
	// 判断安装类型
	final boolean isStreaming = params.sessionParams.dataLoaderParams != null;
	final boolean isApex =
			(params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;

	ArrayList<String> args = getRemainingArgs();

	final boolean fromStdIn = args.isEmpty() || STDIN_PATH.equals(args.get(0));
	final boolean hasSplits = args.size() > 1;

	if (fromStdIn && params.sessionParams.sizeBytes == -1) {
		pw.println("Error: must either specify a package size or an APK file");
		return 1;
	}

	if (isApex && hasSplits) {
		pw.println("Error: can't specify SPLIT(s) for APEX");
		return 1;
	}

	if (!isStreaming) {
		if (fromStdIn && hasSplits) {
			pw.println("Error: can't specify SPLIT(s) along with STDIN");
			return 1;
		}

		if (args.isEmpty()) {
			args.add(STDIN_PATH);
		} else {
			setParamsSize(params, args);
		}
	}

	// 创建SessionID(PMS会创建PackageInstallerSession对象),可以理解成创建了安装APK的任务
	// 通过调用PackageInstallerService的createSession实现
	final int sessionId = doCreateSession(params.sessionParams,
			params.installerPackageName, params.userId);
	boolean abandonSession = true;
	try {
		if (isStreaming) {
			if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex)
					!= PackageInstaller.STATUS_SUCCESS) {
				return 1;
			}
		} else {
			if (doWriteSplits(sessionId, args, params.sessionParams.sizeBytes, isApex)
					!= PackageInstaller.STATUS_SUCCESS) {
				return 1;
			}
		}
		
		// 安装APK(通过提交sessionID),主要关注这个函数。
		if (doCommitSession(sessionId, false /*logSuccess*/)
				!= PackageInstaller.STATUS_SUCCESS) {
			return 1;
		}
		abandonSession = false;

		if (params.sessionParams.isStaged && params.stagedReadyTimeoutMs > 0) {
			return doWaitForStagedSessionReady(sessionId, params.stagedReadyTimeoutMs, pw);
		}

		pw.println("Success");
		return 0;
	} finally {
		if (abandonSession) {
			try {
				doAbandonSession(sessionId, false /*logSuccess*/);
			} catch (Exception ignore) {
			}
		}
	}
}

doCommitSession函数中创建了PackageInstaller.Session对象,通过与上面创建的sessionId进行绑定。然后调用PackageInstaller.Session.commit进行APK安装。

private int doCommitSession(int sessionId, boolean logSuccess)
		throws RemoteException {

	final PrintWriter pw = getOutPrintWriter();
	PackageInstaller.Session session = null;
	try {
		session = new PackageInstaller.Session(
				mInterface.getPackageInstaller().openSession(sessionId));
		if (!session.isMultiPackage() && !session.isStaged()) {
			// Validity 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() + "]");
			}
		}
		final LocalIntentReceiver receiver = new LocalIntentReceiver();
		//调用commit安装APK
		session.commit(receiver.getIntentSender());
		final Intent result = receiver.getResult();
		final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
				PackageInstaller.STATUS_FAILURE);
		// 判断APK安装状态
		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);
	}
}

PackageInstaller.Session的实现如下,调用了IPackageInstallerSession(通过mInterface.getPackageInstaller().openSession(sessionId)取得)对象的commit函数。

public static class Session implements Closeable {
	public Session(IPackageInstallerSession session) {
		mSession = session;
	}

	public void commit(@NonNull IntentSender statusReceiver) {
		try {
			mSession.commit(statusReceiver, false);
		} catch (RemoteException e) {
			throw e.rethrowFromSystemServer();
		}
	}
}

PackageInstallerSession的commit函数,实现在"frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java“。commit函数中,会将处理转到自身的Handle中。通过一系列调用commit -> dispatchSessionSealed -> handleSessionSealed -> dispatchStreamValidateAndCommit -> handleStreamValidateAndCommit -> handleInstall -> verify -> verifyNonStaged,在verifyNonStaged函数中,调用PMS的verifyStage验证APK。验证成功后,通过onVerificationComplete回调,调用install函数,安装APK

// frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
	// 省略
	dispatchSessionSealed();
}

private void dispatchSessionSealed() {
	// 转到Handle线程处理
	mHandler.obtainMessage(MSG_ON_SESSION_SEALED).sendToTarget();
}

private void handleSessionSealed() {
	assertSealed("dispatchSessionSealed");
	// Persist the fact that we've sealed ourselves to prevent
	// mutations of any hard links we create.
	mCallback.onSessionSealedBlocking(this);
	dispatchStreamValidateAndCommit();
}

private void dispatchStreamValidateAndCommit() {
	mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
}

private void handleStreamValidateAndCommit() {
	// 省略
	mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
}

private void handleInstall() {
	// 检查、验证APK包
	verify();
}

private void verify() {
	try {
		verifyNonStaged();
	} catch (PackageManagerException e) {
		final String completeMsg = ExceptionUtils.getCompleteMessage(e);
		onSessionVerificationFailure(e.error, completeMsg);
	}
}
// 调用PMS的verifyStage,验证APK。验证成功会,调用install方法进行安装。
private void verifyNonStaged()
		throws PackageManagerException {
	final PackageManagerService.VerificationParams verifyingSession =
			prepareForVerification();
	if (verifyingSession == null) {
		return;
	}
	if (isMultiPackage()) {
		// 省略
		mPm.verifyStage(verifyingSession, verifyingChildSessions);
	} else {
		mPm.verifyStage(verifyingSession);
	}
}

// 验证成功,通过回调。调用install开始安装APK
private void onVerificationComplete() {
	// Staged sessions will be installed later during boot
	if (isStaged()) {
		// TODO(b/136257624): Remove this once all verification logic has been transferred out
		//  of StagingManager.
		mStagingManager.notifyPreRebootVerification_Apk_Complete(mStagedSession);
		// TODO(b/136257624): We also need to destroy internals for verified staged session,
		//  otherwise file descriptors are never closed for verified staged session until reboot
		return;
	}

	install();
}

在install函数中,调用了PMS的installStage函数,对APK进行了安装。

// frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
private void install() {
	try {
		installNonStaged();
	} catch (PackageManagerException e) {
		final String completeMsg = ExceptionUtils.getCompleteMessage(e);
		onSessionInstallationFailure(e.error, completeMsg);
	}
}

调用PMS的installStage函数,安装APK
private void installNonStaged()
		throws PackageManagerException {
	final PackageManagerService.InstallParams installingSession = makeInstallParams();
	if (installingSession == null) {
		throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
				"Session should contain at least one apk session for installation");
	}
	if (isMultiPackage()) {
		// 省略...
		mPm.installStage(installingSession, installingChildSessions);
	} else {
		mPm.installStage(installingSession);
	}
}

PackageManagerService的installStage会对APK进行实际的安装。

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void installStage(InstallParams params) {
	// 首先进行copy
	final Message msg = mHandler.obtainMessage(INIT_COPY);
	params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
	msg.obj = params;

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

	mHandler.sendMessage(msg);
}

转Handle处理INIT_COPY,调用startCopy函数,在startCopy函数中调用handleStartCopy和handleReturnCode进行APK的拷贝,从/data/local/tmp/目录把APK文件拷贝拷贝到/data/app/包名/目录。然后调用processInstallRequestsAsync进行安装。

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private abstract class HandlerParams {
        final void startCopy() {
            if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
            handleStartCopy();
            handleReturnCode();
        }
}

class InstallParams extends HandlerParams {
  // 根据安装Flag,进行预处理
  public void handleStartCopy() {
            if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
                mRet = INSTALL_SUCCEEDED;
                return;
            }
            PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                    mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);

            // For staged session, there is a delay between its verification and install. Device
            // state can change within this delay and hence we need to re-verify certain conditions.
            boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
            if (isStaged) {
                mRet = verifyReplacingVersionCode(
                        pkgLite, requiredInstalledVersionCode, installFlags);
                if (mRet != INSTALL_SUCCEEDED) {
                    return;
                }
            }

            mRet = overrideInstallLocation(pkgLite);
        }

        @Override
        void handleReturnCode() {
            processPendingInstall();
        }

   		private void processPendingInstall() {
            InstallArgs args = createInstallArgs(this);
            if (mRet == PackageManager.INSTALL_SUCCEEDED) {
				// 这里会对apk进行拷贝。拷贝到/data/app/包名/ 目录下
                mRet = args.copyApk();
            }
            if (mRet == PackageManager.INSTALL_SUCCEEDED) {
				// 解压apk相关的一些资源
                F2fsUtils.releaseCompressedBlocks(
                        mContext.getContentResolver(), new File(args.getCodePath()));
            }
            if (mParentInstallParams != null) {
				// 安装多个APK
                mParentInstallParams.tryProcessInstallRequest(args, mRet);
            } else {
				// 安装一个APK
                PackageInstalledInfo res = createPackageInstalledInfo(mRet);
                processInstallRequestsAsync(
                        res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                        Collections.singletonList(new InstallRequest(args, res)));
            }
        }
}

processInstallRequestsAsync 异步安装APK。最终会调用PMS的installPackagesLI函数进行安装。安装流程包括四个流程:Prepare、Scan、Reconcile、Commit。安装后系统关于该APK的信息会更新,启动该APK时会以新的信息进行启动(安装成功状态)。

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
// Queue up an async operation since the package installation may take a little while.
private void processInstallRequestsAsync(boolean success,
		List<InstallRequest> installRequests) {
	mHandler.post(() -> {
		// 省略
		for (InstallRequest request : apkInstallRequests) {
			restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
					new PostInstallData(request.args, request.installResult, null));
		}
	});
}

// Queue up an async operation since the package installation may take a little while.
private void processInstallRequestsAsync(boolean success,
		List<InstallRequest> installRequests) {
	mHandler.post(() -> {
		// 省略...
		if (success) {
			for (InstallRequest request : apkInstallRequests) {
				request.args.doPreInstall(request.installResult.returnCode);
			}
			synchronized (mInstallLock) {
				// 安装APK
				installPackagesTracedLI(apkInstallRequests);
			}
			for (InstallRequest request : apkInstallRequests) {
				request.args.doPostInstall(
						request.installResult.returnCode, request.installResult.uid);
			}
		}
		for (InstallRequest request : apkInstallRequests) {
			restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
					new PostInstallData(request.args, request.installResult, null));
		}
	});
}


@GuardedBy("mInstallLock")
private void installPackagesTracedLI(List<InstallRequest> requests) {
	try {
		Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
		installPackagesLI(requests);
	} finally {
		Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
	}
}


@GuardedBy("mInstallLock")
private void installPackagesLI(List<InstallRequest> requests) {
	// 省略..
	// 安装APK Prepare-> Scan -> Reconcile -> Commit
	// Prepare: Analyzes any current install state, parses the package and does initial
	// Scan:Interrogates the parsed packages given the context collected in prepare
	// Reconcile:Validates scanned packages in the context of each other and the current system 
	// state to ensure that the install will be successful
	// Commit:Commits all scanned packages and updates system state. 
}

总结

通过adb install安装apk,大概流程是 adb(client)端通过socke命令给adbd(service),然后adbd通过ServiceManager以Binder方式将命令发送给PackageManagerService。PackageManagerService解析命令,复制APK及相关资源到指定路径,并更新系统中APK相关配置信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1402876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

S2-08 ESP-IDF开发 : 存储

S2-06 和 S2-07 暂时先不发&#xff0c;课上没给同学们将&#xff0c;分别是 DMA 和 USB 章节&#xff0c;作为专项讲 存储 ESP32 系列芯片中&#xff0c;不同型号的芯片所携带的 ROM、SRAM、RCT SRAM、PSRAM 以及 Flash大小不同&#xff0c;他们的作用如下&#xff1a; SRAM…

centos 启动nacos pg版本

背景&#xff1a;支持国产化需求&#xff0c;不再使用mysql 1.修改插件 git clone https://github.com/wuchubuzai2018/nacos-datasource-extend-plugins.git cd nacos-datasource-extend-plugins/nacos-postgresql-datasource-plugin-ext mvn package编译成功后&#xff0c;…

虚拟机将1.15版本的nginx推送到阿里云镜像仓库

1、docker images 2、docker login --usernamealiyun7279061146 registry.cn-shenzhen.aliyuncs.com 3、docker tag 53f3fd8007f7 registry.cn-shenzhen.aliyuncs.com/zhouwb/zhou:1.15 docker push registry.cn-shenzhen.aliyuncs.com/zhouwb/zhou:1.15

C++实战:类的包含编译模型

文章目录 一、实战概述二、实战步骤&#xff08;一&#xff09;C普通类的包含编译模型1、创建普通类定义文件2、创建普通类实现文件3、创建主程序文件4、运行主程序&#xff0c;查看结果 &#xff08;二&#xff09;C模板类的包含编译模型1、创建模板类定义文件2、创建模板类实…

【Leetcode 144.二叉树的前序遍历】将二叉树每个节点的值以前序遍历的顺序存入数组中

int* preorderTraversal( struct TreeNode*root, int* returnSize) { }解答代码&#xff1a; int TreeSize(struct TreeNode*root){return rootNULL?0:TreeSize(root->left)TreeSize(root->right)1;}void Prevorder(struct TreeNode*root,int*a,int*pi){if(rootNULL)re…

内网穿透的应用-如何使用Docker部署Redis数据库并结合内网穿透工具实现公网远程访问

文章目录 前言1. 安装Docker步骤2. 使用docker拉取redis镜像3. 启动redis容器4. 本地连接测试4.1 安装redis图形化界面工具4.2 使用RDM连接测试 5. 公网远程访问本地redis5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主要介绍如何在Ub…

代码随想录算法训练DAY25|回溯2

算法训练DAY25|回溯2 216.组合总和III 力扣题目链接 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数&#xff0c;并且每种组合中不存在重复的数字。 说明&#xff1a; 所有数字都是正整数。 解集不能包含重复的组合。 示例 1: 输入: k 3, n …

【并发编程】synchornized原理

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;并发编程 ⛺️稳重求进&#xff0c;晒太阳 目录 Monitor概念 Java对象头 普通对象 数组对象 Monitor(锁) Monitor结构如下&#xff1a; 注意&#xff1a; 原理之synchornized 轻量…

压力容器多开孔结构静力分析APP

压力容器多开孔结构静力分析APP对带有多个接管的容器结构在内压作用下进行静力分析&#xff0c;考察相邻接管开孔对容器及接管强度的影响。通过对容器和接管的几何尺寸、材料属性、载荷等进行参数化&#xff0c;以方便设计工程师对不同参数下的此类结构进行仿真分析。 近年来&a…

透明拼接屏方案,从底层设计到应用尽情了解

一、引言 随着科技的飞速发展&#xff0c;显示技术也在不断创新。透明拼接屏方案作为一种新型的显示技术&#xff0c;以其独特的透明设计和灵活的拼接特性&#xff0c;在商业展示、广告、建筑等领域得到广泛应用。本文将深入探讨透明拼接屏方案的设计、实现方式、技术逻辑、应…

STM32之RTC实时时钟

一、实时时钟概述 1、实时时钟介绍 英文缩写&#xff1a;RTC。显示年、月、日、时、分、秒、星期,自动计算闰年&#xff0c;能够区分每个月的天数。 RTC特点&#xff1a;能从RTC获取到具体的日期时间&#xff0c;断掉后再开机时间仍然准确&#xff08;需要纽扣电池&#xff…

如何控制项目管理中的日程冲突?

《全球公司生产力报告》发现&#xff0c;62% 的公司领导表示&#xff0c;资源调度是他们在项目管理方面面临的最大挑战。其中&#xff0c;日程冲突是利用共享资源池管理多个项目的典型挑战。例如&#xff0c;团队成员参与的活动可能会重叠&#xff0c;也可能是任务分配给了无法…

漏洞复现-SpringBlade export-user SQL 注入漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

【MySQL】NET HELPMSG 3534 报错解决

问题&#xff1a; 解决方案&#xff1a; 注意&#xff1a;确保自己是否使用了带管理员权限的命令窗口。 1.清空你的 MySQL 下的 data 文件夹&#xff1b; 2.确保系统环境变量中已经配置了 mysql 的 bin 目录到Path中&#xff1b; 3.执行以下命令&#xff1a; mysql8为我自己…

【linux】 查看 Linux 重启历史记录(reboot)

了解 Linux 重启日志 /var/log 目录隐藏着 Linux 日志机制的核心信息&#xff0c;它是记录系统活动的宝贵仓库。然而&#xff0c;仅仅有日志还不够&#xff0c;真正的难题在于&#xff0c;如何从大量数据中提炼出与系统重启相关的关键信息。 在 /var/log 目录中&#xff0c;可…

力扣746. 使用最小花费爬楼梯

动态规划 思路&#xff1a; 定义 dp[i] 为到达下标 i 层的最小花费&#xff1b;则状态转移方程为&#xff1a; 第 i 层可以从第 i - 1 层爬一层或者第 i - 2 层爬两层到达&#xff1b;则 dp[i] std::min(dp[i - 1] cost[i - 1], dp[i - 2] cost[i - 2])初始状态&#xff1a…

【操作系统】实验一 Linux操作系统安装

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的很重要&…

Tofu5m目标识别跟踪器

Tofu5m 是高性价比目标识别跟踪模块&#xff0c;支持可见光视频或红外网络视频的输入&#xff0c;支持视频下的多类型物体检测、识别、跟踪等功能。 产品支持视频编码、设备管理、目标检测、深度学习识别、跟踪等功能&#xff0c;提供多机版与触控版管理软件&#xff0c;为二次…

Ant Design Vue 的a-tree-select中的show-search不生效问题

解决方案&#xff1a; 1、配置show-search 2、配置tree-node-filter-prop tree-node-filter-prop的值为接口返回的显示文本&#xff0c;就是你下拉框显示的那个本文 演示&#xff1a;

Web03--CSS进阶

1、CSS常用属性 1.1 文本字体相关属性设置 样式名 描述 text-align 设置内容位置 text-decoration 控制下划线 none没有 underline有 line-hight 行高 font-size 设置字体大小 font-weight 设置字体粗细的 font-famliy 设置字体样式 letter-spacing 设置中文字…