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 <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <algorithm>
23 #include <iostream>
24 #include <string>
25 #include <vector>
26
27 #include <android-base/file.h>
28 #include <android-base/stringprintf.h>
29 #include <android-base/strings.h>
30
31 #include "adb.h"
32 #include "adb_client.h"
33 #include "adb_unique_fd.h"
34 #include "adb_utils.h"
35 #include "client/file_sync_client.h"
36 #include "commandline.h"
37 #include "fastdeploy.h"
38
39 #if defined(ENABLE_FASTDEPLOY)
40 static constexpr int kFastDeployMinApi = 24;
41 #endif
42
can_use_feature(const char * feature)43 static bool can_use_feature(const char* feature) {
44 FeatureSet features;
45 std::string error;
46 if (!adb_get_feature_set(&features, &error)) {
47 fprintf(stderr, "error: %s\n", error.c_str());
48 return true;
49 }
50 return CanUseFeature(features, feature);
51 }
52
use_legacy_install()53 static bool use_legacy_install() {
54 return !can_use_feature(kFeatureCmd);
55 }
56
is_apex_supported()57 static bool is_apex_supported() {
58 return can_use_feature(kFeatureApex);
59 }
60
pm_command(int argc,const char ** argv)61 static int pm_command(int argc, const char** argv) {
62 std::string cmd = "pm";
63
64 while (argc-- > 0) {
65 cmd += " " + escape_arg(*argv++);
66 }
67
68 return send_shell_command(cmd);
69 }
70
uninstall_app_streamed(int argc,const char ** argv)71 static int uninstall_app_streamed(int argc, const char** argv) {
72 // 'adb uninstall' takes the same arguments as 'cmd package uninstall' on device
73 std::string cmd = "cmd package";
74 while (argc-- > 0) {
75 // deny the '-k' option until the remaining data/cache can be removed with adb/UI
76 if (strcmp(*argv, "-k") == 0) {
77 printf("The -k option uninstalls the application while retaining the "
78 "data/cache.\n"
79 "At the moment, there is no way to remove the remaining data.\n"
80 "You will have to reinstall the application with the same "
81 "signature, and fully "
82 "uninstall it.\n"
83 "If you truly wish to continue, execute 'adb shell cmd package "
84 "uninstall -k'.\n");
85 return EXIT_FAILURE;
86 }
87 cmd += " " + escape_arg(*argv++);
88 }
89
90 return send_shell_command(cmd);
91 }
92
uninstall_app_legacy(int argc,const char ** argv)93 static int uninstall_app_legacy(int argc, const char** argv) {
94 /* if the user choose the -k option, we refuse to do it until devices are
95 out with the option to uninstall the remaining data somehow (adb/ui) */
96 for (int i = 1; i < argc; i++) {
97 if (!strcmp(argv[i], "-k")) {
98 printf("The -k option uninstalls the application while retaining the "
99 "data/cache.\n"
100 "At the moment, there is no way to remove the remaining data.\n"
101 "You will have to reinstall the application with the same "
102 "signature, and fully "
103 "uninstall it.\n"
104 "If you truly wish to continue, execute 'adb shell pm uninstall "
105 "-k'\n.");
106 return EXIT_FAILURE;
107 }
108 }
109
110 /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
111 return pm_command(argc, argv);
112 }
113
uninstall_app(int argc,const char ** argv)114 int uninstall_app(int argc, const char** argv) {
115 if (use_legacy_install()) {
116 return uninstall_app_legacy(argc, argv);
117 }
118 return uninstall_app_streamed(argc, argv);
119 }
120
read_status_line(int fd,char * buf,size_t count)121 static void read_status_line(int fd, char* buf, size_t count) {
122 count--;
123 while (count > 0) {
124 int len = adb_read(fd, buf, count);
125 if (len <= 0) {
126 break;
127 }
128
129 buf += len;
130 count -= len;
131 }
132 *buf = '\0';
133 }
134
135 #if defined(ENABLE_FASTDEPLOY)
delete_device_patch_file(const char * apkPath)136 static int delete_device_patch_file(const char* apkPath) {
137 std::string patchDevicePath = get_patch_path(apkPath);
138 return delete_device_file(patchDevicePath);
139 }
140 #endif
141
install_app_streamed(int argc,const char ** argv,bool use_fastdeploy,bool use_localagent)142 static int install_app_streamed(int argc, const char** argv, bool use_fastdeploy,
143 bool use_localagent) {
144 printf("Performing Streamed Install\n");
145
146 // The last argument must be the APK file
147 const char* file = argv[argc - 1];
148 if (!android::base::EndsWithIgnoreCase(file, ".apk") &&
149 !android::base::EndsWithIgnoreCase(file, ".apex")) {
150 error_exit("filename doesn't end .apk or .apex: %s", file);
151 }
152
153 bool is_apex = false;
154 if (android::base::EndsWithIgnoreCase(file, ".apex")) {
155 is_apex = true;
156 }
157 if (is_apex && !is_apex_supported()) {
158 error_exit(".apex is not supported on the target device");
159 }
160
161 if (is_apex && use_fastdeploy) {
162 error_exit("--fastdeploy doesn't support .apex files");
163 }
164
165 if (use_fastdeploy == true) {
166 #if defined(ENABLE_FASTDEPLOY)
167 TemporaryFile metadataTmpFile;
168 std::string patchTmpFilePath;
169 {
170 TemporaryFile patchTmpFile;
171 patchTmpFile.DoNotRemove();
172 patchTmpFilePath = patchTmpFile.path;
173 }
174
175 FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
176 extract_metadata(file, metadataFile);
177 fclose(metadataFile);
178
179 create_patch(file, metadataTmpFile.path, patchTmpFilePath.c_str());
180 // pass all but 1st (command) and last (apk path) parameters through to pm for
181 // session creation
182 std::vector<const char*> pm_args{argv + 1, argv + argc - 1};
183 install_patch(file, patchTmpFilePath.c_str(), pm_args.size(), pm_args.data());
184 adb_unlink(patchTmpFilePath.c_str());
185 delete_device_patch_file(file);
186 return 0;
187 #else
188 error_exit("fastdeploy is disabled");
189 #endif
190 } else {
191 struct stat sb;
192 if (stat(file, &sb) == -1) {
193 fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno));
194 return 1;
195 }
196
197 unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC));
198 if (local_fd < 0) {
199 fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
200 return 1;
201 }
202
203 std::string error;
204 std::string cmd = "exec:cmd package";
205
206 // don't copy the APK name, but, copy the rest of the arguments as-is
207 while (argc-- > 1) {
208 cmd += " " + escape_arg(std::string(*argv++));
209 }
210
211 // add size parameter [required for streaming installs]
212 // do last to override any user specified value
213 cmd += " " + android::base::StringPrintf("-S %" PRIu64, static_cast<uint64_t>(sb.st_size));
214
215 if (is_apex) {
216 cmd += " --apex";
217 }
218
219 unique_fd remote_fd(adb_connect(cmd, &error));
220 if (remote_fd < 0) {
221 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
222 return 1;
223 }
224
225 char buf[BUFSIZ];
226 copy_to_file(local_fd.get(), remote_fd.get());
227 read_status_line(remote_fd.get(), buf, sizeof(buf));
228
229 if (!strncmp("Success", buf, 7)) {
230 fputs(buf, stdout);
231 return 0;
232 }
233 fprintf(stderr, "adb: failed to install %s: %s", file, buf);
234 return 1;
235 }
236 }
237
install_app_legacy(int argc,const char ** argv,bool use_fastdeploy,bool use_localagent)238 static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy,
239 bool use_localagent) {
240 printf("Performing Push Install\n");
241
242 // Find last APK argument.
243 // All other arguments passed through verbatim.
244 int last_apk = -1;
245 for (int i = argc - 1; i >= 0; i--) {
246 if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
247 error_exit("APEX packages are only compatible with Streamed Install");
248 }
249 if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) {
250 last_apk = i;
251 break;
252 }
253 }
254
255 if (last_apk == -1) error_exit("need APK file on command line");
256
257 int result = -1;
258 std::vector<const char*> apk_file = {argv[last_apk]};
259 std::string apk_dest =
260 "/data/local/tmp/" + android::base::Basename(argv[last_apk]);
261
262 if (use_fastdeploy == true) {
263 #if defined(ENABLE_FASTDEPLOY)
264 TemporaryFile metadataTmpFile;
265 TemporaryFile patchTmpFile;
266
267 FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
268 extract_metadata(apk_file[0], metadataFile);
269 fclose(metadataFile);
270
271 create_patch(apk_file[0], metadataTmpFile.path, patchTmpFile.path);
272 apply_patch_on_device(apk_file[0], patchTmpFile.path, apk_dest.c_str());
273 #else
274 error_exit("fastdeploy is disabled");
275 #endif
276 } else {
277 if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk;
278 }
279
280 argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
281 result = pm_command(argc, argv);
282
283 cleanup_apk:
284 if (use_fastdeploy == true) {
285 #if defined(ENABLE_FASTDEPLOY)
286 delete_device_patch_file(apk_file[0]);
287 #endif
288 }
289 delete_device_file(apk_dest);
290 return result;
291 }
292
install_app(int argc,const char ** argv)293 int install_app(int argc, const char** argv) {
294 std::vector<int> processedArgIndicies;
295 enum installMode {
296 INSTALL_DEFAULT,
297 INSTALL_PUSH,
298 INSTALL_STREAM
299 } installMode = INSTALL_DEFAULT;
300 bool use_fastdeploy = false;
301 bool is_reinstall = false;
302 bool use_localagent = false;
303 FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
304
305 for (int i = 1; i < argc; i++) {
306 if (!strcmp(argv[i], "--streaming")) {
307 processedArgIndicies.push_back(i);
308 installMode = INSTALL_STREAM;
309 } else if (!strcmp(argv[i], "--no-streaming")) {
310 processedArgIndicies.push_back(i);
311 installMode = INSTALL_PUSH;
312 } else if (!strcmp(argv[i], "-r")) {
313 // Note that this argument is not added to processedArgIndicies because it
314 // must be passed through to pm
315 is_reinstall = true;
316 } else if (!strcmp(argv[i], "--fastdeploy")) {
317 processedArgIndicies.push_back(i);
318 use_fastdeploy = true;
319 } else if (!strcmp(argv[i], "--no-fastdeploy")) {
320 processedArgIndicies.push_back(i);
321 use_fastdeploy = false;
322 } else if (!strcmp(argv[i], "--force-agent")) {
323 processedArgIndicies.push_back(i);
324 agent_update_strategy = FastDeploy_AgentUpdateAlways;
325 } else if (!strcmp(argv[i], "--date-check-agent")) {
326 processedArgIndicies.push_back(i);
327 agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp;
328 } else if (!strcmp(argv[i], "--version-check-agent")) {
329 processedArgIndicies.push_back(i);
330 agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
331 #ifndef _WIN32
332 } else if (!strcmp(argv[i], "--local-agent")) {
333 processedArgIndicies.push_back(i);
334 use_localagent = true;
335 #endif
336 }
337 }
338
339 if (installMode == INSTALL_DEFAULT) {
340 if (use_legacy_install()) {
341 installMode = INSTALL_PUSH;
342 } else {
343 installMode = INSTALL_STREAM;
344 }
345 }
346
347 if (installMode == INSTALL_STREAM && use_legacy_install() == true) {
348 error_exit("Attempting to use streaming install on unsupported device");
349 }
350
351 #if defined(ENABLE_FASTDEPLOY)
352 if (use_fastdeploy == true && get_device_api_level() < kFastDeployMinApi) {
353 printf("Fast Deploy is only compatible with devices of API version %d or higher, "
354 "ignoring.\n",
355 kFastDeployMinApi);
356 use_fastdeploy = false;
357 }
358 #endif
359
360 std::vector<const char*> passthrough_argv;
361 for (int i = 0; i < argc; i++) {
362 if (std::find(processedArgIndicies.begin(), processedArgIndicies.end(), i) ==
363 processedArgIndicies.end()) {
364 passthrough_argv.push_back(argv[i]);
365 }
366 }
367 if (passthrough_argv.size() < 2) {
368 error_exit("install requires an apk argument");
369 }
370
371 if (use_fastdeploy == true) {
372 #if defined(ENABLE_FASTDEPLOY)
373 fastdeploy_set_local_agent(use_localagent);
374 update_agent(agent_update_strategy);
375
376 // The last argument must be the APK file
377 const char* file = passthrough_argv.back();
378 use_fastdeploy = find_package(file);
379 #else
380 error_exit("fastdeploy is disabled");
381 #endif
382 }
383
384 switch (installMode) {
385 case INSTALL_PUSH:
386 return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(),
387 use_fastdeploy, use_localagent);
388 case INSTALL_STREAM:
389 return install_app_streamed(passthrough_argv.size(), passthrough_argv.data(),
390 use_fastdeploy, use_localagent);
391 case INSTALL_DEFAULT:
392 default:
393 return 1;
394 }
395 }
396
install_multiple_app(int argc,const char ** argv)397 int install_multiple_app(int argc, const char** argv) {
398 // Find all APK arguments starting at end.
399 // All other arguments passed through verbatim.
400 int first_apk = -1;
401 uint64_t total_size = 0;
402 for (int i = argc - 1; i >= 0; i--) {
403 const char* file = argv[i];
404 if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
405 error_exit("APEX packages are not compatible with install-multiple");
406 }
407
408 if (android::base::EndsWithIgnoreCase(file, ".apk") ||
409 android::base::EndsWithIgnoreCase(file, ".dm") ||
410 android::base::EndsWithIgnoreCase(file, ".fsv_sig")) {
411 struct stat sb;
412 if (stat(file, &sb) != -1) total_size += sb.st_size;
413 first_apk = i;
414 } else {
415 break;
416 }
417 }
418
419 if (first_apk == -1) error_exit("need APK file on command line");
420
421 std::string install_cmd;
422 if (use_legacy_install()) {
423 install_cmd = "exec:pm";
424 } else {
425 install_cmd = "exec:cmd package";
426 }
427
428 std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64,
429 install_cmd.c_str(), total_size);
430 for (int i = 1; i < first_apk; i++) {
431 cmd += " " + escape_arg(argv[i]);
432 }
433
434 // Create install session
435 std::string error;
436 char buf[BUFSIZ];
437 {
438 unique_fd fd(adb_connect(cmd, &error));
439 if (fd < 0) {
440 fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
441 return EXIT_FAILURE;
442 }
443 read_status_line(fd.get(), buf, sizeof(buf));
444 }
445
446 int session_id = -1;
447 if (!strncmp("Success", buf, 7)) {
448 char* start = strrchr(buf, '[');
449 char* end = strrchr(buf, ']');
450 if (start && end) {
451 *end = '\0';
452 session_id = strtol(start + 1, nullptr, 10);
453 }
454 }
455 if (session_id < 0) {
456 fprintf(stderr, "adb: failed to create session\n");
457 fputs(buf, stderr);
458 return EXIT_FAILURE;
459 }
460
461 // Valid session, now stream the APKs
462 int success = 1;
463 for (int i = first_apk; i < argc; i++) {
464 const char* file = argv[i];
465 struct stat sb;
466 if (stat(file, &sb) == -1) {
467 fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno));
468 success = 0;
469 goto finalize_session;
470 }
471
472 std::string cmd =
473 android::base::StringPrintf("%s install-write -S %" PRIu64 " %d %s -",
474 install_cmd.c_str(), static_cast<uint64_t>(sb.st_size),
475 session_id, android::base::Basename(file).c_str());
476
477 unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC));
478 if (local_fd < 0) {
479 fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
480 success = 0;
481 goto finalize_session;
482 }
483
484 std::string error;
485 unique_fd remote_fd(adb_connect(cmd, &error));
486 if (remote_fd < 0) {
487 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
488 success = 0;
489 goto finalize_session;
490 }
491
492 copy_to_file(local_fd.get(), remote_fd.get());
493 read_status_line(remote_fd.get(), buf, sizeof(buf));
494
495 if (strncmp("Success", buf, 7)) {
496 fprintf(stderr, "adb: failed to write %s\n", file);
497 fputs(buf, stderr);
498 success = 0;
499 goto finalize_session;
500 }
501 }
502
503 finalize_session:
504 // Commit session if we streamed everything okay; otherwise abandon
505 std::string service = android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
506 success ? "commit" : "abandon", session_id);
507 {
508 unique_fd fd(adb_connect(service, &error));
509 if (fd < 0) {
510 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
511 return EXIT_FAILURE;
512 }
513 read_status_line(fd.get(), buf, sizeof(buf));
514 }
515
516 if (!strncmp("Success", buf, 7)) {
517 fputs(buf, stdout);
518 return 0;
519 }
520 fprintf(stderr, "adb: failed to finalize session\n");
521 fputs(buf, stderr);
522 return EXIT_FAILURE;
523 }
524
install_multi_package(int argc,const char ** argv)525 int install_multi_package(int argc, const char** argv) {
526 // Find all APK arguments starting at end.
527 // All other arguments passed through verbatim.
528 bool apex_found = false;
529 int first_package = -1;
530 for (int i = argc - 1; i >= 0; i--) {
531 const char* file = argv[i];
532 if (android::base::EndsWithIgnoreCase(file, ".apk") ||
533 android::base::EndsWithIgnoreCase(file, ".apex")) {
534 first_package = i;
535 if (android::base::EndsWithIgnoreCase(file, ".apex")) {
536 apex_found = true;
537 }
538 } else {
539 break;
540 }
541 }
542
543 if (first_package == -1) error_exit("need APK or APEX files on command line");
544
545 if (use_legacy_install()) {
546 fprintf(stderr, "adb: multi-package install is not supported on this device\n");
547 return EXIT_FAILURE;
548 }
549 std::string install_cmd = "exec:cmd package";
550
551 std::string multi_package_cmd =
552 android::base::StringPrintf("%s install-create --multi-package", install_cmd.c_str());
553 for (int i = 1; i < first_package; i++) {
554 multi_package_cmd += " " + escape_arg(argv[i]);
555 }
556
557 if (apex_found) {
558 multi_package_cmd += " --staged";
559 }
560
561 // Create multi-package install session
562 std::string error;
563 char buf[BUFSIZ];
564 {
565 unique_fd fd(adb_connect(multi_package_cmd, &error));
566 if (fd < 0) {
567 fprintf(stderr, "adb: connect error for create multi-package: %s\n", error.c_str());
568 return EXIT_FAILURE;
569 }
570 read_status_line(fd.get(), buf, sizeof(buf));
571 }
572
573 int parent_session_id = -1;
574 if (!strncmp("Success", buf, 7)) {
575 char* start = strrchr(buf, '[');
576 char* end = strrchr(buf, ']');
577 if (start && end) {
578 *end = '\0';
579 parent_session_id = strtol(start + 1, nullptr, 10);
580 }
581 }
582 if (parent_session_id < 0) {
583 fprintf(stderr, "adb: failed to create multi-package session\n");
584 fputs(buf, stderr);
585 return EXIT_FAILURE;
586 }
587
588 fprintf(stdout, "Created parent session ID %d.\n", parent_session_id);
589
590 std::vector<int> session_ids;
591
592 // Valid session, now create the individual sessions and stream the APKs
593 int success = EXIT_FAILURE;
594 std::string individual_cmd =
595 android::base::StringPrintf("%s install-create", install_cmd.c_str());
596 std::string all_session_ids = "";
597 for (int i = 1; i < first_package; i++) {
598 individual_cmd += " " + escape_arg(argv[i]);
599 }
600 if (apex_found) {
601 individual_cmd += " --staged";
602 }
603 std::string individual_apex_cmd = individual_cmd + " --apex";
604 std::string cmd = "";
605 for (int i = first_package; i < argc; i++) {
606 const char* file = argv[i];
607 char buf[BUFSIZ];
608 {
609 unique_fd fd;
610 // Create individual install session
611 if (android::base::EndsWithIgnoreCase(file, ".apex")) {
612 fd.reset(adb_connect(individual_apex_cmd, &error));
613 } else {
614 fd.reset(adb_connect(individual_cmd, &error));
615 }
616 if (fd < 0) {
617 fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
618 goto finalize_multi_package_session;
619 }
620 read_status_line(fd.get(), buf, sizeof(buf));
621 }
622
623 int session_id = -1;
624 if (!strncmp("Success", buf, 7)) {
625 char* start = strrchr(buf, '[');
626 char* end = strrchr(buf, ']');
627 if (start && end) {
628 *end = '\0';
629 session_id = strtol(start + 1, nullptr, 10);
630 }
631 }
632 if (session_id < 0) {
633 fprintf(stderr, "adb: failed to create multi-package session\n");
634 fputs(buf, stderr);
635 goto finalize_multi_package_session;
636 }
637
638 fprintf(stdout, "Created child session ID %d.\n", session_id);
639 session_ids.push_back(session_id);
640
641 // Support splitAPKs by allowing the notation split1.apk:split2.apk:split3.apk as argument.
642 std::vector<std::string> splits = android::base::Split(file, ":");
643
644 for (const std::string& split : splits) {
645 struct stat sb;
646 if (stat(split.c_str(), &sb) == -1) {
647 fprintf(stderr, "adb: failed to stat %s: %s\n", split.c_str(), strerror(errno));
648 goto finalize_multi_package_session;
649 }
650
651 std::string cmd = android::base::StringPrintf(
652 "%s install-write -S %" PRIu64 " %d %d_%s -", install_cmd.c_str(),
653 static_cast<uint64_t>(sb.st_size), session_id, i,
654 android::base::Basename(split).c_str());
655
656 unique_fd local_fd(adb_open(split.c_str(), O_RDONLY | O_CLOEXEC));
657 if (local_fd < 0) {
658 fprintf(stderr, "adb: failed to open %s: %s\n", split.c_str(), strerror(errno));
659 goto finalize_multi_package_session;
660 }
661
662 std::string error;
663 unique_fd remote_fd(adb_connect(cmd, &error));
664 if (remote_fd < 0) {
665 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
666 goto finalize_multi_package_session;
667 }
668
669 copy_to_file(local_fd.get(), remote_fd.get());
670 read_status_line(remote_fd.get(), buf, sizeof(buf));
671
672 if (strncmp("Success", buf, 7)) {
673 fprintf(stderr, "adb: failed to write %s\n", split.c_str());
674 fputs(buf, stderr);
675 goto finalize_multi_package_session;
676 }
677 }
678 all_session_ids += android::base::StringPrintf(" %d", session_id);
679 }
680
681 cmd = android::base::StringPrintf("%s install-add-session %d%s", install_cmd.c_str(),
682 parent_session_id, all_session_ids.c_str());
683 {
684 unique_fd fd(adb_connect(cmd, &error));
685 if (fd < 0) {
686 fprintf(stderr, "adb: connect error for install-add-session: %s\n", error.c_str());
687 goto finalize_multi_package_session;
688 }
689 read_status_line(fd.get(), buf, sizeof(buf));
690 }
691
692 if (strncmp("Success", buf, 7)) {
693 fprintf(stderr, "adb: failed to link sessions (%s)\n", cmd.c_str());
694 fputs(buf, stderr);
695 goto finalize_multi_package_session;
696 }
697
698 // no failures means we can proceed with the assumption of success
699 success = 0;
700
701 finalize_multi_package_session:
702 // Commit session if we streamed everything okay; otherwise abandon
703 std::string service =
704 android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
705 success == 0 ? "commit" : "abandon", parent_session_id);
706 {
707 unique_fd fd(adb_connect(service, &error));
708 if (fd < 0) {
709 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
710 return EXIT_FAILURE;
711 }
712 read_status_line(fd.get(), buf, sizeof(buf));
713 }
714
715 if (!strncmp("Success", buf, 7)) {
716 fputs(buf, stdout);
717 if (success == 0) {
718 return 0;
719 }
720 } else {
721 fprintf(stderr, "adb: failed to finalize session\n");
722 fputs(buf, stderr);
723 }
724
725 session_ids.push_back(parent_session_id);
726 // try to abandon all remaining sessions
727 for (std::size_t i = 0; i < session_ids.size(); i++) {
728 service = android::base::StringPrintf("%s install-abandon %d", install_cmd.c_str(),
729 session_ids[i]);
730 fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]);
731 unique_fd fd(adb_connect(service, &error));
732 if (fd < 0) {
733 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
734 continue;
735 }
736 read_status_line(fd.get(), buf, sizeof(buf));
737 }
738 return EXIT_FAILURE;
739 }
740
delete_device_file(const std::string & filename)741 int delete_device_file(const std::string& filename) {
742 std::string cmd = "rm -f " + escape_arg(filename);
743 return send_shell_command(cmd);
744 }
745