[adb] Speed up the streaming install
1. Use bigger buffer for transfers - 64kb is the default size for push, so let it be the same in streaming 2. Use abb when it's available for lower overhead 3. Add a posix_fadvise() on the source APK 4. Increase buffer sizes for the socketpair that's transferring the data from adbd. Overall this saves about 25% time for streaming installations and makes it faster than the legacy push (at last!) Test: manual Change-Id: Ieb84284da2058944815e062ef6e4389b842565fa
This commit is contained in:
parent
f7970cee69
commit
6eca0e6999
5 changed files with 75 additions and 29 deletions
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "adb_install.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
@ -40,18 +41,31 @@
|
|||
static constexpr int kFastDeployMinApi = 24;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
enum InstallMode {
|
||||
INSTALL_DEFAULT,
|
||||
INSTALL_PUSH,
|
||||
INSTALL_STREAM,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static bool can_use_feature(const char* feature) {
|
||||
FeatureSet features;
|
||||
std::string error;
|
||||
if (!adb_get_feature_set(&features, &error)) {
|
||||
fprintf(stderr, "error: %s\n", error.c_str());
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return CanUseFeature(features, feature);
|
||||
}
|
||||
|
||||
static bool use_legacy_install() {
|
||||
return !can_use_feature(kFeatureCmd);
|
||||
static InstallMode best_install_mode() {
|
||||
if (can_use_feature(kFeatureCmd)) {
|
||||
return INSTALL_STREAM;
|
||||
}
|
||||
return INSTALL_PUSH;
|
||||
}
|
||||
|
||||
static bool is_apex_supported() {
|
||||
|
@ -112,7 +126,7 @@ static int uninstall_app_legacy(int argc, const char** argv) {
|
|||
}
|
||||
|
||||
int uninstall_app(int argc, const char** argv) {
|
||||
if (use_legacy_install()) {
|
||||
if (best_install_mode() == INSTALL_PUSH) {
|
||||
return uninstall_app_legacy(argc, argv);
|
||||
}
|
||||
return uninstall_app_streamed(argc, argv);
|
||||
|
@ -200,32 +214,49 @@ static int install_app_streamed(int argc, const char** argv, bool use_fastdeploy
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
posix_fadvise(local_fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
|
||||
#endif
|
||||
|
||||
const bool use_abb = can_use_feature(kFeatureAbb);
|
||||
std::string error;
|
||||
std::string cmd = "exec:cmd package";
|
||||
std::vector<std::string> cmd_args = {use_abb ? "package" : "exec:cmd package"};
|
||||
cmd_args.reserve(argc + 3);
|
||||
|
||||
// don't copy the APK name, but, copy the rest of the arguments as-is
|
||||
while (argc-- > 1) {
|
||||
cmd += " " + escape_arg(std::string(*argv++));
|
||||
if (use_abb) {
|
||||
cmd_args.push_back(*argv++);
|
||||
} else {
|
||||
cmd_args.push_back(escape_arg(*argv++));
|
||||
}
|
||||
}
|
||||
|
||||
// add size parameter [required for streaming installs]
|
||||
// do last to override any user specified value
|
||||
cmd += " " + android::base::StringPrintf("-S %" PRIu64, static_cast<uint64_t>(sb.st_size));
|
||||
cmd_args.push_back("-S");
|
||||
cmd_args.push_back(
|
||||
android::base::StringPrintf("%" PRIu64, static_cast<uint64_t>(sb.st_size)));
|
||||
|
||||
if (is_apex) {
|
||||
cmd += " --apex";
|
||||
cmd_args.push_back("--apex");
|
||||
}
|
||||
|
||||
unique_fd remote_fd(adb_connect(cmd, &error));
|
||||
unique_fd remote_fd;
|
||||
if (use_abb) {
|
||||
remote_fd = send_abb_exec_command(cmd_args, &error);
|
||||
} else {
|
||||
remote_fd.reset(adb_connect(android::base::Join(cmd_args, " "), &error));
|
||||
}
|
||||
if (remote_fd < 0) {
|
||||
fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
char buf[BUFSIZ];
|
||||
copy_to_file(local_fd.get(), remote_fd.get());
|
||||
read_status_line(remote_fd.get(), buf, sizeof(buf));
|
||||
|
||||
char buf[BUFSIZ];
|
||||
read_status_line(remote_fd.get(), buf, sizeof(buf));
|
||||
if (!strncmp("Success", buf, 7)) {
|
||||
fputs(buf, stdout);
|
||||
return 0;
|
||||
|
@ -256,8 +287,7 @@ static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy,
|
|||
|
||||
int result = -1;
|
||||
std::vector<const char*> apk_file = {argv[last_apk]};
|
||||
std::string apk_dest =
|
||||
"/data/local/tmp/" + android::base::Basename(argv[last_apk]);
|
||||
std::string apk_dest = "/data/local/tmp/" + android::base::Basename(argv[last_apk]);
|
||||
|
||||
if (use_fastdeploy == true) {
|
||||
#if defined(ENABLE_FASTDEPLOY)
|
||||
|
@ -292,11 +322,7 @@ cleanup_apk:
|
|||
|
||||
int install_app(int argc, const char** argv) {
|
||||
std::vector<int> processedArgIndicies;
|
||||
enum installMode {
|
||||
INSTALL_DEFAULT,
|
||||
INSTALL_PUSH,
|
||||
INSTALL_STREAM
|
||||
} installMode = INSTALL_DEFAULT;
|
||||
InstallMode installMode = INSTALL_DEFAULT;
|
||||
bool use_fastdeploy = false;
|
||||
bool is_reinstall = false;
|
||||
bool use_localagent = false;
|
||||
|
@ -337,14 +363,10 @@ int install_app(int argc, const char** argv) {
|
|||
}
|
||||
|
||||
if (installMode == INSTALL_DEFAULT) {
|
||||
if (use_legacy_install()) {
|
||||
installMode = INSTALL_PUSH;
|
||||
} else {
|
||||
installMode = INSTALL_STREAM;
|
||||
}
|
||||
installMode = best_install_mode();
|
||||
}
|
||||
|
||||
if (installMode == INSTALL_STREAM && use_legacy_install() == true) {
|
||||
if (installMode == INSTALL_STREAM && best_install_mode() == INSTALL_PUSH) {
|
||||
error_exit("Attempting to use streaming install on unsupported device");
|
||||
}
|
||||
|
||||
|
@ -419,7 +441,7 @@ int install_multiple_app(int argc, const char** argv) {
|
|||
if (first_apk == -1) error_exit("need APK file on command line");
|
||||
|
||||
std::string install_cmd;
|
||||
if (use_legacy_install()) {
|
||||
if (best_install_mode() == INSTALL_PUSH) {
|
||||
install_cmd = "exec:pm";
|
||||
} else {
|
||||
install_cmd = "exec:cmd package";
|
||||
|
@ -542,7 +564,7 @@ int install_multi_package(int argc, const char** argv) {
|
|||
|
||||
if (first_package == -1) error_exit("need APK or APEX files on command line");
|
||||
|
||||
if (use_legacy_install()) {
|
||||
if (best_install_mode() == INSTALL_PUSH) {
|
||||
fprintf(stderr, "adb: multi-package install is not supported on this device\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
|
@ -355,7 +355,7 @@ static void stdinout_raw_epilogue(int inFd, int outFd, int old_stdin_mode, int o
|
|||
}
|
||||
|
||||
void copy_to_file(int inFd, int outFd) {
|
||||
std::vector<char> buf(32 * 1024);
|
||||
std::vector<char> buf(64 * 1024);
|
||||
int len;
|
||||
long total = 0;
|
||||
int old_stdin_mode = -1;
|
||||
|
|
|
@ -17,7 +17,11 @@
|
|||
#ifndef COMMANDLINE_H
|
||||
#define COMMANDLINE_H
|
||||
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#include "adb.h"
|
||||
#include "adb_client.h"
|
||||
#include "adb_unique_fd.h"
|
||||
|
||||
// Callback used to handle the standard streams (stdout and stderr) sent by the
|
||||
// device's upon receiving a command.
|
||||
|
@ -105,4 +109,17 @@ int send_shell_command(
|
|||
const std::string& command, bool disable_shell_protocol = false,
|
||||
StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK);
|
||||
|
||||
// Connects to the device "abb" service with |command| and returns the fd.
|
||||
template <typename ContainerT>
|
||||
unique_fd send_abb_exec_command(const ContainerT& command_args, std::string* error) {
|
||||
std::string service_string = "abb_exec:" + android::base::Join(command_args, ABB_ARG_DELIMETER);
|
||||
|
||||
unique_fd fd(adb_connect(service_string, error));
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "adb: failed to run abb_exec. Error: %s\n", error->c_str());
|
||||
return unique_fd{};
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
#endif // COMMANDLINE_H
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "adb_io.h"
|
||||
#include "adb_utils.h"
|
||||
#include "shell_service.h"
|
||||
#include "sysdeps.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -69,6 +70,11 @@ std::vector<std::string_view> parseCmdArgs(std::string_view args) {
|
|||
} // namespace
|
||||
|
||||
static int execCmd(std::string_view args, borrowed_fd in, borrowed_fd out, borrowed_fd err) {
|
||||
int max_buf = LINUX_MAX_SOCKET_SIZE;
|
||||
adb_setsockopt(in, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
|
||||
adb_setsockopt(out, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
|
||||
adb_setsockopt(err, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
|
||||
|
||||
AdbFdTextOutput oin(out);
|
||||
AdbFdTextOutput oerr(err);
|
||||
return cmdMain(parseCmdArgs(args), oin, oerr, in.get(), out.get(), err.get(),
|
||||
|
@ -98,6 +104,8 @@ int main(int argc, char* const argv[]) {
|
|||
}
|
||||
|
||||
unique_fd result = StartCommandInProcess(std::string(name), &execCmd, protocol);
|
||||
int max_buf = LINUX_MAX_SOCKET_SIZE;
|
||||
adb_setsockopt(result, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
|
||||
if (android::base::SendFileDescriptors(fd, "", 1, result.get()) != 1) {
|
||||
PLOG(ERROR) << "Failed to send an inprocess fd for command: " << data;
|
||||
break;
|
||||
|
|
|
@ -53,14 +53,13 @@ unique_fd AbbProcess::sendCommand(std::string_view command) {
|
|||
return error_fd;
|
||||
}
|
||||
|
||||
if (!SendProtocolString(socket_fd_, std::string(command))) {
|
||||
if (!SendProtocolString(socket_fd_, command)) {
|
||||
PLOG(ERROR) << "failed to send command to abb";
|
||||
socket_fd_.reset();
|
||||
continue;
|
||||
}
|
||||
|
||||
unique_fd fd;
|
||||
std::string error;
|
||||
char buf;
|
||||
if (android::base::ReceiveFileDescriptors(socket_fd_, &buf, 1, &fd) != 1) {
|
||||
PLOG(ERROR) << "failed to receive FD from abb";
|
||||
|
|
Loading…
Reference in a new issue