Merge "Adding EXEC version of calling ABB."
This commit is contained in:
commit
e257772bb2
7 changed files with 66 additions and 72 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue