Adding EXEC version of calling ABB.

This is corresponding to exec: command of adb and allows for simplifed calls
to binder without shell protocol.

Bug: 111621042
Test: manual

Change-Id: Id6935cd53e351388ecf6d2d15f3a204cb871536a
diff --git a/adb/adb.h b/adb/adb.h
index 9209997..3a8cb7b 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -153,7 +153,7 @@
 #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 d949dd1..4ffa6bb 100644
--- a/adb/daemon/abb.cpp
+++ b/adb/daemon/abb.cpp
@@ -85,7 +85,19 @@
             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 d32bf52..a435279 100644
--- a/adb/daemon/abb_service.cpp
+++ b/adb/daemon/abb_service.cpp
@@ -86,6 +86,6 @@
 
 }  // 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 d1f0345..362a987 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -244,9 +244,8 @@
 
 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 0794bcd..e9d9c63 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -170,6 +170,8 @@
     // 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 @@
     }
 
     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 @@
     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 @@
     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 @@
     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 @@
     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,
diff --git a/adb/daemon/shell_service.h b/adb/daemon/shell_service.h
index fc66377..3abd958 100644
--- a/adb/daemon/shell_service.h
+++ b/adb/daemon/shell_service.h
@@ -49,7 +49,7 @@
 //
 // 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 0c7b0b6..0b4e084 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -72,6 +72,7 @@
 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 @@
             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.