Merge "Adding EXEC version of calling ABB."

This commit is contained in:
Treehugger Robot 2019-02-23 15:16:36 +00:00 committed by Gerrit Code Review
commit e257772bb2
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 #endif
#if !ADB_HOST #if !ADB_HOST
unique_fd execute_binder_command(std::string_view command); unique_fd execute_abb_command(std::string_view command);
#endif #endif
#if !ADB_HOST #if !ADB_HOST

View file

@ -85,7 +85,19 @@ int main(int argc, char* const argv[]) {
break; 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) { if (android::base::SendFileDescriptors(fd, "", 1, result.get()) != 1) {
PLOG(ERROR) << "Failed to send an inprocess fd for command: " << data; PLOG(ERROR) << "Failed to send an inprocess fd for command: " << data;
break; break;

View file

@ -86,6 +86,6 @@ unique_fd AbbProcess::startAbbProcess(unique_fd* error_fd) {
} // namespace } // namespace
unique_fd execute_binder_command(std::string_view command) { unique_fd execute_abb_command(std::string_view command) {
return abbp->sendCommand(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) { unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__) #if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
if (name.starts_with("abb:")) { if (name.starts_with("abb:") || name.starts_with("abb_exec:")) {
name.remove_prefix(strlen("abb:")); return execute_abb_command(name);
return execute_binder_command(name);
} }
#endif #endif

View file

@ -170,6 +170,8 @@ class Subprocess {
// Opens the file at |pts_name|. // Opens the file at |pts_name|.
int OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd); int OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd);
bool ConnectProtocolEndpoints(std::string* _Nonnull error);
static void ThreadHandler(void* userdata); static void ThreadHandler(void* userdata);
void PassDataStreams(); void PassDataStreams();
void WaitForExit(); void WaitForExit();
@ -383,42 +385,9 @@ bool Subprocess::ForkAndExec(std::string* error) {
} }
D("subprocess parent: exec completed"); D("subprocess parent: exec completed");
if (protocol_ == SubprocessProtocol::kNone) { if (!ConnectProtocolEndpoints(error)) {
// No protocol: all streams pass through the stdinout FD and hook kill(pid_, SIGKILL);
// directly into the local socket for raw data transfer. return false;
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;
}
}
}
} }
D("subprocess parent: completed"); 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; unique_fd child_stdinout_sfd, child_stderr_sfd;
CHECK(type_ == SubprocessType::kRaw); CHECK(type_ == SubprocessType::kRaw);
CHECK(protocol_ == SubprocessProtocol::kShell);
__android_log_security_bswrite(SEC_TAG_ADB_SHELL_CMD, command_.c_str()); __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(), D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(),
stderr_sfd_.get()); stderr_sfd_.get());
// Required for shell protocol: create another socketpair to intercept data. if (!ConnectProtocolEndpoints(error)) {
if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) {
*error = android::base::StringPrintf("failed to create socketpair to intercept data: %s",
strerror(errno));
return false; 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), std::thread([inout_sfd = std::move(child_stdinout_sfd), err_sfd = std::move(child_stderr_sfd),
command = std::move(command), command = std::move(command),
@ -486,6 +429,45 @@ bool Subprocess::ExecInProcess(Command command, std::string* _Nonnull error) {
return true; 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) { bool Subprocess::StartThread(std::unique_ptr<Subprocess> subprocess, std::string* error) {
Subprocess* raw = subprocess.release(); Subprocess* raw = subprocess.release();
std::thread(ThreadHandler, raw).detach(); std::thread(ThreadHandler, raw).detach();
@ -863,12 +845,11 @@ unique_fd StartSubprocess(std::string name, const char* terminal_type, Subproces
return local_socket; 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()) << ")"; LOG(INFO) << "StartCommandInProcess(" << dump_hex(name.data(), name.size()) << ")";
constexpr auto terminal_type = ""; constexpr auto terminal_type = "";
constexpr auto type = SubprocessType::kRaw; constexpr auto type = SubprocessType::kRaw;
constexpr auto protocol = SubprocessProtocol::kShell;
constexpr auto make_pty_raw = false; constexpr auto make_pty_raw = false;
auto subprocess = std::make_unique<Subprocess>(std::move(name), terminal_type, type, protocol, 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. // 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); 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. // Create a pipe containing the error.
unique_fd ReportError(SubprocessProtocol protocol, const std::string& message); 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 kFeatureFixedPushMkdir = "fixed_push_mkdir";
const char* const kFeatureAbb = "abb"; const char* const kFeatureAbb = "abb";
const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp"; const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp";
const char* const kFeatureAbbExec = "abb_exec";
namespace { namespace {
@ -1013,6 +1014,7 @@ const FeatureSet& supported_features() {
kFeatureApex, kFeatureApex,
kFeatureAbb, kFeatureAbb,
kFeatureFixedPushSymlinkTimestamp, kFeatureFixedPushSymlinkTimestamp,
kFeatureAbbExec,
// Increment ADB_SERVER_VERSION when adding a feature that adbd needs // Increment ADB_SERVER_VERSION when adding a feature that adbd needs
// to know about. Otherwise, the client can be stuck running an old // to know about. Otherwise, the client can be stuck running an old
// version of the server even after upgrading their copy of adb. // version of the server even after upgrading their copy of adb.