Adb和PMS安裝apk源碼流程
adb install命令
通過adb install命令可以將apk安裝到Android系統(tǒng)(注意:特定類型的apk,比如persist類型是無法通過adb安裝的)
下述命令中adb解析install命令,并調(diào)用Android PackageManagerService進(jìn)行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命令的源碼實(shí)現(xiàn)
Android中adb的源碼被放在 “packages/modules/adb”這個(gè)倉庫中,這個(gè)倉庫編譯后的主要成果物是adbd和**adb。**adbd是a服務(wù)端進(jìn)程,adb是提供的客戶端工具。adb和adbd兩者間,通過socket完成相互間的通信。
# packages/modules/adb/Android.bp
# adbd,在Android系統(tǒng)中運(yùn)行
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端(就是主機(jī)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",
],
# 省略...
}
這里關(guān)注adb install命令對(duì)應(yīng)的源碼實(shí)現(xiàn),adb這個(gè)bin程序?qū)?yīng)的main函數(shù)定義在“packages/modules/adb/client/main.cpp”,main函數(shù)中調(diào)用adb_trace_init進(jìn)行Trace(記錄運(yùn)行Log)的初始化,然后調(diào)用adb_commandline解析adb命令參數(shù)。
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);
// 這里忽略了第一個(gè)入?yún)ⅲǔ绦蛎约海?/span>
return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
}
adb_commandline函數(shù)在"packages/modules/adb/client/commandline.cpp"中實(shí)現(xiàn),在這個(gè)函數(shù)中解析adb命令的參數(shù)。如果是adb install命令,會(huì)調(diào)用install_app函數(shù)進(jìn)行APK安裝的相關(guān)流程。
int adb_commandline(int argc, const char** argv) {
// 省略...
// 解析各個(gè)參數(shù)
while (argc > 0) {
// 解析第一個(gè)參數(shù)。就是adb命令后第一個(gè)參數(shù)
if (!strcmp(argv[0], "server")) {
// 省略了很多代碼...
} else {
// adb install 的情況下走這里,跳出循環(huán)
/* out of recognized modifiers and flags */
break;
}
argc--;
argv++;
}
// 省略...
/* adb_connect() commands */
if (!strcmp(argv[0], "devices")) {
// 省略了很多代碼(對(duì)各個(gè)命令的判斷)
} else if (!strcmp(argv[0], "install")) {
// 判斷參數(shù)為install,執(zhí)行app安裝相關(guān)函數(shù)
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")) {
// 省略...
}
// 省略...
// 如果輸入了錯(cuò)誤的參數(shù),會(huì)報(bào)下面的錯(cuò)誤,并結(jié)束此次adb命令的執(zhí)行
error_exit("unknown command %s", argv[0]);
__builtin_unreachable();
}
install_app函數(shù)在“packages/modules/adb/client/adb_install.cpp”中定義。該函數(shù)先判斷APK的安裝模式是
INSTALL_PUSH/INSTALL_STREAM/INSTALL_INCREMENTAL中哪一種。默認(rèn)情況下是INSTALL_PUSH模式,然后調(diào)用install_app_legacy函數(shù)進(jìn)行APK安裝。
- INSTALL_PUSH:通過推送的方式安裝APK,將APK整個(gè)推送到設(shè)置上進(jìn)行安裝。
- INSTALL_STREAM:流式傳輸安裝APK,APK被分割成多份并在安裝過程中逐個(gè)傳輸?shù)较到y(tǒng)設(shè)置上進(jìn)行組裝和安裝,這種方式可以減少安裝的時(shí)間(如果系統(tǒng)支持,默認(rèn)會(huì)使用這種方式安裝)
- INSTALL_INCREMENTAL:增量方式安裝APK,僅安裝差異的部分不需要重新安裝整個(gè)Apk,加速apk安裝時(shí)間。大型的APK(如GB級(jí)別)應(yīng)用較多(需要系統(tǒng)支持)
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;
// 進(jìn)行安裝默認(rèn)的判斷,通過parse_install_mode/parse_fast_deploy_mode/calculate_install_mode實(shí)現(xiàn)
// 具體實(shí)現(xiàn)方式請(qǐng)自行查看源碼,這里就不關(guān)注了
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默認(rèn)使用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");
}
};
// 如果安裝失敗,會(huì)使用fallback mode再次安裝。默認(rèn)情況下,fallback mode是空(不進(jìn)行安裝)
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函數(shù)定義在"packages/modules/adb/client/adb_install.cpp"中。函數(shù)執(zhí)行時(shí),會(huì)在終端輸出"Performing Push Install"提示使用者。函數(shù)中判斷adb install命令是否以.apk字符結(jié)束,并將apk文件push到/data/local/tmp/目錄下。然后調(diào)用pm_command函數(shù)安裝/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結(jié)尾。如果沒有就認(rèn)為沒有提供待安裝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的形式,報(bào)錯(cuò)。
if (last_apk == -1) error_exit("need APK file on command line");
// 創(chuàng)建臨時(shí)目錄 /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 */
// 如果使用快速部署(默認(rèn)為false)
if (use_fastdeploy) {
// 省略 ...
}
// 將Apk push到/data/local/tmp/目錄下
if (do_sync_push(apk_file, apk_dest.c_str(), false, CompressionType::Any, false)) {
// 執(zhí)行安裝
result = pm_command(argc, argv);
// 安裝完成后,刪除臨時(shí)目錄/data/local/tmp/下的apk文件。
delete_device_file(apk_dest);
}
return result;
}
pm_command函數(shù),顧名思義給執(zhí)行pm(PackageManager)相關(guān)的命令。所以在函數(shù)中,為字符串拼接了 "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);
// 將命令發(fā)送給adbd,由adbd執(zhí)(注意adb運(yùn)行在Host端,比如PC。adbd才是運(yùn)行在Android系統(tǒng)上的服務(wù))
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服務(wù)端的處理流程
adbd(daemon進(jìn)程)在收到Client端(adb)請(qǐng)求,并執(zhí)行相關(guān)動(dòng)作。在函數(shù)StartCommandInProcess中,執(zhí)行客戶端發(fā)過來的 “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;
// 讀取客戶端的請(qǐng)求
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;
}
// 處理請(qǐng)求命令,具體實(shí)現(xiàn)可以參考源碼。
// 基本上就是創(chuàng)建了一個(gè)Process,在Process中執(zhí)行傳過來的命令。
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));
// 處理結(jié)果發(fā)送給客戶端
if (android::base::SendFileDescriptors(fd, "", 1, result.get()) != 1) {
PLOG(ERROR) << "Failed to send an inprocess fd for command: " << data;
break;
}
}
}
pm命令的處理流程
上述流程中最終執(zhí)行的是 pm install -r -t -d /data/local/tmp/linduo.apk。Android pm命令實(shí)際上是一段bash程序。實(shí)現(xiàn)在frameworks/base/cmds/pm/pm中,只是簡(jiǎn)單的調(diào)用了cmd package,并將入?yún)髁诉M(jìn)去。
#!/system/bin/sh
cmd package "$@"
cmd是一個(gè)bin程序,其實(shí)現(xiàn)在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",
],
}
如果調(diào)用的是cmd package,cmd程序中會(huì)通過Android 的ServiceManager連接到PMS服務(wù)。然后將命令通過binder發(fā)送給PMS服務(wù)。
// frameworks/native/cmds/cmd/main.cpp
#include <unistd.h>
#include "cmd.h"
int main(int argc, char* const argv[]) {
signal(SIGPIPE, SIG_IGN);
// 這里將入?yún)⒌牡谝粋€(gè)參數(shù)去掉。比如 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程序中調(diào)用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對(duì)象
sp<IServiceManager> sm = defaultServiceManager();
// 這里判斷一下,cmd命令中想要調(diào)用的服務(wù)在當(dāng)前系統(tǒng)中是否存在。不存在則返回
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選項(xiàng)。
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
// 這里將命令發(fā)送給對(duì)應(yīng)的服務(wù)端執(zhí)行。
// TODO: block until a result is returned to MyResultReceiver.
status_t error = IBinder::shellCommand(service, in, out, err, args, cb, result);
// 省略...
}
PackageManagerService接收安裝Apk的請(qǐng)求,將Apk安裝到Android系統(tǒng)
adb將安裝apk的命令發(fā)送到adbd(服務(wù)端),adbd通過binder調(diào)用PMS服務(wù)安裝APK。PMS接收到shell調(diào)用后,會(huì)創(chuàng)建PackageManagerShellCommand對(duì)象并調(diào)用它exec函數(shù)的進(jìn)行處理。
@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函數(shù),有其繼承的父類定義。該函數(shù)中會(huì)調(diào)用onCommand解析命令并調(diào)用不同的處理分支。對(duì)于本文中的情況(執(zhí)行INSTALL_PUSH方式安裝)會(huì)調(diào)用runInstall函數(shù)進(jìn)行處理。runInstall函數(shù)中調(diào)用makeInstallParams將組織APK安裝的參數(shù),然后調(diào)用doRunInstall進(jìn)程安裝。
// 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函數(shù)會(huì)根據(jù)adb install [apk相關(guān)參數(shù)] 時(shí)輸入的參數(shù)進(jìn)行組織。其實(shí)現(xiàn)如下
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
// 例如: adb install -t -r -d linduo.apk(注意安裝路徑會(huì)被替換成 /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函數(shù)根據(jù)安裝參數(shù)進(jìn)行APK的安裝,該函數(shù)主要做了兩個(gè)事情。一個(gè)是通過doCreateSession函數(shù),創(chuàng)建了PackageInstallerSession對(duì)象,做了些Apk安裝準(zhǔn)工作。另一個(gè)是通過doCommitSession函數(shù),利用PackageInstaller.Session對(duì)象進(jìn)行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);
}
}
// 創(chuàng)建SessionID(PMS會(huì)創(chuàng)建PackageInstallerSession對(duì)象),可以理解成創(chuàng)建了安裝APK的任務(wù)
// 通過調(diào)用PackageInstallerService的createSession實(shí)現(xiàn)
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),主要關(guān)注這個(gè)函數(shù)。
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函數(shù)中創(chuàng)建了PackageInstaller.Session對(duì)象,通過與上面創(chuàng)建的sessionId進(jìn)行綁定。然后調(diào)用PackageInstaller.Session.commit進(jìn)行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();
//調(diào)用commit安裝APK
session.commit(receiver.getIntentSender());
final Intent result = receiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
// 判斷APK安裝狀態(tài)
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的實(shí)現(xiàn)如下,調(diào)用了IPackageInstallerSession(通過mInterface.getPackageInstaller().openSession(sessionId)取得)對(duì)象的commit函數(shù)。
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函數(shù),實(shí)現(xiàn)在"frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java“。commit函數(shù)中,會(huì)將處理轉(zhuǎn)到自身的Handle中。通過一系列調(diào)用commit -> dispatchSessionSealed -> handleSessionSealed -> dispatchStreamValidateAndCommit -> handleStreamValidateAndCommit -> handleInstall -> verify -> verifyNonStaged,在verifyNonStaged函數(shù)中,調(diào)用PMS的verifyStage驗(yàn)證APK。驗(yàn)證成功后,通過onVerificationComplete回調(diào),調(diào)用install函數(shù),安裝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() {
// 轉(zhuǎn)到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() {
// 檢查、驗(yàn)證APK包
verify();
}
private void verify() {
try {
verifyNonStaged();
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
onSessionVerificationFailure(e.error, completeMsg);
}
}
// 調(diào)用PMS的verifyStage,驗(yàn)證APK。驗(yàn)證成功會(huì),調(diào)用install方法進(jìn)行安裝。
private void verifyNonStaged()
throws PackageManagerException {
final PackageManagerService.VerificationParams verifyingSession =
prepareForVerification();
if (verifyingSession == null) {
return;
}
if (isMultiPackage()) {
// 省略
mPm.verifyStage(verifyingSession, verifyingChildSessions);
} else {
mPm.verifyStage(verifyingSession);
}
}
// 驗(yàn)證成功,通過回調(diào)。調(diào)用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函數(shù)中,調(diào)用了PMS的installStage函數(shù),對(duì)APK進(jìn)行了安裝。
// 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);
}
}
調(diào)用PMS的installStage函數(shù),安裝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會(huì)對(duì)APK進(jìn)行實(shí)際的安裝。
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void installStage(InstallParams params) {
// 首先進(jìn)行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);
}
轉(zhuǎn)Handle處理INIT_COPY,調(diào)用startCopy函數(shù),在startCopy函數(shù)中調(diào)用handleStartCopy和handleReturnCode進(jìn)行APK的拷貝,從/data/local/tmp/目錄把APK文件拷貝拷貝到/data/app/包名/目錄。然后調(diào)用processInstallRequestsAsync進(jìn)行安裝。
// 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 {
// 根據(jù)安裝Flag,進(jìn)行預(yù)處理
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) {
// 這里會(huì)對(duì)apk進(jìn)行拷貝??截惖?data/app/包名/ 目錄下
mRet = args.copyApk();
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
// 解壓apk相關(guān)的一些資源
F2fsUtils.releaseCompressedBlocks(
mContext.getContentResolver(), new File(args.getCodePath()));
}
if (mParentInstallParams != null) {
// 安裝多個(gè)APK
mParentInstallParams.tryProcessInstallRequest(args, mRet);
} else {
// 安裝一個(gè)APK
PackageInstalledInfo res = createPackageInstalledInfo(mRet);
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
}
processInstallRequestsAsync 異步安裝APK。最終會(huì)調(diào)用PMS的installPackagesLI函數(shù)進(jìn)行安裝。安裝流程包括四個(gè)流程:Prepare、Scan、Reconcile、Commit。安裝后系統(tǒng)關(guān)于該APK的信息會(huì)更新,啟動(dòng)該APK時(shí)會(huì)以新的信息進(jìn)行啟動(dòng)(安裝成功狀態(tài))。文章來源:http://www.zghlxwxcb.cn/news/detail-814068.html
// 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.
}
總結(jié)
通過adb install安裝apk,大概流程是 adb(client)端通過socke命令給adbd(service),然后adbd通過ServiceManager以Binder方式將命令發(fā)送給PackageManagerService。PackageManagerService解析命令,復(fù)制APK及相關(guān)資源到指定路徑,并更新系統(tǒng)中APK相關(guān)配置信息。文章來源地址http://www.zghlxwxcb.cn/news/detail-814068.html
到了這里,關(guān)于【Android12】Android Framework系列---Adb和PMS安裝apk源碼流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!