Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 05626c18 authored by Alex Buynytskyy's avatar Alex Buynytskyy
Browse files

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
parent ed7458e0
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+13 −1
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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);
}
+2 −3
Original line number Diff line number Diff line
@@ -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

+46 −65
Original line number Diff line number Diff line
@@ -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,44 +385,11 @@ 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";
    if (!ConnectProtocolEndpoints(error)) {
        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");
    return true;
}
@@ -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,10 +416,29 @@ bool Subprocess::ExecInProcess(Command command, std::string* _Nonnull error) {
    D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(),
      stderr_sfd_.get());

    if (!ConnectProtocolEndpoints(error)) {
        return false;
    }

    std::thread([inout_sfd = std::move(child_stdinout_sfd), err_sfd = std::move(child_stderr_sfd),
                 command = std::move(command),
                 args = command_]() { command(args, inout_sfd, inout_sfd, err_sfd); })
            .detach();

    D("execinprocess: completed");
    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));
            *error = android::base::StringPrintf(
                    "failed to create socketpair to intercept data: %s", strerror(errno));
            return false;
        }
        D("protocol FD = %d", protocol_sfd_.get());
@@ -470,19 +457,14 @@ bool Subprocess::ExecInProcess(Command command, std::string* _Nonnull error) {
        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);
                    *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),
                 args = command_]() { command(args, inout_sfd, inout_sfd, err_sfd); })
            .detach();

    D("execinprocess: completed");
    return true;
}

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