blob: ea50f591adaf1ce2caadb43d90b78901bb0668b4 [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
Yurii Zubrytskyie59c1bd2019-06-27 13:47:34 -070019#include <fcntl.h>
Josh Gaoa4dfc142020-02-19 13:50:57 -080020#include <inttypes.h>
Idries Hamadi1ecee442018-01-29 16:30:36 +000021#include <stdio.h>
22#include <stdlib.h>
Idries Hamadi78330f02018-09-13 18:00:25 +010023#include <unistd.h>
Idries Hamadi1ecee442018-01-29 16:30:36 +000024#include <algorithm>
Idries Hamadi1ecee442018-01-29 16:30:36 +000025#include <string>
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -070026#include <string_view>
Idries Hamadi1ecee442018-01-29 16:30:36 +000027#include <vector>
28
Josh Gaob9155972019-01-11 13:13:20 -080029#include <android-base/file.h>
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -070030#include <android-base/parsebool.h>
Josh Gaob9155972019-01-11 13:13:20 -080031#include <android-base/stringprintf.h>
32#include <android-base/strings.h>
33
Idries Hamadi78330f02018-09-13 18:00:25 +010034#include "adb.h"
35#include "adb_client.h"
Josh Gaob9155972019-01-11 13:13:20 -080036#include "adb_unique_fd.h"
Idries Hamadi78330f02018-09-13 18:00:25 +010037#include "adb_utils.h"
Idries Hamadi78330f02018-09-13 18:00:25 +010038#include "client/file_sync_client.h"
39#include "commandline.h"
40#include "fastdeploy.h"
Alex Buynytskyy175ce292020-02-13 06:52:04 -080041#include "incremental.h"
Idries Hamadi1ecee442018-01-29 16:30:36 +000042
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -070043using namespace std::literals;
44
Idries Hamadidc272242018-08-24 11:46:45 +010045static constexpr int kFastDeployMinApi = 24;
46
Yurii Zubrytskyie59c1bd2019-06-27 13:47:34 -070047namespace {
48
49enum InstallMode {
50 INSTALL_DEFAULT,
51 INSTALL_PUSH,
52 INSTALL_STREAM,
Alex Buynytskyy175ce292020-02-13 06:52:04 -080053 INSTALL_INCREMENTAL,
Yurii Zubrytskyie59c1bd2019-06-27 13:47:34 -070054};
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -070055
56enum class CmdlineOption { None, Enable, Disable };
Yurii Zubrytskyie59c1bd2019-06-27 13:47:34 -070057}
58
Dario Frenidcb4c362018-10-04 16:26:40 +010059static bool can_use_feature(const char* feature) {
Josh Gao291733b2020-04-16 19:34:43 -070060 // 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) {
Yurii Zubrytskyie59c1bd2019-06-27 13:47:34 -070063 return false;
Idries Hamadi1ecee442018-01-29 16:30:36 +000064 }
Josh Gao291733b2020-04-16 19:34:43 -070065 return CanUseFeature(*features, feature);
Dario Frenidcb4c362018-10-04 16:26:40 +010066}
67
Yurii Zubrytskyie59c1bd2019-06-27 13:47:34 -070068static InstallMode best_install_mode() {
69 if (can_use_feature(kFeatureCmd)) {
70 return INSTALL_STREAM;
71 }
72 return INSTALL_PUSH;
Dario Frenidcb4c362018-10-04 16:26:40 +010073}
74
75static bool is_apex_supported() {
76 return can_use_feature(kFeatureApex);
Idries Hamadi1ecee442018-01-29 16:30:36 +000077}
78
Alex Buynytskyy175ce292020-02-13 06:52:04 -080079static bool is_abb_exec_supported() {
80 return can_use_feature(kFeatureAbbExec);
81}
82
Idries Hamadi1ecee442018-01-29 16:30:36 +000083static 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
93static 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
115static 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
136int uninstall_app(int argc, const char** argv) {
Yurii Zubrytskyie59c1bd2019-06-27 13:47:34 -0700137 if (best_install_mode() == INSTALL_PUSH) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000138 return uninstall_app_legacy(argc, argv);
139 }
140 return uninstall_app_streamed(argc, argv);
141}
142
143static 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
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700157static 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
Alex Buynytskyy1af550e2019-09-16 12:10:54 -0700165static int install_app_streamed(int argc, const char** argv, bool use_fastdeploy) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000166 printf("Performing Streamed Install\n");
167
168 // The last argument must be the APK file
169 const char* file = argv[argc - 1];
Dario Frenidcb4c362018-10-04 16:26:40 +0100170 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");
Idries Hamadi1ecee442018-01-29 16:30:36 +0000185 }
186
Alex Buynytskyy1af550e2019-09-16 12:10:54 -0700187 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));
Henry Daitx7cdf4892019-01-17 16:11:20 +0000195 }
Alex Buynytskyybdff85c2019-09-13 14:19:01 -0700196 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000197
Alex Buynytskyybdff85c2019-09-13 14:19:01 -0700198 struct stat sb;
199 if (stat(file, &sb) == -1) {
200 fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno));
Idries Hamadi1ecee442018-01-29 16:30:36 +0000201 return 1;
202 }
Alex Buynytskyybdff85c2019-09-13 14:19:01 -0700203
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
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800214 const bool use_abb_exec = is_abb_exec_supported();
Alex Buynytskyybdff85c2019-09-13 14:19:01 -0700215 std::string error;
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800216 std::vector<std::string> cmd_args = {use_abb_exec ? "package" : "exec:cmd package"};
Alex Buynytskyybdff85c2019-09-13 14:19:01 -0700217 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) {
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800221 if (use_abb_exec) {
Alex Buynytskyybdff85c2019-09-13 14:19:01 -0700222 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
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700237 unique_fd remote_fd = send_command(cmd_args, &error);
Alex Buynytskyybdff85c2019-09-13 14:19:01 -0700238 if (remote_fd < 0) {
239 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
240 return 1;
241 }
242
Josh Gaod7f1d0b2019-12-03 16:05:54 -0800243 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 }
Alex Buynytskyybdff85c2019-09-13 14:19:01 -0700247
248 char buf[BUFSIZ];
249 read_status_line(remote_fd.get(), buf, sizeof(buf));
Josh Gaod7f1d0b2019-12-03 16:05:54 -0800250 if (strncmp("Success", buf, 7) != 0) {
251 fprintf(stderr, "adb: failed to install %s: %s", file, buf);
252 return 1;
Alex Buynytskyybdff85c2019-09-13 14:19:01 -0700253 }
Josh Gaod7f1d0b2019-12-03 16:05:54 -0800254
255 fputs(buf, stdout);
256 return 0;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000257}
258
Alex Buynytskyy1af550e2019-09-16 12:10:54 -0700259static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000260 printf("Performing Push Install\n");
261
Idries Hamadi1ecee442018-01-29 16:30:36 +0000262 // 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--) {
Dario Frenidcb4c362018-10-04 16:26:40 +0100266 if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
267 error_exit("APEX packages are only compatible with Streamed Install");
268 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000269 if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) {
270 last_apk = i;
271 break;
272 }
273 }
274
Elliott Hughes0119a912018-10-22 17:02:51 -0700275 if (last_apk == -1) error_exit("need APK file on command line");
Idries Hamadi1ecee442018-01-29 16:30:36 +0000276
277 int result = -1;
278 std::vector<const char*> apk_file = {argv[last_apk]};
Yurii Zubrytskyie59c1bd2019-06-27 13:47:34 -0700279 std::string apk_dest = "/data/local/tmp/" + android::base::Basename(argv[last_apk]);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000280 argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
Idries Hamadi1ecee442018-01-29 16:30:36 +0000281
Alex Buynytskyy1af550e2019-09-16 12:10:54 -0700282 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 }
Idries Hamadib1702db2018-09-06 18:42:39 +0100293 }
Alex Buynytskyy1af550e2019-09-16 12:10:54 -0700294
Josh Gao8a410a02020-03-30 23:25:16 -0700295 if (do_sync_push(apk_file, apk_dest.c_str(), false, CompressionType::Any, false)) {
Alex Buynytskyy1af550e2019-09-16 12:10:54 -0700296 result = pm_command(argc, argv);
297 delete_device_file(apk_dest);
298 }
299
Idries Hamadi1ecee442018-01-29 16:30:36 +0000300 return result;
301}
302
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800303template <class TimePoint>
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700304static int ms_between(TimePoint start, TimePoint end) {
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800305 return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
306}
307
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700308static int install_app_incremental(int argc, const char** argv, bool wait, bool silent) {
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800309 using clock = std::chrono::high_resolution_clock;
310 const auto start = clock::now();
311 int first_apk = -1;
312 int last_apk = -1;
Alex Buynytskyy31ff0ca2020-05-14 13:29:05 -0700313 incremental::Args passthrough_args = {};
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800314 for (int i = 0; i < argc; ++i) {
315 const auto arg = std::string_view(argv[i]);
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700316 if (android::base::EndsWithIgnoreCase(arg, ".apk"sv)) {
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800317 last_apk = i;
318 if (first_apk == -1) {
319 first_apk = i;
320 }
Alex Buynytskyy31ff0ca2020-05-14 13:29:05 -0700321 } else if (arg.starts_with("install"sv)) {
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800322 // 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
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800324 } else {
Alex Buynytskyy31ff0ca2020-05-14 13:29:05 -0700325 passthrough_args.push_back(arg);
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800326 }
327 }
328
Josh Gaofb139d92020-03-30 17:38:37 -0700329 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 }
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800335
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700336 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 }
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800344
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700345 printf("Performing Incremental Install\n");
Alex Buynytskyy31ff0ca2020-05-14 13:29:05 -0700346 auto server_process = incremental::install(files, passthrough_args, silent);
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800347 if (!server_process) {
348 return -1;
349 }
350
351 const auto end = clock::now();
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700352 printf("Install command complete in %d ms\n", ms_between(start, end));
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800353
354 if (wait) {
355 (*server_process).wait();
356 }
357
358 return 0;
359}
360
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700361static std::pair<InstallMode, std::optional<InstallMode>> calculate_install_mode(
362 InstallMode modeFromArgs, bool fastdeploy, CmdlineOption incremental_request) {
363 if (incremental_request == CmdlineOption::Enable) {
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700364 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) {
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700372 if (incremental_request == CmdlineOption::Enable) {
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700373 error_exit("--incremental is not compatible with other installation modes");
374 }
375 return {modeFromArgs, std::nullopt};
376 }
377
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700378 if (incremental_request != CmdlineOption::Disable && !is_abb_exec_supported()) {
379 if (incremental_request == CmdlineOption::None) {
380 incremental_request = CmdlineOption::Disable;
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700381 } else {
382 error_exit("Device doesn't support incremental installations");
383 }
384 }
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700385 if (incremental_request == CmdlineOption::None) {
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700386 // 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) {
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700391 incremental_request = CmdlineOption::Disable;
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700392 }
393 }
394 }
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700395 if (incremental_request == CmdlineOption::None) {
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700396 // 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) {
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700411 incremental_request = CmdlineOption::Disable;
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700412 }
413 }
414 }
415
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700416 if (incremental_request == CmdlineOption::Enable) {
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700417 // explicitly requested - no fallback
418 return {INSTALL_INCREMENTAL, std::nullopt};
419 }
420 const auto bestMode = best_install_mode();
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700421 if (incremental_request == CmdlineOption::None) {
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700422 // 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
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700429static 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;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000436
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700437 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);
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800451 }
452 }
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700453 return passthrough;
454}
Alex Buynytskyy175ce292020-02-13 06:52:04 -0800455
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700456static 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
481int 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) &&
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700498 best_install_mode() == INSTALL_PUSH) {
Elliott Hughes0119a912018-10-22 17:02:51 -0700499 error_exit("Attempting to use streaming install on unsupported device");
Idries Hamadi1ecee442018-01-29 16:30:36 +0000500 }
501
Alex Buynytskyy1af550e2019-09-16 12:10:54 -0700502 if (use_fastdeploy && get_device_api_level() < kFastDeployMinApi) {
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700503 fprintf(stderr,
504 "Fast Deploy is only compatible with devices of API version %d or higher, "
505 "ignoring.\n",
506 kFastDeployMinApi);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000507 use_fastdeploy = false;
508 }
Alex Buynytskyy1af550e2019-09-16 12:10:54 -0700509 fastdeploy_set_agent_update_strategy(agent_update_strategy);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000510
Henry Daitxe4cc4d92018-12-12 10:40:57 +0000511 if (passthrough_argv.size() < 2) {
512 error_exit("install requires an apk argument");
513 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000514
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700515 auto run_install_mode = [&](InstallMode install_mode, bool silent) {
516 switch (install_mode) {
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700517 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(),
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700525 incremental_wait, silent);
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700526 case INSTALL_DEFAULT:
527 default:
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700528 error_exit("invalid install mode");
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700529 }
530 };
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700531 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);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000534 }
Yurii Zubrytskyi39ee3d82020-03-26 18:20:39 -0700535 return res;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000536}
537
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700538static int install_multiple_app_streamed(int argc, const char** argv) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000539 // 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];
Dario Frenidcb4c362018-10-04 16:26:40 +0100545 if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
546 error_exit("APEX packages are not compatible with install-multiple");
547 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000548
Victor Hsieh88f14b82018-10-04 10:46:56 -0700549 if (android::base::EndsWithIgnoreCase(file, ".apk") ||
Victor Hsieh55174872018-10-29 16:54:23 -0700550 android::base::EndsWithIgnoreCase(file, ".dm") ||
551 android::base::EndsWithIgnoreCase(file, ".fsv_sig")) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000552 struct stat sb;
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700553 if (stat(file, &sb) == -1) perror_exit("failed to stat \"%s\"", file);
554 total_size += sb.st_size;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000555 first_apk = i;
556 } else {
557 break;
558 }
559 }
560
Elliott Hughes0119a912018-10-22 17:02:51 -0700561 if (first_apk == -1) error_exit("need APK file on command line");
Idries Hamadi1ecee442018-01-29 16:30:36 +0000562
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700563 const bool use_abb_exec = is_abb_exec_supported();
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700564 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);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000571 for (int i = 1; i < first_apk; i++) {
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700572 if (use_abb_exec) {
573 cmd_args.push_back(argv[i]);
574 } else {
575 cmd_args.push_back(escape_arg(argv[i]));
576 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000577 }
578
579 // Create install session
580 std::string error;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000581 char buf[BUFSIZ];
Josh Gaob9155972019-01-11 13:13:20 -0800582 {
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700583 unique_fd fd = send_command(cmd_args, &error);
Josh Gaob9155972019-01-11 13:13:20 -0800584 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 }
Idries Hamadi1ecee442018-01-29 16:30:36 +0000590
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 }
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700605 const auto session_id_str = std::to_string(session_id);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000606
607 // Valid session, now stream the APKs
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700608 bool success = true;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000609 for (int i = first_apk; i < argc; i++) {
610 const char* file = argv[i];
611 struct stat sb;
612 if (stat(file, &sb) == -1) {
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700613 fprintf(stderr, "adb: failed to stat \"%s\": %s\n", file, strerror(errno));
614 success = false;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000615 goto finalize_session;
616 }
617
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700618 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 };
Idries Hamadi1ecee442018-01-29 16:30:36 +0000627
Josh Gaob9155972019-01-11 13:13:20 -0800628 unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC));
629 if (local_fd < 0) {
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700630 fprintf(stderr, "adb: failed to open \"%s\": %s\n", file, strerror(errno));
631 success = false;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000632 goto finalize_session;
633 }
634
635 std::string error;
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700636 unique_fd remote_fd = send_command(cmd_args, &error);
Josh Gaob9155972019-01-11 13:13:20 -0800637 if (remote_fd < 0) {
Idries Hamadi1ecee442018-01-29 16:30:36 +0000638 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700639 success = false;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000640 goto finalize_session;
641 }
642
Josh Gaod7f1d0b2019-12-03 16:05:54 -0800643 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
Josh Gaob9155972019-01-11 13:13:20 -0800649 read_status_line(remote_fd.get(), buf, sizeof(buf));
Idries Hamadi1ecee442018-01-29 16:30:36 +0000650
651 if (strncmp("Success", buf, 7)) {
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700652 fprintf(stderr, "adb: failed to write \"%s\"\n", file);
Idries Hamadi1ecee442018-01-29 16:30:36 +0000653 fputs(buf, stderr);
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700654 success = false;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000655 goto finalize_session;
656 }
657 }
658
659finalize_session:
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700660 // Commit session if we streamed everything okay; otherwise abandon.
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700661 std::vector<std::string> service_args = {
662 install_cmd,
663 success ? "install-commit" : "install-abandon",
664 session_id_str,
665 };
Josh Gaob9155972019-01-11 13:13:20 -0800666 {
Alex Buynytskyy8594fcd2020-04-23 14:45:52 -0700667 unique_fd fd = send_command(service_args, &error);
Josh Gaob9155972019-01-11 13:13:20 -0800668 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));
Idries Hamadi1ecee442018-01-29 16:30:36 +0000673 }
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700674 if (!success) return EXIT_FAILURE;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000675
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700676 if (strncmp("Success", buf, 7)) {
677 fprintf(stderr, "adb: failed to finalize session\n");
678 fputs(buf, stderr);
679 return EXIT_FAILURE;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000680 }
Elliott Hughesb6ebbe22019-08-05 17:06:04 -0700681
682 fputs(buf, stdout);
683 return EXIT_SUCCESS;
Idries Hamadi1ecee442018-01-29 16:30:36 +0000684}
685
Alex Buynytskyy7a4224f2020-05-18 11:27:44 -0700686int 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
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700724int install_multi_package(int argc, const char** argv) {
725 // Find all APK arguments starting at end.
726 // All other arguments passed through verbatim.
Dario Freni907ef682019-01-14 17:06:32 +0000727 bool apex_found = false;
728 int first_package = -1;
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700729 for (int i = argc - 1; i >= 0; i--) {
730 const char* file = argv[i];
Dario Freni907ef682019-01-14 17:06:32 +0000731 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 }
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700737 } else {
738 break;
739 }
740 }
741
Dario Freni907ef682019-01-14 17:06:32 +0000742 if (first_package == -1) error_exit("need APK or APEX files on command line");
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700743
Yurii Zubrytskyie59c1bd2019-06-27 13:47:34 -0700744 if (best_install_mode() == INSTALL_PUSH) {
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700745 fprintf(stderr, "adb: multi-package install is not supported on this device\n");
746 return EXIT_FAILURE;
747 }
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700748
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700749 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);
Dario Freni2042fd22019-01-29 14:17:05 +0000756 for (int i = 1; i < first_package; i++) {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700757 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 }
Dario Freni2042fd22019-01-29 14:17:05 +0000762 }
763
Dario Freni907ef682019-01-14 17:06:32 +0000764 if (apex_found) {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700765 multi_package_cmd_args.emplace_back("--staged");
Dario Freni907ef682019-01-14 17:06:32 +0000766 }
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700767
768 // Create multi-package install session
769 std::string error;
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700770 char buf[BUFSIZ];
Josh Gaob9155972019-01-11 13:13:20 -0800771 {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700772 unique_fd fd = send_command(multi_package_cmd_args, &error);
Josh Gaob9155972019-01-11 13:13:20 -0800773 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 }
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700779
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 }
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700794 const auto parent_session_id_str = std::to_string(parent_session_id);
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700795
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;
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700802 std::vector<std::string> individual_cmd_args = {install_cmd, "install-create"};
Dario Freni907ef682019-01-14 17:06:32 +0000803 for (int i = 1; i < first_package; i++) {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700804 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 }
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700809 }
Dario Freni907ef682019-01-14 17:06:32 +0000810 if (apex_found) {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700811 individual_cmd_args.emplace_back("--staged");
Dario Freni907ef682019-01-14 17:06:32 +0000812 }
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700813
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
Dario Freni907ef682019-01-14 17:06:32 +0000826 for (int i = first_package; i < argc; i++) {
827 const char* file = argv[i];
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700828 char buf[BUFSIZ];
Josh Gaob9155972019-01-11 13:13:20 -0800829 {
Dario Freni907ef682019-01-14 17:06:32 +0000830 unique_fd fd;
831 // Create individual install session
832 if (android::base::EndsWithIgnoreCase(file, ".apex")) {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700833 fd = send_command(individual_apex_cmd_args, &error);
Dario Freni907ef682019-01-14 17:06:32 +0000834 } else {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700835 fd = send_command(individual_cmd_args, &error);
Dario Freni907ef682019-01-14 17:06:32 +0000836 }
Josh Gaob9155972019-01-11 13:13:20 -0800837 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 }
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700843
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 }
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700858 const auto session_id_str = std::to_string(session_id);
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700859
860 fprintf(stdout, "Created child session ID %d.\n", session_id);
861 session_ids.push_back(session_id);
862
Dario Freni7d5a5e12019-02-25 12:00:32 +0000863 // 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
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700873 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,
Alex Buynytskyy83e11f52020-07-14 17:55:22 -0700879 android::base::StringPrintf("%d_%s", i, android::base::Basename(split).c_str()),
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700880 "-",
881 };
Dario Freni7d5a5e12019-02-25 12:00:32 +0000882
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;
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700890 unique_fd remote_fd = send_command(cmd_args, &error);
Dario Freni7d5a5e12019-02-25 12:00:32 +0000891 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
Josh Gaod7f1d0b2019-12-03 16:05:54 -0800896 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
Dario Freni7d5a5e12019-02-25 12:00:32 +0000901 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 }
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700908 }
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700909 add_session_cmd_args.push_back(std::to_string(session_id));
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700910 }
911
Josh Gaob9155972019-01-11 13:13:20 -0800912 {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700913 unique_fd fd = send_command(add_session_cmd_args, &error);
Josh Gaob9155972019-01-11 13:13:20 -0800914 if (fd < 0) {
Dario Freni907ef682019-01-14 17:06:32 +0000915 fprintf(stderr, "adb: connect error for install-add-session: %s\n", error.c_str());
Josh Gaob9155972019-01-11 13:13:20 -0800916 goto finalize_multi_package_session;
917 }
918 read_status_line(fd.get(), buf, sizeof(buf));
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700919 }
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700920
921 if (strncmp("Success", buf, 7)) {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700922 fprintf(stderr, "adb: failed to link sessions (%s)\n",
923 android::base::Join(add_session_cmd_args, " ").c_str());
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700924 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
931finalize_multi_package_session:
932 // Commit session if we streamed everything okay; otherwise abandon
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700933 std::vector<std::string> service_args = {
934 install_cmd,
935 success == 0 ? "install-commit" : "install-abandon",
936 parent_session_id_str,
937 };
938
Josh Gaob9155972019-01-11 13:13:20 -0800939 {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700940 unique_fd fd = send_command(service_args, &error);
Josh Gaob9155972019-01-11 13:13:20 -0800941 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));
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700946 }
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700947
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
Dario Freni7d5a5e12019-02-25 12:00:32 +0000958 session_ids.push_back(parent_session_id);
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700959 // try to abandon all remaining sessions
960 for (std::size_t i = 0; i < session_ids.size(); i++) {
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700961 std::vector<std::string> service_args = {
962 install_cmd,
963 "install-abandon",
964 std::to_string(session_ids[i]),
965 };
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700966 fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]);
Alex Buynytskyy77138ae2020-05-18 16:48:14 -0700967 unique_fd fd = send_command(service_args, &error);
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700968 if (fd < 0) {
969 fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
970 continue;
971 }
Josh Gaob9155972019-01-11 13:13:20 -0800972 read_status_line(fd.get(), buf, sizeof(buf));
Patrick Baumann810ee9b2018-10-09 10:45:03 -0700973 }
974 return EXIT_FAILURE;
975}
976
Idries Hamadi1ecee442018-01-29 16:30:36 +0000977int delete_device_file(const std::string& filename) {
Elliott Hughes203f5372019-08-02 16:06:06 -0700978 // 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");
Idries Hamadi1ecee442018-01-29 16:30:36 +0000994}