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
can_use_feature(const char * feature)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
best_install_mode()68 static InstallMode best_install_mode() {
69 if (can_use_feature(kFeatureCmd)) {
70 return INSTALL_STREAM;
71 }
72 return INSTALL_PUSH;
73 }
74
is_apex_supported()75 static bool is_apex_supported() {
76 return can_use_feature(kFeatureApex);
77 }
78
is_abb_exec_supported()79 static bool is_abb_exec_supported() {
80 return can_use_feature(kFeatureAbbExec);
81 }
82
pm_command(int argc,const char ** argv)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
uninstall_app_streamed(int argc,const char ** argv)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
uninstall_app_legacy(int argc,const char ** argv)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
uninstall_app(int argc,const char ** argv)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
read_status_line(int fd,char * buf,size_t count)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
send_command(const std::vector<std::string> & cmd_args,std::string * error)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
install_app_streamed(int argc,const char ** argv,bool use_fastdeploy)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
install_app_legacy(int argc,const char ** argv,bool use_fastdeploy)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>
ms_between(TimePoint start,TimePoint end)304 static int ms_between(TimePoint start, TimePoint end) {
305 return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
306 }
307
install_app_incremental(int argc,const char ** argv,bool wait,bool silent)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
calculate_install_mode(InstallMode modeFromArgs,bool fastdeploy,CmdlineOption incremental_request)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
parse_install_mode(std::vector<const char * > argv,InstallMode * install_mode,CmdlineOption * incremental_request,bool * incremental_wait)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
parse_fast_deploy_mode(std::vector<const char * > argv,bool * use_fastdeploy,FastDeploy_AgentUpdateStrategy * agent_update_strategy)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
install_app(int argc,const char ** argv)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
install_multiple_app_streamed(int argc,const char ** argv)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
install_multiple_app(int argc,const char ** argv)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
install_multi_package(int argc,const char ** argv)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 install_cmd,
935 success == 0 ? "install-commit" : "install-abandon",
936 parent_session_id_str,
937 };
938
939 {
940 unique_fd fd = send_command(service_args, &error);
941 if (fd < 0) {
942 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
943 return EXIT_FAILURE;
944 }
945 read_status_line(fd.get(), buf, sizeof(buf));
946 }
947
948 if (!strncmp("Success", buf, 7)) {
949 fputs(buf, stdout);
950 if (success == 0) {
951 return 0;
952 }
953 } else {
954 fprintf(stderr, "adb: failed to finalize session\n");
955 fputs(buf, stderr);
956 }
957
958 session_ids.push_back(parent_session_id);
959 // try to abandon all remaining sessions
960 for (std::size_t i = 0; i < session_ids.size(); i++) {
961 std::vector<std::string> service_args = {
962 install_cmd,
963 "install-abandon",
964 std::to_string(session_ids[i]),
965 };
966 fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]);
967 unique_fd fd = send_command(service_args, &error);
968 if (fd < 0) {
969 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
970 continue;
971 }
972 read_status_line(fd.get(), buf, sizeof(buf));
973 }
974 return EXIT_FAILURE;
975 }
976
delete_device_file(const std::string & filename)977 int delete_device_file(const std::string& filename) {
978 // http://b/17339227 "Sideloading a Readonly File Results in a Prompt to
979 // Delete" caused us to add `-f` here, to avoid the equivalent of the `-i`
980 // prompt that you get from BSD rm (used in Android 5) if you have a
981 // non-writable file and stdin is a tty (which is true for old versions of
982 // adbd).
983 //
984 // Unfortunately, `rm -f` requires Android 4.3, so that workaround broke
985 // earlier Android releases. This was reported as http://b/37704384 "adb
986 // install -r passes invalid argument to rm on Android 4.1" and
987 // http://b/37035817 "ADB Fails: rm failed for -f, No such file or
988 // directory".
989 //
990 // Testing on a variety of devices and emulators shows that redirecting
991 // stdin is sufficient to avoid the pseudo-`-i`, and works on toolbox,
992 // BSD, and toybox versions of rm.
993 return send_shell_command("rm " + escape_arg(filename) + " </dev/null");
994 }
995