[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:
Yurii Zubrytskyi 2019-06-27 13:47:34 -07:00 committed by Songchun Fan
parent f7970cee69
commit 6eca0e6999
5 changed files with 75 additions and 29 deletions

View file

@ -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;
}

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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";