blob: 7a4a21bbb4af221815be67713686314d53dc8f26 [file] [log] [blame]
Idries Hamadi1ecee442018-01-29 16:30:36 +00001/*
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
Idries Hamadi78330f02018-09-13 18:00:25 +010017#include "adb_install.h"
Idries Hamadi1ecee442018-01-29 16:30:36 +000018
19#include <stdio.h>
20#include <stdlib.h>
Idries Hamadi78330f02018-09-13 18:00:25 +010021#include <unistd.h>
Idries Hamadi1ecee442018-01-29 16:30:36 +000022#include <algorithm>
23#include <iostream>
24#include <string>
25#include <vector>
26
Idries Hamadi78330f02018-09-13 18:00:25 +010027#include "adb.h"
28#include "adb_client.h"
29#include "adb_utils.h"
30#include "android-base/file.h"
31#include "android-base/stringprintf.h"
32#include "android-base/strings.h"
Idries Hamadi78330f02018-09-13 18:00:25 +010033#include "client/file_sync_client.h"
34#include "commandline.h"
35#include "fastdeploy.h"
Idries Hamadi1ecee442018-01-29 16:30:36 +000036
Idries Hamadidc272242018-08-24 11:46:45 +010037static constexpr int kFastDeployMinApi = 24;
38
Dario Frenidcb4c362018-10-04 16:26:40 +010039static bool can_use_feature(const char* feature) {
Idries Hamadi1ecee442018-01-29 16:30:36 +000040 FeatureSet features;
41 std::string error;
42 if (!adb_get_feature_set(&features, &error)) {
43 fprintf(stderr, "error: %s\n", error.c_str());
44 return true;
45 }
Dario Frenidcb4c362018-10-04 16:26:40 +010046 return CanUseFeature(features, feature);
47}
48
49static bool use_legacy_install() {
50 return !can_use_feature(kFeatureCmd);
51}
52
53static bool is_apex_supported() {
54 return can_use_feature(kFeatureApex);
Idries Hamadi1ecee442018-01-29 16:30:36 +000055}
56
57static int pm_command(int argc, const char** argv) {
58 std::string cmd = "pm";
59
60 while (argc-- > 0) {
61 cmd += " " + escape_arg(*argv++);
62 }
63
64 return send_shell_command(cmd);
65}
66
67static int uninstall_app_streamed(int argc, const char** argv) {
68 // 'adb uninstall' takes the same arguments as 'cmd package uninstall' on device
69 std::string cmd = "cmd package";
70 while (argc-- > 0) {
71 // deny the '-k' option until the remaining data/cache can be removed with adb/UI
72 if (strcmp(*argv, "-k") == 0) {
73 printf("The -k option uninstalls the application while retaining the "
74 "data/cache.\n"
75 "At the moment, there is no way to remove the remaining data.\n"
76 "You will have to reinstall the application with the same "
77 "signature, and fully "
78 "uninstall it.\n"
79 "If you truly wish to continue, execute 'adb shell cmd package "
80 "uninstall -k'.\n");
81 return EXIT_FAILURE;
82 }
83 cmd += " " + escape_arg(*argv++);
84 }
85
86 return send_shell_command(cmd);
87}
88
89static int uninstall_app_legacy(int argc, const char** argv) {
90 /* if the user choose the -k option, we refuse to do it until devices are
91 out with the option to uninstall the remaining data somehow (adb/ui) */
92 for (int i = 1; i < argc; i++) {
93 if (!strcmp(argv[i], "-k")) {
94 printf("The -k option uninstalls the application while retaining the "
95 "data/cache.\n"
96 "At the moment, there is no way to remove the remaining data.\n"
97 "You will have to reinstall the application with the same "
98 "signature, and fully "
99 "uninstall it.\n"
100 "If you truly wish to continue, execute 'adb shell pm uninstall "
101 "-k'\n.");
102 return EXIT_FAILURE;
103 }
104 }
105
106 /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
107 return pm_command(argc, argv);
108}
109
110int uninstall_app(int argc, const char** argv) {
Dario Frenidcb4c362018-10-04 16:26:40 +0100111 if (use_legacy_install()) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000112 return uninstall_app_legacy(argc, argv);
113 }
114 return uninstall_app_streamed(argc, argv);
115}
116
117static void read_status_line(int fd, char* buf, size_t count) {
118 count--;
119 while (count > 0) {
120 int len = adb_read(fd, buf, count);
121 if (len <= 0) {
122 break;
123 }
124
125 buf += len;
126 count -= len;
127 }
128 *buf = '\0';
129}
130
131static int delete_device_patch_file(const char* apkPath) {
132 std::string patchDevicePath = get_patch_path(apkPath);
133 return delete_device_file(patchDevicePath);
134}
135
Idries Hamadi1ecee442018-01-29 16:30:36 +0000136static int install_app_streamed(int argc, const char** argv, bool use_fastdeploy,
Idries Hamadi7919be22018-08-28 12:58:09 +0100137 bool use_localagent) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000138 printf("Performing Streamed Install\n");
139
140 // The last argument must be the APK file
141 const char* file = argv[argc - 1];
Dario Frenidcb4c362018-10-04 16:26:40 +0100142 if (!android::base::EndsWithIgnoreCase(file, ".apk") &&
143 !android::base::EndsWithIgnoreCase(file, ".apex")) {
144 error_exit("filename doesn't end .apk or .apex: %s", file);
145 }
146
147 bool is_apex = false;
148 if (android::base::EndsWithIgnoreCase(file, ".apex")) {
149 is_apex = true;
150 }
151 if (is_apex && !is_apex_supported()) {
152 error_exit(".apex is not supported on the target device");
153 }
154
155 if (is_apex && use_fastdeploy) {
156 error_exit("--fastdeploy doesn't support .apex files");
Idries Hamadi1ecee442018-01-29 16:30:36 +0000157 }
158
159 if (use_fastdeploy == true) {
Idries Hamadi0a525802018-08-21 15:47:35 +0100160 TemporaryFile metadataTmpFile;
Henry Daitx7cdf4892019-01-17 16:11:20 +0000161 std::string patchTmpFilePath;
162 {
163 TemporaryFile patchTmpFile;
164 patchTmpFile.DoNotRemove();
165 patchTmpFilePath = patchTmpFile.path;
166 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000167
Idries Hamadi0a525802018-08-21 15:47:35 +0100168 FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
Idries Hamadi78330f02018-09-13 18:00:25 +0100169 extract_metadata(file, metadataFile);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000170 fclose(metadataFile);
171
Henry Daitx7cdf4892019-01-17 16:11:20 +0000172 create_patch(file, metadataTmpFile.path, patchTmpFilePath.c_str());
Idries Hamadi78330f02018-09-13 18:00:25 +0100173 // pass all but 1st (command) and last (apk path) parameters through to pm for
174 // session creation
175 std::vector<const char*> pm_args{argv + 1, argv + argc - 1};
Henry Daitx7cdf4892019-01-17 16:11:20 +0000176 install_patch(file, patchTmpFilePath.c_str(), pm_args.size(), pm_args.data());
177 adb_unlink(patchTmpFilePath.c_str());
Idries Hamadi78330f02018-09-13 18:00:25 +0100178 delete_device_patch_file(file);
179 return 0;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000180 } else {
181 struct stat sb;
182 if (stat(file, &sb) == -1) {
183 fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno));
184 return 1;
185 }
186
187 int localFd = adb_open(file, O_RDONLY);
188 if (localFd < 0) {
189 fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
190 return 1;
191 }
192
193 std::string error;
194 std::string cmd = "exec:cmd package";
195
196 // don't copy the APK name, but, copy the rest of the arguments as-is
197 while (argc-- > 1) {
198 cmd += " " + escape_arg(std::string(*argv++));
199 }
200
201 // add size parameter [required for streaming installs]
202 // do last to override any user specified value
203 cmd += " " + android::base::StringPrintf("-S %" PRIu64, static_cast<uint64_t>(sb.st_size));
204
Dario Frenidcb4c362018-10-04 16:26:40 +0100205 if (is_apex) {
206 cmd += " --apex";
207 }
208
Idries Hamadi1ecee442018-01-29 16:30:36 +0000209 int remoteFd = adb_connect(cmd, &error);
210 if (remoteFd < 0) {
211 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
212 adb_close(localFd);
213 return 1;
214 }
215
216 char buf[BUFSIZ];
217 copy_to_file(localFd, remoteFd);
218 read_status_line(remoteFd, buf, sizeof(buf));
219
220 adb_close(localFd);
221 adb_close(remoteFd);
222
223 if (!strncmp("Success", buf, 7)) {
224 fputs(buf, stdout);
225 return 0;
226 }
227 fprintf(stderr, "adb: failed to install %s: %s", file, buf);
228 return 1;
229 }
230}
231
Idries Hamadi7919be22018-08-28 12:58:09 +0100232static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy,
233 bool use_localagent) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000234 printf("Performing Push Install\n");
235
Idries Hamadi1ecee442018-01-29 16:30:36 +0000236 // Find last APK argument.
237 // All other arguments passed through verbatim.
238 int last_apk = -1;
239 for (int i = argc - 1; i >= 0; i--) {
Dario Frenidcb4c362018-10-04 16:26:40 +0100240 if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
241 error_exit("APEX packages are only compatible with Streamed Install");
242 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000243 if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) {
244 last_apk = i;
245 break;
246 }
247 }
248
Elliott Hughes0119a912018-10-22 17:02:51 -0700249 if (last_apk == -1) error_exit("need APK file on command line");
Idries Hamadi1ecee442018-01-29 16:30:36 +0000250
251 int result = -1;
252 std::vector<const char*> apk_file = {argv[last_apk]};
253 std::string apk_dest =
Patrick Baumanne75ef0a2018-11-19 14:28:51 -0800254 "/data/local/tmp/" + android::base::Basename(argv[last_apk]);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000255
Idries Hamadi1ecee442018-01-29 16:30:36 +0000256 if (use_fastdeploy == true) {
Idries Hamadib1702db2018-09-06 18:42:39 +0100257 TemporaryFile metadataTmpFile;
258 TemporaryFile patchTmpFile;
259
Idries Hamadi0a525802018-08-21 15:47:35 +0100260 FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
Idries Hamadi78330f02018-09-13 18:00:25 +0100261 extract_metadata(apk_file[0], metadataFile);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000262 fclose(metadataFile);
263
Idries Hamadi78330f02018-09-13 18:00:25 +0100264 create_patch(apk_file[0], metadataTmpFile.path, patchTmpFile.path);
265 apply_patch_on_device(apk_file[0], patchTmpFile.path, apk_dest.c_str());
Idries Hamadi1ecee442018-01-29 16:30:36 +0000266 } else {
267 if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk;
268 }
269
270 argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
271 result = pm_command(argc, argv);
272
273cleanup_apk:
Idries Hamadib1702db2018-09-06 18:42:39 +0100274 if (use_fastdeploy == true) {
275 delete_device_patch_file(apk_file[0]);
276 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000277 delete_device_file(apk_dest);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000278 return result;
279}
280
281int install_app(int argc, const char** argv) {
282 std::vector<int> processedArgIndicies;
283 enum installMode {
284 INSTALL_DEFAULT,
285 INSTALL_PUSH,
286 INSTALL_STREAM
287 } installMode = INSTALL_DEFAULT;
288 bool use_fastdeploy = false;
289 bool is_reinstall = false;
290 bool use_localagent = false;
291 FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
292
293 for (int i = 1; i < argc; i++) {
294 if (!strcmp(argv[i], "--streaming")) {
295 processedArgIndicies.push_back(i);
296 installMode = INSTALL_STREAM;
297 } else if (!strcmp(argv[i], "--no-streaming")) {
298 processedArgIndicies.push_back(i);
299 installMode = INSTALL_PUSH;
300 } else if (!strcmp(argv[i], "-r")) {
301 // Note that this argument is not added to processedArgIndicies because it
302 // must be passed through to pm
303 is_reinstall = true;
304 } else if (!strcmp(argv[i], "--fastdeploy")) {
305 processedArgIndicies.push_back(i);
306 use_fastdeploy = true;
307 } else if (!strcmp(argv[i], "--no-fastdeploy")) {
308 processedArgIndicies.push_back(i);
309 use_fastdeploy = false;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000310 } else if (!strcmp(argv[i], "--force-agent")) {
311 processedArgIndicies.push_back(i);
312 agent_update_strategy = FastDeploy_AgentUpdateAlways;
313 } else if (!strcmp(argv[i], "--date-check-agent")) {
314 processedArgIndicies.push_back(i);
315 agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp;
316 } else if (!strcmp(argv[i], "--version-check-agent")) {
317 processedArgIndicies.push_back(i);
318 agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
319#ifndef _WIN32
320 } else if (!strcmp(argv[i], "--local-agent")) {
321 processedArgIndicies.push_back(i);
322 use_localagent = true;
323#endif
324 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000325 }
326
327 if (installMode == INSTALL_DEFAULT) {
Dario Frenidcb4c362018-10-04 16:26:40 +0100328 if (use_legacy_install()) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000329 installMode = INSTALL_PUSH;
330 } else {
331 installMode = INSTALL_STREAM;
332 }
333 }
334
Dario Frenidcb4c362018-10-04 16:26:40 +0100335 if (installMode == INSTALL_STREAM && use_legacy_install() == true) {
Elliott Hughes0119a912018-10-22 17:02:51 -0700336 error_exit("Attempting to use streaming install on unsupported device");
Idries Hamadi1ecee442018-01-29 16:30:36 +0000337 }
338
Idries Hamadi1ecee442018-01-29 16:30:36 +0000339 if (use_fastdeploy == true && get_device_api_level() < kFastDeployMinApi) {
340 printf("Fast Deploy is only compatible with devices of API version %d or higher, "
341 "ignoring.\n",
342 kFastDeployMinApi);
343 use_fastdeploy = false;
344 }
345
346 std::vector<const char*> passthrough_argv;
347 for (int i = 0; i < argc; i++) {
348 if (std::find(processedArgIndicies.begin(), processedArgIndicies.end(), i) ==
349 processedArgIndicies.end()) {
350 passthrough_argv.push_back(argv[i]);
351 }
352 }
Henry Daitxe4cc4d92018-12-12 10:40:57 +0000353 if (passthrough_argv.size() < 2) {
354 error_exit("install requires an apk argument");
355 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000356
Idries Hamadi1ecee442018-01-29 16:30:36 +0000357 if (use_fastdeploy == true) {
Idries Hamadidc272242018-08-24 11:46:45 +0100358 fastdeploy_set_local_agent(use_localagent);
Idries Hamadib1702db2018-09-06 18:42:39 +0100359 update_agent(agent_update_strategy);
Henry Daitxe4cc4d92018-12-12 10:40:57 +0000360
361 // The last argument must be the APK file
362 const char* file = passthrough_argv.back();
363 use_fastdeploy = find_package(file);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000364 }
365
366 switch (installMode) {
367 case INSTALL_PUSH:
368 return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(),
Idries Hamadi7919be22018-08-28 12:58:09 +0100369 use_fastdeploy, use_localagent);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000370 case INSTALL_STREAM:
371 return install_app_streamed(passthrough_argv.size(), passthrough_argv.data(),
Idries Hamadi7919be22018-08-28 12:58:09 +0100372 use_fastdeploy, use_localagent);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000373 case INSTALL_DEFAULT:
374 default:
375 return 1;
376 }
377}
378
379int install_multiple_app(int argc, const char** argv) {
380 // Find all APK arguments starting at end.
381 // All other arguments passed through verbatim.
382 int first_apk = -1;
383 uint64_t total_size = 0;
384 for (int i = argc - 1; i >= 0; i--) {
385 const char* file = argv[i];
Dario Frenidcb4c362018-10-04 16:26:40 +0100386 if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
387 error_exit("APEX packages are not compatible with install-multiple");
388 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000389
Victor Hsieh88f14b82018-10-04 10:46:56 -0700390 if (android::base::EndsWithIgnoreCase(file, ".apk") ||
Victor Hsieh55174872018-10-29 16:54:23 -0700391 android::base::EndsWithIgnoreCase(file, ".dm") ||
392 android::base::EndsWithIgnoreCase(file, ".fsv_sig")) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000393 struct stat sb;
394 if (stat(file, &sb) != -1) total_size += sb.st_size;
395 first_apk = i;
396 } else {
397 break;
398 }
399 }
400
Elliott Hughes0119a912018-10-22 17:02:51 -0700401 if (first_apk == -1) error_exit("need APK file on command line");
Idries Hamadi1ecee442018-01-29 16:30:36 +0000402
403 std::string install_cmd;
Dario Frenidcb4c362018-10-04 16:26:40 +0100404 if (use_legacy_install()) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000405 install_cmd = "exec:pm";
406 } else {
407 install_cmd = "exec:cmd package";
408 }
409
410 std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64,
411 install_cmd.c_str(), total_size);
412 for (int i = 1; i < first_apk; i++) {
413 cmd += " " + escape_arg(argv[i]);
414 }
415
416 // Create install session
417 std::string error;
418 int fd = adb_connect(cmd, &error);
419 if (fd < 0) {
420 fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
421 return EXIT_FAILURE;
422 }
423 char buf[BUFSIZ];
424 read_status_line(fd, buf, sizeof(buf));
425 adb_close(fd);
426
427 int session_id = -1;
428 if (!strncmp("Success", buf, 7)) {
429 char* start = strrchr(buf, '[');
430 char* end = strrchr(buf, ']');
431 if (start && end) {
432 *end = '\0';
433 session_id = strtol(start + 1, nullptr, 10);
434 }
435 }
436 if (session_id < 0) {
437 fprintf(stderr, "adb: failed to create session\n");
438 fputs(buf, stderr);
439 return EXIT_FAILURE;
440 }
441
442 // Valid session, now stream the APKs
443 int success = 1;
444 for (int i = first_apk; i < argc; i++) {
445 const char* file = argv[i];
446 struct stat sb;
447 if (stat(file, &sb) == -1) {
448 fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno));
449 success = 0;
450 goto finalize_session;
451 }
452
453 std::string cmd =
Victor Hsieh88f14b82018-10-04 10:46:56 -0700454 android::base::StringPrintf("%s install-write -S %" PRIu64 " %d %s -",
Idries Hamadi1ecee442018-01-29 16:30:36 +0000455 install_cmd.c_str(), static_cast<uint64_t>(sb.st_size),
Victor Hsieh88f14b82018-10-04 10:46:56 -0700456 session_id, android::base::Basename(file).c_str());
Idries Hamadi1ecee442018-01-29 16:30:36 +0000457
458 int localFd = adb_open(file, O_RDONLY);
459 if (localFd < 0) {
460 fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
461 success = 0;
462 goto finalize_session;
463 }
464
465 std::string error;
466 int remoteFd = adb_connect(cmd, &error);
467 if (remoteFd < 0) {
468 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
469 adb_close(localFd);
470 success = 0;
471 goto finalize_session;
472 }
473
474 copy_to_file(localFd, remoteFd);
475 read_status_line(remoteFd, buf, sizeof(buf));
476
477 adb_close(localFd);
478 adb_close(remoteFd);
479
480 if (strncmp("Success", buf, 7)) {
481 fprintf(stderr, "adb: failed to write %s\n", file);
482 fputs(buf, stderr);
483 success = 0;
484 goto finalize_session;
485 }
486 }
487
488finalize_session:
489 // Commit session if we streamed everything okay; otherwise abandon
490 std::string service = android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
491 success ? "commit" : "abandon", session_id);
492 fd = adb_connect(service, &error);
493 if (fd < 0) {
494 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
495 return EXIT_FAILURE;
496 }
497 read_status_line(fd, buf, sizeof(buf));
498 adb_close(fd);
499
500 if (!strncmp("Success", buf, 7)) {
501 fputs(buf, stdout);
502 return 0;
503 }
504 fprintf(stderr, "adb: failed to finalize session\n");
505 fputs(buf, stderr);
506 return EXIT_FAILURE;
507}
508
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700509int install_multi_package(int argc, const char** argv) {
510 // Find all APK arguments starting at end.
511 // All other arguments passed through verbatim.
512 int first_apk = -1;
513 for (int i = argc - 1; i >= 0; i--) {
514 const char* file = argv[i];
515 if (android::base::EndsWithIgnoreCase(file, ".apk")) {
516 first_apk = i;
517 } else {
518 break;
519 }
520 }
521
522 if (first_apk == -1) error_exit("need APK file on command line");
523
524 if (use_legacy_install()) {
525 fprintf(stderr, "adb: multi-package install is not supported on this device\n");
526 return EXIT_FAILURE;
527 }
528 std::string install_cmd = "exec:cmd package";
529
530 std::string multi_package_cmd =
531 android::base::StringPrintf("%s install-create --multi-package", install_cmd.c_str());
532
533 // Create multi-package install session
534 std::string error;
535 int fd = adb_connect(multi_package_cmd, &error);
536 if (fd < 0) {
537 fprintf(stderr, "adb: connect error for create multi-package: %s\n", error.c_str());
538 return EXIT_FAILURE;
539 }
540 char buf[BUFSIZ];
541 read_status_line(fd, buf, sizeof(buf));
542 adb_close(fd);
543
544 int parent_session_id = -1;
545 if (!strncmp("Success", buf, 7)) {
546 char* start = strrchr(buf, '[');
547 char* end = strrchr(buf, ']');
548 if (start && end) {
549 *end = '\0';
550 parent_session_id = strtol(start + 1, nullptr, 10);
551 }
552 }
553 if (parent_session_id < 0) {
554 fprintf(stderr, "adb: failed to create multi-package session\n");
555 fputs(buf, stderr);
556 return EXIT_FAILURE;
557 }
558
559 fprintf(stdout, "Created parent session ID %d.\n", parent_session_id);
560
561 std::vector<int> session_ids;
562
563 // Valid session, now create the individual sessions and stream the APKs
564 int success = EXIT_FAILURE;
565 std::string individual_cmd =
566 android::base::StringPrintf("%s install-create", install_cmd.c_str());
567 std::string all_session_ids = "";
568 for (int i = 1; i < first_apk; i++) {
569 individual_cmd += " " + escape_arg(argv[i]);
570 }
571 std::string cmd = "";
572 for (int i = first_apk; i < argc; i++) {
573 // Create individual install session
574 fd = adb_connect(individual_cmd, &error);
575 if (fd < 0) {
576 fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
577 goto finalize_multi_package_session;
578 }
579 char buf[BUFSIZ];
580 read_status_line(fd, buf, sizeof(buf));
581 adb_close(fd);
582
583 int session_id = -1;
584 if (!strncmp("Success", buf, 7)) {
585 char* start = strrchr(buf, '[');
586 char* end = strrchr(buf, ']');
587 if (start && end) {
588 *end = '\0';
589 session_id = strtol(start + 1, nullptr, 10);
590 }
591 }
592 if (session_id < 0) {
593 fprintf(stderr, "adb: failed to create multi-package session\n");
594 fputs(buf, stderr);
595 goto finalize_multi_package_session;
596 }
597
598 fprintf(stdout, "Created child session ID %d.\n", session_id);
599 session_ids.push_back(session_id);
600
601 const char* file = argv[i];
602 struct stat sb;
603 if (stat(file, &sb) == -1) {
604 fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno));
605 goto finalize_multi_package_session;
606 }
607
608 std::string cmd =
609 android::base::StringPrintf("%s install-write -S %" PRIu64 " %d %d_%s -",
610 install_cmd.c_str(), static_cast<uint64_t>(sb.st_size),
611 session_id, i, android::base::Basename(file).c_str());
612
613 int localFd = adb_open(file, O_RDONLY);
614 if (localFd < 0) {
615 fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
616 goto finalize_multi_package_session;
617 }
618
619 std::string error;
620 int remoteFd = adb_connect(cmd, &error);
621 if (remoteFd < 0) {
622 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
623 adb_close(localFd);
624 goto finalize_multi_package_session;
625 }
626
627 copy_to_file(localFd, remoteFd);
628 read_status_line(remoteFd, buf, sizeof(buf));
629
630 adb_close(localFd);
631 adb_close(remoteFd);
632
633 if (strncmp("Success", buf, 7)) {
634 fprintf(stderr, "adb: failed to write %s\n", file);
635 fputs(buf, stderr);
636 goto finalize_multi_package_session;
637 }
638
639 all_session_ids += android::base::StringPrintf(" %d", session_id);
640 }
641
642 cmd = android::base::StringPrintf("%s install-add-session %d%s", install_cmd.c_str(),
643 parent_session_id, all_session_ids.c_str());
644 fd = adb_connect(cmd, &error);
645 if (fd < 0) {
646 fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
647 goto finalize_multi_package_session;
648 }
649 read_status_line(fd, buf, sizeof(buf));
650 adb_close(fd);
651
652 if (strncmp("Success", buf, 7)) {
653 fprintf(stderr, "adb: failed to link sessions (%s)\n", cmd.c_str());
654 fputs(buf, stderr);
655 goto finalize_multi_package_session;
656 }
657
658 // no failures means we can proceed with the assumption of success
659 success = 0;
660
661finalize_multi_package_session:
662 // Commit session if we streamed everything okay; otherwise abandon
663 std::string service =
664 android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
665 success == 0 ? "commit" : "abandon", parent_session_id);
666 fd = adb_connect(service, &error);
667 if (fd < 0) {
668 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
669 return EXIT_FAILURE;
670 }
671 read_status_line(fd, buf, sizeof(buf));
672 adb_close(fd);
673
674 if (!strncmp("Success", buf, 7)) {
675 fputs(buf, stdout);
676 if (success == 0) {
677 return 0;
678 }
679 } else {
680 fprintf(stderr, "adb: failed to finalize session\n");
681 fputs(buf, stderr);
682 }
683
684 // try to abandon all remaining sessions
685 for (std::size_t i = 0; i < session_ids.size(); i++) {
686 service = android::base::StringPrintf("%s install-abandon %d", install_cmd.c_str(),
687 session_ids[i]);
688 fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]);
689 fd = adb_connect(service, &error);
690 if (fd < 0) {
691 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
692 continue;
693 }
694 read_status_line(fd, buf, sizeof(buf));
695 adb_close(fd);
696 }
697 return EXIT_FAILURE;
698}
699
Idries Hamadi1ecee442018-01-29 16:30:36 +0000700int delete_device_file(const std::string& filename) {
701 std::string cmd = "rm -f " + escape_arg(filename);
702 return send_shell_command(cmd);
703}