• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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