Merge "Adding EXEC version of calling ABB."

am: e257772bb2

Change-Id: I2ab1da67fe0b2030d55bf1129aa6e7dd22b85f9a
This commit is contained in:
Alex Buynytskyy 2019-02-23 07:22:06 -08:00 committed by android-build-merger
commit b590a59bc4
7 changed files with 66 additions and 72 deletions

View file

@ -153,7 +153,7 @@ asocket* daemon_service_to_socket(std::string_view name);
#endif
#if !ADB_HOST
unique_fd execute_binder_command(std::string_view command);
unique_fd execute_abb_command(std::string_view command);
#endif
#if !ADB_HOST

View file

@ -85,7 +85,19 @@ int main(int argc, char* const argv[]) {
break;
}
unique_fd result = StartCommandInProcess(std::move(data), &execCmd);
std::string_view name = data;
auto protocol = SubprocessProtocol::kShell;
if (name.starts_with("abb:")) {
name.remove_prefix(strlen("abb:"));
protocol = SubprocessProtocol::kShell;
} else if (name.starts_with("abb_exec:")) {
name.remove_prefix(strlen("abb_exec:"));
protocol = SubprocessProtocol::kNone;
} else {
LOG(FATAL) << "Unknown command prefix for abb: " << data;
}
unique_fd result = StartCommandInProcess(std::string(name), &execCmd, protocol);
if (android::base::SendFileDescriptors(fd, "", 1, result.get()) != 1) {
PLOG(ERROR) << "Failed to send an inprocess fd for command: " << data;
break;

View file

@ -86,6 +86,6 @@ unique_fd AbbProcess::startAbbProcess(unique_fd* error_fd) {
} // namespace
unique_fd execute_binder_command(std::string_view command) {
unique_fd execute_abb_command(std::string_view command) {
return abbp->sendCommand(command);
}

View file

@ -244,9 +244,8 @@ asocket* daemon_service_to_socket(std::string_view name) {
unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
if (name.starts_with("abb:")) {
name.remove_prefix(strlen("abb:"));
return execute_binder_command(name);
if (name.starts_with("abb:") || name.starts_with("abb_exec:")) {
return execute_abb_command(name);
}
#endif

View file

@ -170,6 +170,8 @@ class Subprocess {
// Opens the file at |pts_name|.
int OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd);
bool ConnectProtocolEndpoints(std::string* _Nonnull error);
static void ThreadHandler(void* userdata);
void PassDataStreams();
void WaitForExit();
@ -383,42 +385,9 @@ bool Subprocess::ForkAndExec(std::string* error) {
}
D("subprocess parent: exec completed");
if (protocol_ == SubprocessProtocol::kNone) {
// No protocol: all streams pass through the stdinout FD and hook
// directly into the local socket for raw data transfer.
local_socket_sfd_.reset(stdinout_sfd_.release());
} else {
// Shell protocol: create another socketpair to intercept data.
if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) {
*error = android::base::StringPrintf(
"failed to create socketpair to intercept data: %s", strerror(errno));
kill(pid_, SIGKILL);
return false;
}
D("protocol FD = %d", protocol_sfd_.get());
input_ = std::make_unique<ShellProtocol>(protocol_sfd_);
output_ = std::make_unique<ShellProtocol>(protocol_sfd_);
if (!input_ || !output_) {
*error = "failed to allocate shell protocol objects";
kill(pid_, SIGKILL);
return false;
}
// Don't let reads/writes to the subprocess block our thread. This isn't
// likely but could happen under unusual circumstances, such as if we
// write a ton of data to stdin but the subprocess never reads it and
// the pipe fills up.
for (int fd : {stdinout_sfd_.get(), stderr_sfd_.get()}) {
if (fd >= 0) {
if (!set_file_block_mode(fd, false)) {
*error = android::base::StringPrintf(
"failed to set non-blocking mode for fd %d", fd);
kill(pid_, SIGKILL);
return false;
}
}
}
if (!ConnectProtocolEndpoints(error)) {
kill(pid_, SIGKILL);
return false;
}
D("subprocess parent: completed");
@ -429,7 +398,6 @@ bool Subprocess::ExecInProcess(Command command, std::string* _Nonnull error) {
unique_fd child_stdinout_sfd, child_stderr_sfd;
CHECK(type_ == SubprocessType::kRaw);
CHECK(protocol_ == SubprocessProtocol::kShell);
__android_log_security_bswrite(SEC_TAG_ADB_SHELL_CMD, command_.c_str());
@ -448,34 +416,9 @@ bool Subprocess::ExecInProcess(Command command, std::string* _Nonnull error) {
D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(),
stderr_sfd_.get());
// Required for shell protocol: create another socketpair to intercept data.
if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) {
*error = android::base::StringPrintf("failed to create socketpair to intercept data: %s",
strerror(errno));
if (!ConnectProtocolEndpoints(error)) {
return false;
}
D("protocol FD = %d", protocol_sfd_.get());
input_ = std::make_unique<ShellProtocol>(protocol_sfd_);
output_ = std::make_unique<ShellProtocol>(protocol_sfd_);
if (!input_ || !output_) {
*error = "failed to allocate shell protocol objects";
return false;
}
// Don't let reads/writes to the subprocess block our thread. This isn't
// likely but could happen under unusual circumstances, such as if we
// write a ton of data to stdin but the subprocess never reads it and
// the pipe fills up.
for (int fd : {stdinout_sfd_.get(), stderr_sfd_.get()}) {
if (fd >= 0) {
if (!set_file_block_mode(fd, false)) {
*error = android::base::StringPrintf("failed to set non-blocking mode for fd %d",
fd);
return false;
}
}
}
std::thread([inout_sfd = std::move(child_stdinout_sfd), err_sfd = std::move(child_stderr_sfd),
command = std::move(command),
@ -486,6 +429,45 @@ bool Subprocess::ExecInProcess(Command command, std::string* _Nonnull error) {
return true;
}
bool Subprocess::ConnectProtocolEndpoints(std::string* _Nonnull error) {
if (protocol_ == SubprocessProtocol::kNone) {
// No protocol: all streams pass through the stdinout FD and hook
// directly into the local socket for raw data transfer.
local_socket_sfd_.reset(stdinout_sfd_.release());
} else {
// Required for shell protocol: create another socketpair to intercept data.
if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) {
*error = android::base::StringPrintf(
"failed to create socketpair to intercept data: %s", strerror(errno));
return false;
}
D("protocol FD = %d", protocol_sfd_.get());
input_ = std::make_unique<ShellProtocol>(protocol_sfd_);
output_ = std::make_unique<ShellProtocol>(protocol_sfd_);
if (!input_ || !output_) {
*error = "failed to allocate shell protocol objects";
return false;
}
// Don't let reads/writes to the subprocess block our thread. This isn't
// likely but could happen under unusual circumstances, such as if we
// write a ton of data to stdin but the subprocess never reads it and
// the pipe fills up.
for (int fd : {stdinout_sfd_.get(), stderr_sfd_.get()}) {
if (fd >= 0) {
if (!set_file_block_mode(fd, false)) {
*error = android::base::StringPrintf(
"failed to set non-blocking mode for fd %d", fd);
return false;
}
}
}
}
return true;
}
bool Subprocess::StartThread(std::unique_ptr<Subprocess> subprocess, std::string* error) {
Subprocess* raw = subprocess.release();
std::thread(ThreadHandler, raw).detach();
@ -863,12 +845,11 @@ unique_fd StartSubprocess(std::string name, const char* terminal_type, Subproces
return local_socket;
}
unique_fd StartCommandInProcess(std::string name, Command command) {
unique_fd StartCommandInProcess(std::string name, Command command, SubprocessProtocol protocol) {
LOG(INFO) << "StartCommandInProcess(" << dump_hex(name.data(), name.size()) << ")";
constexpr auto terminal_type = "";
constexpr auto type = SubprocessType::kRaw;
constexpr auto protocol = SubprocessProtocol::kShell;
constexpr auto make_pty_raw = false;
auto subprocess = std::make_unique<Subprocess>(std::move(name), terminal_type, type, protocol,

View file

@ -49,7 +49,7 @@ unique_fd StartSubprocess(std::string name, const char* terminal_type, Subproces
//
// Returns an open FD connected to the thread or -1 on failure.
using Command = int(std::string_view args, int in, int out, int err);
unique_fd StartCommandInProcess(std::string name, Command command);
unique_fd StartCommandInProcess(std::string name, Command command, SubprocessProtocol protocol);
// Create a pipe containing the error.
unique_fd ReportError(SubprocessProtocol protocol, const std::string& message);

View file

@ -72,6 +72,7 @@ const char* const kFeatureApex = "apex";
const char* const kFeatureFixedPushMkdir = "fixed_push_mkdir";
const char* const kFeatureAbb = "abb";
const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp";
const char* const kFeatureAbbExec = "abb_exec";
namespace {
@ -1013,6 +1014,7 @@ const FeatureSet& supported_features() {
kFeatureApex,
kFeatureAbb,
kFeatureFixedPushSymlinkTimestamp,
kFeatureAbbExec,
// Increment ADB_SERVER_VERSION when adding a feature that adbd needs
// to know about. Otherwise, the client can be stuck running an old
// version of the server even after upgrading their copy of adb.