1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "adb_install.h" 18 19 #include <fcntl.h> 20 #include <inttypes.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <unistd.h> 24 #include <algorithm> 25 #include <string> 26 #include <string_view> 27 #include <vector> 28 29 #include <android-base/file.h> 30 #include <android-base/parsebool.h> 31 #include <android-base/stringprintf.h> 32 #include <android-base/strings.h> 33 34 #include "adb.h" 35 #include "adb_client.h" 36 #include "adb_unique_fd.h" 37 #include "adb_utils.h" 38 #include "client/file_sync_client.h" 39 #include "commandline.h" 40 #include "fastdeploy.h" 41 #include "incremental.h" 42 43 using namespace std::literals; 44 45 static constexpr int kFastDeployMinApi = 24; 46 47 namespace { 48 49 enum InstallMode { 50 INSTALL_DEFAULT, 51 INSTALL_PUSH, 52 INSTALL_STREAM, 53 INSTALL_INCREMENTAL, 54 }; 55 56 enum class CmdlineOption { None, Enable, Disable }; 57 } 58 59 static bool can_use_feature(const char* feature) { 60 // We ignore errors here, if the device is missing, we'll notice when we try to push install. 61 auto&& features = adb_get_feature_set(nullptr); 62 if (!features) { 63 return false; 64 } 65 return CanUseFeature(*features, feature); 66 } 67 68 static InstallMode best_install_mode() { 69 if (can_use_feature(kFeatureCmd)) { 70 return INSTALL_STREAM; 71 } 72 return INSTALL_PUSH; 73 } 74 75 static bool is_apex_supported() { 76 return can_use_feature(kFeatureApex); 77 } 78 79 static bool is_abb_exec_supported() { 80 return can_use_feature(kFeatureAbbExec); 81 } 82 83 static int pm_command(int argc, const char** argv) { 84 std::string cmd = "pm"; 85 86 while (argc-- > 0) { 87 cmd += " " + escape_arg(*argv++); 88 } 89 90 return send_shell_command(cmd); 91 } 92 93 static int uninstall_app_streamed(int argc, const char** argv) { 94 // 'adb uninstall' takes the same arguments as 'cmd package uninstall' on device 95 std::string cmd = "cmd package"; 96 while (argc-- > 0) { 97 // deny the '-k' option until the remaining data/cache can be removed with adb/UI 98 if (strcmp(*argv, "-k") == 0) { 99 printf("The -k option uninstalls the application while retaining the " 100 "data/cache.\n" 101 "At the moment, there is no way to remove the remaining data.\n" 102 "You will have to reinstall the application with the same " 103 "signature, and fully " 104 "uninstall it.\n" 105 "If you truly wish to continue, execute 'adb shell cmd package " 106 "uninstall -k'.\n"); 107 return EXIT_FAILURE; 108 } 109 cmd += " " + escape_arg(*argv++); 110 } 111 112 return send_shell_command(cmd); 113 } 114 115 static int uninstall_app_legacy(int argc, const char** argv) { 116 /* if the user choose the -k option, we refuse to do it until devices are 117 out with the option to uninstall the remaining data somehow (adb/ui) */ 118 for (int i = 1; i < argc; i++) { 119 if (!strcmp(argv[i], "-k")) { 120 printf("The -k option uninstalls the application while retaining the " 121 "data/cache.\n" 122 "At the moment, there is no way to remove the remaining data.\n" 123 "You will have to reinstall the application with the same " 124 "signature, and fully " 125 "uninstall it.\n" 126 "If you truly wish to continue, execute 'adb shell pm uninstall " 127 "-k'\n."); 128 return EXIT_FAILURE; 129 } 130 } 131 132 /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */ 133 return pm_command(argc, argv); 134 } 135 136 int uninstall_app(int argc, const char** argv) { 137 if (best_install_mode() == INSTALL_PUSH) { 138 return uninstall_app_legacy(argc, argv); 139 } 140 return uninstall_app_streamed(argc, argv); 141 } 142 143 static void read_status_line(int fd, char* buf, size_t count) { 144 count--; 145 while (count > 0) { 146 int len = adb_read(fd, buf, count); 147 if (len <= 0) { 148 break; 149 } 150 151 buf += len; 152 count -= len; 153 } 154 *buf = '\0'; 155 } 156 157 static unique_fd send_command(const std::vector<std::string>& cmd_args, std::string* error) { 158 if (is_abb_exec_supported()) { 159 return send_abb_exec_command(cmd_args, error); 160 } else { 161 return unique_fd(adb_connect(android::base::Join(cmd_args, " "), error)); 162 } 163 } 164 165 static int install_app_streamed(int argc, const char** argv, bool use_fastdeploy) { 166 printf("Performing Streamed Install\n"); 167 168 // The last argument must be the APK file 169 const char* file = argv[argc - 1]; 170 if (!android::base::EndsWithIgnoreCase(file, ".apk") && 171 !android::base::EndsWithIgnoreCase(file, ".apex")) { 172 error_exit("filename doesn't end .apk or .apex: %s", file); 173 } 174 175 bool is_apex = false; 176 if (android::base::EndsWithIgnoreCase(file, ".apex")) { 177 is_apex = true; 178 } 179 if (is_apex && !is_apex_supported()) { 180 error_exit(".apex is not supported on the target device"); 181 } 182 183 if (is_apex && use_fastdeploy) { 184 error_exit("--fastdeploy doesn't support .apex files"); 185 } 186 187 if (use_fastdeploy) { 188 auto metadata = extract_metadata(file); 189 if (metadata.has_value()) { 190 // pass all but 1st (command) and last (apk path) parameters through to pm for 191 // session creation 192 std::vector<const char*> pm_args{argv + 1, argv + argc - 1}; 193 auto patchFd = install_patch(pm_args.size(), pm_args.data()); 194 return stream_patch(file, std::move(metadata.value()), std::move(patchFd)); 195 } 196 } 197 198 struct stat sb; 199 if (stat(file, &sb) == -1) { 200 fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno)); 201 return 1; 202 } 203 204 unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC)); 205 if (local_fd < 0) { 206 fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno)); 207 return 1; 208 } 209 210 #ifdef __linux__ 211 posix_fadvise(local_fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE); 212 #endif 213 214 const bool use_abb_exec = is_abb_exec_supported(); 215 std::string error; 216 std::vector<std::string> cmd_args = {use_abb_exec ? "package" : "exec:cmd package"}; 217 cmd_args.reserve(argc + 3); 218 219 // don't copy the APK name, but, copy the rest of the arguments as-is 220 while (argc-- > 1) { 221 if (use_abb_exec) { 222 cmd_args.push_back(*argv++); 223 } else { 224 cmd_args.push_back(escape_arg(*argv++)); 225 } 226 } 227 228 // add size parameter [required for streaming installs] 229 // do last to override any user specified value 230 cmd_args.push_back("-S"); 231 cmd_args.push_back(android::base::StringPrintf("%" PRIu64, static_cast<uint64_t>(sb.st_size))); 232 233 if (is_apex) { 234 cmd_args.push_back("--apex"); 235 } 236 237 unique_fd remote_fd = send_command(cmd_args, &error); 238 if (remote_fd < 0) { 239 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str()); 240 return 1; 241 } 242 243 if (!copy_to_file(local_fd.get(), remote_fd.get())) { 244 fprintf(stderr, "adb: failed to install: copy_to_file: %s: %s", file, strerror(errno)); 245 return 1; 246 } 247 248 char buf[BUFSIZ]; 249 read_status_line(remote_fd.get(), buf, sizeof(buf)); 250 if (strncmp("Success", buf, 7) != 0) { 251 fprintf(stderr, "adb: failed to install %s: %s", file, buf); 252 return 1; 253 } 254 255 fputs(buf, stdout); 256 return 0; 257 } 258 259 static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy) { 260 printf("Performing Push Install\n"); 261 262 // Find last APK argument. 263 // All other arguments passed through verbatim. 264 int last_apk = -1; 265 for (int i = argc - 1; i >= 0; i--) { 266 if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) { 267 error_exit("APEX packages are only compatible with Streamed Install"); 268 } 269 if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) { 270 last_apk = i; 271 break; 272 } 273 } 274 275 if (last_apk == -1) error_exit("need APK file on command line"); 276 277 int result = -1; 278 std::vector<const char*> apk_file = {argv[last_apk]}; 279 std::string apk_dest = "/data/local/tmp/" + android::base::Basename(argv[last_apk]); 280 argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */ 281 282 if (use_fastdeploy) { 283 auto metadata = extract_metadata(apk_file[0]); 284 if (metadata.has_value()) { 285 auto patchFd = apply_patch_on_device(apk_dest.c_str()); 286 int status = stream_patch(apk_file[0], std::move(metadata.value()), std::move(patchFd)); 287 288 result = pm_command(argc, argv); 289 delete_device_file(apk_dest); 290 291 return status; 292 } 293 } 294 295 if (do_sync_push(apk_file, apk_dest.c_str(), false, CompressionType::Any, false)) { 296 result = pm_command(argc, argv); 297 delete_device_file(apk_dest); 298 } 299 300 return result; 301 } 302 303 template <class TimePoint> 304 static int ms_between(TimePoint start, TimePoint end) { 305 return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); 306 } 307 308 static int install_app_incremental(int argc, const char** argv, bool wait, bool silent) { 309 using clock = std::chrono::high_resolution_clock; 310 const auto start = clock::now(); 311 int first_apk = -1; 312 int last_apk = -1; 313 incremental::Args passthrough_args = {}; 314 for (int i = 0; i < argc; ++i) { 315 const auto arg = std::string_view(argv[i]); 316 if (android::base::EndsWithIgnoreCase(arg, ".apk"sv)) { 317 last_apk = i; 318 if (first_apk == -1) { 319 first_apk = i; 320 } 321 } else if (arg.starts_with("install"sv)) { 322 // incremental installation command on the device is the same for all its variations in 323 // the adb, e.g. install-multiple or install-multi-package 324 } else { 325 passthrough_args.push_back(arg); 326 } 327 } 328 329 if (first_apk == -1) { 330 if (!silent) { 331 fprintf(stderr, "error: need at least one APK file on command line\n"); 332 } 333 return -1; 334 } 335 336 auto files = incremental::Files{argv + first_apk, argv + last_apk + 1}; 337 if (silent) { 338 // For a silent installation we want to do the lightweight check first and bail early and 339 // quietly if it fails. 340 if (!incremental::can_install(files)) { 341 return -1; 342 } 343 } 344 345 printf("Performing Incremental Install\n"); 346 auto server_process = incremental::install(files, passthrough_args, silent); 347 if (!server_process) { 348 return -1; 349 } 350 351 const auto end = clock::now(); 352 printf("Install command complete in %d ms\n", ms_between(start, end)); 353 354 if (wait) { 355 (*server_process).wait(); 356 } 357 358 return 0; 359 } 360 361 static std::pair<InstallMode, std::optional<InstallMode>> calculate_install_mode( 362 InstallMode modeFromArgs, bool fastdeploy, CmdlineOption incremental_request) { 363 if (incremental_request == CmdlineOption::Enable) { 364 if (fastdeploy) { 365 error_exit( 366 "--incremental and --fast-deploy options are incompatible. " 367 "Please choose one"); 368 } 369 } 370 371 if (modeFromArgs != INSTALL_DEFAULT) { 372 if (incremental_request == CmdlineOption::Enable) { 373 error_exit("--incremental is not compatible with other installation modes"); 374 } 375 return {modeFromArgs, std::nullopt}; 376 } 377 378 if (incremental_request != CmdlineOption::Disable && !is_abb_exec_supported()) { 379 if (incremental_request == CmdlineOption::None) { 380 incremental_request = CmdlineOption::Disable; 381 } else { 382 error_exit("Device doesn't support incremental installations"); 383 } 384 } 385 if (incremental_request == CmdlineOption::None) { 386 // check if the host is ok with incremental by default 387 if (const char* incrementalFromEnv = getenv("ADB_INSTALL_DEFAULT_INCREMENTAL")) { 388 using namespace android::base; 389 auto val = ParseBool(incrementalFromEnv); 390 if (val == ParseBoolResult::kFalse) { 391 incremental_request = CmdlineOption::Disable; 392 } 393 } 394 } 395 if (incremental_request == CmdlineOption::None) { 396 // still ok: let's see if the device allows using incremental by default 397 // it starts feeling like we're looking for an excuse to not to use incremental... 398 std::string error; 399 std::vector<std::string> args = {"settings", "get", 400 "enable_adb_incremental_install_default"}; 401 auto fd = send_abb_exec_command(args, &error); 402 if (!fd.ok()) { 403 fprintf(stderr, "adb: retrieving the default device installation mode failed: %s", 404 error.c_str()); 405 } else { 406 char buf[BUFSIZ] = {}; 407 read_status_line(fd.get(), buf, sizeof(buf)); 408 using namespace android::base; 409 auto val = ParseBool(buf); 410 if (val == ParseBoolResult::kFalse) { 411 incremental_request = CmdlineOption::Disable; 412 } 413 } 414 } 415 416 if (incremental_request == CmdlineOption::Enable) { 417 // explicitly requested - no fallback 418 return {INSTALL_INCREMENTAL, std::nullopt}; 419 } 420 const auto bestMode = best_install_mode(); 421 if (incremental_request == CmdlineOption::None) { 422 // no opinion - use incremental, fallback to regular on a failure. 423 return {INSTALL_INCREMENTAL, bestMode}; 424 } 425 // incremental turned off - use the regular best mode without a fallback. 426 return {bestMode, std::nullopt}; 427 } 428 429 static std::vector<const char*> parse_install_mode(std::vector<const char*> argv, 430 InstallMode* install_mode, 431 CmdlineOption* incremental_request, 432 bool* incremental_wait) { 433 *install_mode = INSTALL_DEFAULT; 434 *incremental_request = CmdlineOption::None; 435 *incremental_wait = false; 436 437 std::vector<const char*> passthrough; 438 for (auto&& arg : argv) { 439 if (arg == "--streaming"sv) { 440 *install_mode = INSTALL_STREAM; 441 } else if (arg == "--no-streaming"sv) { 442 *install_mode = INSTALL_PUSH; 443 } else if (strlen(arg) >= "--incr"sv.size() && "--incremental"sv.starts_with(arg)) { 444 *incremental_request = CmdlineOption::Enable; 445 } else if (strlen(arg) >= "--no-incr"sv.size() && "--no-incremental"sv.starts_with(arg)) { 446 *incremental_request = CmdlineOption::Disable; 447 } else if (arg == "--wait"sv) { 448 *incremental_wait = true; 449 } else { 450 passthrough.push_back(arg); 451 } 452 } 453 return passthrough; 454 } 455 456 static std::vector<const char*> parse_fast_deploy_mode( 457 std::vector<const char*> argv, bool* use_fastdeploy, 458 FastDeploy_AgentUpdateStrategy* agent_update_strategy) { 459 *use_fastdeploy = false; 460 *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion; 461 462 std::vector<const char*> passthrough; 463 for (auto&& arg : argv) { 464 if (arg == "--fastdeploy"sv) { 465 *use_fastdeploy = true; 466 } else if (arg == "--no-fastdeploy"sv) { 467 *use_fastdeploy = false; 468 } else if (arg == "--force-agent"sv) { 469 *agent_update_strategy = FastDeploy_AgentUpdateAlways; 470 } else if (arg == "--date-check-agent"sv) { 471 *agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp; 472 } else if (arg == "--version-check-agent"sv) { 473 *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion; 474 } else { 475 passthrough.push_back(arg); 476 } 477 } 478 return passthrough; 479 } 480 481 int install_app(int argc, const char** argv) { 482 InstallMode install_mode = INSTALL_DEFAULT; 483 auto incremental_request = CmdlineOption::None; 484 bool incremental_wait = false; 485 486 bool use_fastdeploy = false; 487 FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion; 488 489 auto unused_argv = parse_install_mode({argv, argv + argc}, &install_mode, &incremental_request, 490 &incremental_wait); 491 auto passthrough_argv = 492 parse_fast_deploy_mode(std::move(unused_argv), &use_fastdeploy, &agent_update_strategy); 493 494 auto [primary_mode, fallback_mode] = 495 calculate_install_mode(install_mode, use_fastdeploy, incremental_request); 496 if ((primary_mode == INSTALL_STREAM || 497 fallback_mode.value_or(INSTALL_PUSH) == INSTALL_STREAM) && 498 best_install_mode() == INSTALL_PUSH) { 499 error_exit("Attempting to use streaming install on unsupported device"); 500 } 501 502 if (use_fastdeploy && get_device_api_level() < kFastDeployMinApi) { 503 fprintf(stderr, 504 "Fast Deploy is only compatible with devices of API version %d or higher, " 505 "ignoring.\n", 506 kFastDeployMinApi); 507 use_fastdeploy = false; 508 } 509 fastdeploy_set_agent_update_strategy(agent_update_strategy); 510 511 if (passthrough_argv.size() < 2) { 512 error_exit("install requires an apk argument"); 513 } 514 515 auto run_install_mode = [&](InstallMode install_mode, bool silent) { 516 switch (install_mode) { 517 case INSTALL_PUSH: 518 return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(), 519 use_fastdeploy); 520 case INSTALL_STREAM: 521 return install_app_streamed(passthrough_argv.size(), passthrough_argv.data(), 522 use_fastdeploy); 523 case INSTALL_INCREMENTAL: 524 return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(), 525 incremental_wait, silent); 526 case INSTALL_DEFAULT: 527 default: 528 error_exit("invalid install mode"); 529 } 530 }; 531 auto res = run_install_mode(primary_mode, fallback_mode.has_value()); 532 if (res && fallback_mode.value_or(primary_mode) != primary_mode) { 533 res = run_install_mode(*fallback_mode, false); 534 } 535 return res; 536 } 537 538 static int install_multiple_app_streamed(int argc, const char** argv) { 539 // Find all APK arguments starting at end. 540 // All other arguments passed through verbatim. 541 int first_apk = -1; 542 uint64_t total_size = 0; 543 for (int i = argc - 1; i >= 0; i--) { 544 const char* file = argv[i]; 545 if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) { 546 error_exit("APEX packages are not compatible with install-multiple"); 547 } 548 549 if (android::base::EndsWithIgnoreCase(file, ".apk") || 550 android::base::EndsWithIgnoreCase(file, ".dm") || 551 android::base::EndsWithIgnoreCase(file, ".fsv_sig")) { 552 struct stat sb; 553 if (stat(file, &sb) == -1) perror_exit("failed to stat \"%s\"", file); 554 total_size += sb.st_size; 555 first_apk = i; 556 } else { 557 break; 558 } 559 } 560 561 if (first_apk == -1) error_exit("need APK file on command line"); 562 563 const bool use_abb_exec = is_abb_exec_supported(); 564 const std::string install_cmd = 565 use_abb_exec ? "package" 566 : best_install_mode() == INSTALL_PUSH ? "exec:pm" : "exec:cmd package"; 567 568 std::vector<std::string> cmd_args = {install_cmd, "install-create", "-S", 569 std::to_string(total_size)}; 570 cmd_args.reserve(first_apk + 4); 571 for (int i = 1; i < first_apk; i++) { 572 if (use_abb_exec) { 573 cmd_args.push_back(argv[i]); 574 } else { 575 cmd_args.push_back(escape_arg(argv[i])); 576 } 577 } 578 579 // Create install session 580 std::string error; 581 char buf[BUFSIZ]; 582 { 583 unique_fd fd = send_command(cmd_args, &error); 584 if (fd < 0) { 585 fprintf(stderr, "adb: connect error for create: %s\n", error.c_str()); 586 return EXIT_FAILURE; 587 } 588 read_status_line(fd.get(), buf, sizeof(buf)); 589 } 590 591 int session_id = -1; 592 if (!strncmp("Success", buf, 7)) { 593 char* start = strrchr(buf, '['); 594 char* end = strrchr(buf, ']'); 595 if (start && end) { 596 *end = '\0'; 597 session_id = strtol(start + 1, nullptr, 10); 598 } 599 } 600 if (session_id < 0) { 601 fprintf(stderr, "adb: failed to create session\n"); 602 fputs(buf, stderr); 603 return EXIT_FAILURE; 604 } 605 const auto session_id_str = std::to_string(session_id); 606 607 // Valid session, now stream the APKs 608 bool success = true; 609 for (int i = first_apk; i < argc; i++) { 610 const char* file = argv[i]; 611 struct stat sb; 612 if (stat(file, &sb) == -1) { 613 fprintf(stderr, "adb: failed to stat \"%s\": %s\n", file, strerror(errno)); 614 success = false; 615 goto finalize_session; 616 } 617 618 std::vector<std::string> cmd_args = { 619 install_cmd, 620 "install-write", 621 "-S", 622 std::to_string(sb.st_size), 623 session_id_str, 624 android::base::Basename(file), 625 "-", 626 }; 627 628 unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC)); 629 if (local_fd < 0) { 630 fprintf(stderr, "adb: failed to open \"%s\": %s\n", file, strerror(errno)); 631 success = false; 632 goto finalize_session; 633 } 634 635 std::string error; 636 unique_fd remote_fd = send_command(cmd_args, &error); 637 if (remote_fd < 0) { 638 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str()); 639 success = false; 640 goto finalize_session; 641 } 642 643 if (!copy_to_file(local_fd.get(), remote_fd.get())) { 644 fprintf(stderr, "adb: failed to write \"%s\": %s\n", file, strerror(errno)); 645 success = false; 646 goto finalize_session; 647 } 648 649 read_status_line(remote_fd.get(), buf, sizeof(buf)); 650 651 if (strncmp("Success", buf, 7)) { 652 fprintf(stderr, "adb: failed to write \"%s\"\n", file); 653 fputs(buf, stderr); 654 success = false; 655 goto finalize_session; 656 } 657 } 658 659 finalize_session: 660 // Commit session if we streamed everything okay; otherwise abandon. 661 std::vector<std::string> service_args = { 662 install_cmd, 663 success ? "install-commit" : "install-abandon", 664 session_id_str, 665 }; 666 { 667 unique_fd fd = send_command(service_args, &error); 668 if (fd < 0) { 669 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str()); 670 return EXIT_FAILURE; 671 } 672 read_status_line(fd.get(), buf, sizeof(buf)); 673 } 674 if (!success) return EXIT_FAILURE; 675 676 if (strncmp("Success", buf, 7)) { 677 fprintf(stderr, "adb: failed to finalize session\n"); 678 fputs(buf, stderr); 679 return EXIT_FAILURE; 680 } 681 682 fputs(buf, stdout); 683 return EXIT_SUCCESS; 684 } 685 686 int install_multiple_app(int argc, const char** argv) { 687 InstallMode install_mode = INSTALL_DEFAULT; 688 auto incremental_request = CmdlineOption::None; 689 bool incremental_wait = false; 690 bool use_fastdeploy = false; 691 692 auto passthrough_argv = parse_install_mode({argv + 1, argv + argc}, &install_mode, 693 &incremental_request, &incremental_wait); 694 695 auto [primary_mode, fallback_mode] = 696 calculate_install_mode(install_mode, use_fastdeploy, incremental_request); 697 if ((primary_mode == INSTALL_STREAM || 698 fallback_mode.value_or(INSTALL_PUSH) == INSTALL_STREAM) && 699 best_install_mode() == INSTALL_PUSH) { 700 error_exit("Attempting to use streaming install on unsupported device"); 701 } 702 703 auto run_install_mode = [&](InstallMode install_mode, bool silent) { 704 switch (install_mode) { 705 case INSTALL_PUSH: 706 case INSTALL_STREAM: 707 return install_multiple_app_streamed(passthrough_argv.size(), 708 passthrough_argv.data()); 709 case INSTALL_INCREMENTAL: 710 return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(), 711 incremental_wait, silent); 712 case INSTALL_DEFAULT: 713 default: 714 error_exit("invalid install mode"); 715 } 716 }; 717 auto res = run_install_mode(primary_mode, fallback_mode.has_value()); 718 if (res && fallback_mode.value_or(primary_mode) != primary_mode) { 719 res = run_install_mode(*fallback_mode, false); 720 } 721 return res; 722 } 723 724 int install_multi_package(int argc, const char** argv) { 725 // Find all APK arguments starting at end. 726 // All other arguments passed through verbatim. 727 bool apex_found = false; 728 int first_package = -1; 729 for (int i = argc - 1; i >= 0; i--) { 730 const char* file = argv[i]; 731 if (android::base::EndsWithIgnoreCase(file, ".apk") || 732 android::base::EndsWithIgnoreCase(file, ".apex")) { 733 first_package = i; 734 if (android::base::EndsWithIgnoreCase(file, ".apex")) { 735 apex_found = true; 736 } 737 } else { 738 break; 739 } 740 } 741 742 if (first_package == -1) error_exit("need APK or APEX files on command line"); 743 744 if (best_install_mode() == INSTALL_PUSH) { 745 fprintf(stderr, "adb: multi-package install is not supported on this device\n"); 746 return EXIT_FAILURE; 747 } 748 749 const bool use_abb_exec = is_abb_exec_supported(); 750 const std::string install_cmd = use_abb_exec ? "package" : "exec:cmd package"; 751 752 std::vector<std::string> multi_package_cmd_args = {install_cmd, "install-create", 753 "--multi-package"}; 754 755 multi_package_cmd_args.reserve(first_package + 4); 756 for (int i = 1; i < first_package; i++) { 757 if (use_abb_exec) { 758 multi_package_cmd_args.push_back(argv[i]); 759 } else { 760 multi_package_cmd_args.push_back(escape_arg(argv[i])); 761 } 762 } 763 764 if (apex_found) { 765 multi_package_cmd_args.emplace_back("--staged"); 766 } 767 768 // Create multi-package install session 769 std::string error; 770 char buf[BUFSIZ]; 771 { 772 unique_fd fd = send_command(multi_package_cmd_args, &error); 773 if (fd < 0) { 774 fprintf(stderr, "adb: connect error for create multi-package: %s\n", error.c_str()); 775 return EXIT_FAILURE; 776 } 777 read_status_line(fd.get(), buf, sizeof(buf)); 778 } 779 780 int parent_session_id = -1; 781 if (!strncmp("Success", buf, 7)) { 782 char* start = strrchr(buf, '['); 783 char* end = strrchr(buf, ']'); 784 if (start && end) { 785 *end = '\0'; 786 parent_session_id = strtol(start + 1, nullptr, 10); 787 } 788 } 789 if (parent_session_id < 0) { 790 fprintf(stderr, "adb: failed to create multi-package session\n"); 791 fputs(buf, stderr); 792 return EXIT_FAILURE; 793 } 794 const auto parent_session_id_str = std::to_string(parent_session_id); 795 796 fprintf(stdout, "Created parent session ID %d.\n", parent_session_id); 797 798 std::vector<int> session_ids; 799 800 // Valid session, now create the individual sessions and stream the APKs 801 int success = EXIT_FAILURE; 802 std::vector<std::string> individual_cmd_args = {install_cmd, "install-create"}; 803 for (int i = 1; i < first_package; i++) { 804 if (use_abb_exec) { 805 individual_cmd_args.push_back(argv[i]); 806 } else { 807 individual_cmd_args.push_back(escape_arg(argv[i])); 808 } 809 } 810 if (apex_found) { 811 individual_cmd_args.emplace_back("--staged"); 812 } 813 814 std::vector<std::string> individual_apex_cmd_args; 815 if (apex_found) { 816 individual_apex_cmd_args = individual_cmd_args; 817 individual_apex_cmd_args.emplace_back("--apex"); 818 } 819 820 std::vector<std::string> add_session_cmd_args = { 821 install_cmd, 822 "install-add-session", 823 parent_session_id_str, 824 }; 825 826 for (int i = first_package; i < argc; i++) { 827 const char* file = argv[i]; 828 char buf[BUFSIZ]; 829 { 830 unique_fd fd; 831 // Create individual install session 832 if (android::base::EndsWithIgnoreCase(file, ".apex")) { 833 fd = send_command(individual_apex_cmd_args, &error); 834 } else { 835 fd = send_command(individual_cmd_args, &error); 836 } 837 if (fd < 0) { 838 fprintf(stderr, "adb: connect error for create: %s\n", error.c_str()); 839 goto finalize_multi_package_session; 840 } 841 read_status_line(fd.get(), buf, sizeof(buf)); 842 } 843 844 int session_id = -1; 845 if (!strncmp("Success", buf, 7)) { 846 char* start = strrchr(buf, '['); 847 char* end = strrchr(buf, ']'); 848 if (start && end) { 849 *end = '\0'; 850 session_id = strtol(start + 1, nullptr, 10); 851 } 852 } 853 if (session_id < 0) { 854 fprintf(stderr, "adb: failed to create multi-package session\n"); 855 fputs(buf, stderr); 856 goto finalize_multi_package_session; 857 } 858 const auto session_id_str = std::to_string(session_id); 859 860 fprintf(stdout, "Created child session ID %d.\n", session_id); 861 session_ids.push_back(session_id); 862 863 // Support splitAPKs by allowing the notation split1.apk:split2.apk:split3.apk as argument. 864 std::vector<std::string> splits = android::base::Split(file, ":"); 865 866 for (const std::string& split : splits) { 867 struct stat sb; 868 if (stat(split.c_str(), &sb) == -1) { 869 fprintf(stderr, "adb: failed to stat %s: %s\n", split.c_str(), strerror(errno)); 870 goto finalize_multi_package_session; 871 } 872 873 std::vector<std::string> cmd_args = { 874 install_cmd, 875 "install-write", 876 "-S", 877 std::to_string(sb.st_size), 878 session_id_str, 879 android::base::StringPrintf("%d_%s", i, android::base::Basename(split).c_str()), 880 "-", 881 }; 882 883 unique_fd local_fd(adb_open(split.c_str(), O_RDONLY | O_CLOEXEC)); 884 if (local_fd < 0) { 885 fprintf(stderr, "adb: failed to open %s: %s\n", split.c_str(), strerror(errno)); 886 goto finalize_multi_package_session; 887 } 888 889 std::string error; 890 unique_fd remote_fd = send_command(cmd_args, &error); 891 if (remote_fd < 0) { 892 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str()); 893 goto finalize_multi_package_session; 894 } 895 896 if (!copy_to_file(local_fd.get(), remote_fd.get())) { 897 fprintf(stderr, "adb: failed to write %s: %s\n", split.c_str(), strerror(errno)); 898 goto finalize_multi_package_session; 899 } 900 901 read_status_line(remote_fd.get(), buf, sizeof(buf)); 902 903 if (strncmp("Success", buf, 7)) { 904 fprintf(stderr, "adb: failed to write %s\n", split.c_str()); 905 fputs(buf, stderr); 906 goto finalize_multi_package_session; 907 } 908 } 909 add_session_cmd_args.push_back(std::to_string(session_id)); 910 } 911 912 { 913 unique_fd fd = send_command(add_session_cmd_args, &error); 914 if (fd < 0) { 915 fprintf(stderr, "adb: connect error for install-add-session: %s\n", error.c_str()); 916 goto finalize_multi_package_session; 917 } 918 read_status_line(fd.get(), buf, sizeof(buf)); 919 } 920 921 if (strncmp("Success", buf, 7)) { 922 fprintf(stderr, "adb: failed to link sessions (%s)\n", 923 android::base::Join(add_session_cmd_args, " ").c_str()); 924 fputs(buf, stderr); 925 goto finalize_multi_package_session; 926 } 927 928 // no failures means we can proceed with the assumption of success 929 success = 0; 930 931 finalize_multi_package_session: 932 // Commit session if we streamed everything okay; otherwise abandon 933 std::vector<std::string> service_args; 934 if (success == 0) { 935 service_args.push_back(install_cmd); 936 service_args.push_back("install-commit"); 937 // If successful, we need to forward args to install-commit 938 for (int i = 1; i < first_package - 1; i++) { 939 if (strcmp(argv[i], "--staged-ready-timeout") == 0) { 940 service_args.push_back(argv[i]); 941 service_args.push_back(argv[i + 1]); 942 i++; 943 } 944 } 945 service_args.push_back(parent_session_id_str); 946 } else { 947 service_args = {install_cmd, "install-abandon", parent_session_id_str}; 948 } 949 950 { 951 unique_fd fd = send_command(service_args, &error); 952 if (fd < 0) { 953 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str()); 954 return EXIT_FAILURE; 955 } 956 read_status_line(fd.get(), buf, sizeof(buf)); 957 } 958 959 if (!strncmp("Success", buf, 7)) { 960 fputs(buf, stdout); 961 if (success == 0) { 962 return 0; 963 } 964 } else { 965 fprintf(stderr, "adb: failed to finalize session\n"); 966 fputs(buf, stderr); 967 } 968 969 session_ids.push_back(parent_session_id); 970 // try to abandon all remaining sessions 971 for (std::size_t i = 0; i < session_ids.size(); i++) { 972 std::vector<std::string> service_args = { 973 install_cmd, 974 "install-abandon", 975 std::to_string(session_ids[i]), 976 }; 977 fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]); 978 unique_fd fd = send_command(service_args, &error); 979 if (fd < 0) { 980 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str()); 981 continue; 982 } 983 read_status_line(fd.get(), buf, sizeof(buf)); 984 } 985 return EXIT_FAILURE; 986 } 987 988 int delete_device_file(const std::string& filename) { 989 // http://b/17339227 "Sideloading a Readonly File Results in a Prompt to 990 // Delete" caused us to add `-f` here, to avoid the equivalent of the `-i` 991 // prompt that you get from BSD rm (used in Android 5) if you have a 992 // non-writable file and stdin is a tty (which is true for old versions of 993 // adbd). 994 // 995 // Unfortunately, `rm -f` requires Android 4.3, so that workaround broke 996 // earlier Android releases. This was reported as http://b/37704384 "adb 997 // install -r passes invalid argument to rm on Android 4.1" and 998 // http://b/37035817 "ADB Fails: rm failed for -f, No such file or 999 // directory". 1000 // 1001 // Testing on a variety of devices and emulators shows that redirecting 1002 // stdin is sufficient to avoid the pseudo-`-i`, and works on toolbox, 1003 // BSD, and toybox versions of rm. 1004 return send_shell_command("rm " + escape_arg(filename) + " </dev/null"); 1005 } 1006