diff --git a/adb/adb.h b/adb/adb.h index 920999705..3a8cb7b1c 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -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 diff --git a/adb/daemon/abb.cpp b/adb/daemon/abb.cpp index d949dd118..4ffa6bb85 100644 --- a/adb/daemon/abb.cpp +++ b/adb/daemon/abb.cpp @@ -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; diff --git a/adb/daemon/abb_service.cpp b/adb/daemon/abb_service.cpp index d32bf52fb..a43527982 100644 --- a/adb/daemon/abb_service.cpp +++ b/adb/daemon/abb_service.cpp @@ -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); } diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp index d1f034507..362a987e0 100644 --- a/adb/daemon/services.cpp +++ b/adb/daemon/services.cpp @@ -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 diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp index 0794bcdae..e9d9c63fc 100644 --- a/adb/daemon/shell_service.cpp +++ b/adb/daemon/shell_service.cpp @@ -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(protocol_sfd_); - output_ = std::make_unique(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(protocol_sfd_); - output_ = std::make_unique(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(protocol_sfd_); + output_ = std::make_unique(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, 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(std::move(name), terminal_type, type, protocol, diff --git a/adb/daemon/shell_service.h b/adb/daemon/shell_service.h index fc6637790..3abd95807 100644 --- a/adb/daemon/shell_service.h +++ b/adb/daemon/shell_service.h @@ -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); diff --git a/adb/transport.cpp b/adb/transport.cpp index 0c7b0b69b..0b4e08431 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp @@ -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.