diff --git a/adb/Android.bp b/adb/Android.bp index 2a9a57985..07f052fd4 100644 --- a/adb/Android.bp +++ b/adb/Android.bp @@ -292,7 +292,6 @@ cc_library_static { static_libs: [ "libasyncio", - "libbootloader_message", "libcrypto_utils", "libcrypto", "libdiagnose_usb", @@ -318,6 +317,7 @@ cc_binary { "daemon/framebuffer_service.cpp", "daemon/remount_service.cpp", "daemon/set_verity_enable_state_service.cpp", + "daemon/services.cpp", "daemon/shell_service.cpp", "shell_service_protocol.cpp", ], @@ -359,6 +359,7 @@ cc_test { name: "adbd_test", defaults: ["adb_defaults"], srcs: libadb_test_srcs + [ + "daemon/services.cpp", "daemon/shell_service.cpp", "daemon/shell_service_test.cpp", "shell_service_protocol.cpp", @@ -368,6 +369,7 @@ cc_test { static_libs: [ "libadbd", "libbase", + "libbootloader_message", "libcutils", "libcrypto_utils", "libcrypto", diff --git a/adb/adb.h b/adb/adb.h index 26b5fa146..13ca4d7e0 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -143,6 +143,10 @@ atransport* find_emulator_transport_by_console_port(int console_port); #endif int service_to_fd(const char* name, atransport* transport); +#if !ADB_HOST +unique_fd daemon_service_to_fd(const char* name, atransport* transport); +#endif + #if ADB_HOST asocket* host_service_to_socket(const char* name, const char* serial, TransportId transport_id); #endif @@ -151,7 +155,7 @@ asocket* host_service_to_socket(const char* name, const char* serial, TransportI int init_jdwp(void); asocket* create_jdwp_service_socket(); asocket* create_jdwp_tracker_service_socket(); -int create_jdwp_connection_fd(int jdwp_pid); +unique_fd create_jdwp_connection_fd(int jdwp_pid); #endif int handle_forward_request(const char* service, atransport* transport, int reply_fd); diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp index 175e82e8e..b40faee6f 100644 --- a/adb/daemon/jdwp_service.cpp +++ b/adb/daemon/jdwp_service.cpp @@ -311,7 +311,7 @@ CloseProcess: jdwp_process_list_updated(); } -int create_jdwp_connection_fd(int pid) { +unique_fd create_jdwp_connection_fd(int pid) { D("looking for pid %d in JDWP process list", pid); for (auto& proc : _jdwp_list) { @@ -320,7 +320,7 @@ int create_jdwp_connection_fd(int pid) { if (adb_socketpair(fds) < 0) { D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno)); - return -1; + return unique_fd{}; } D("socketpair: (%d,%d)", fds[0], fds[1]); @@ -329,11 +329,11 @@ int create_jdwp_connection_fd(int pid) { fdevent_add(proc->fde, FDE_WRITE); } - return fds[0]; + return unique_fd{fds[0]}; } } D("search failed !!"); - return -1; + return unique_fd{}; } /** VM DEBUG CONTROL SOCKET diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp new file mode 100644 index 000000000..25024b05a --- /dev/null +++ b/adb/daemon/services.cpp @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define TRACE_TAG SERVICES + +#include "sysdeps.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adb.h" +#include "adb_io.h" +#include "adb_unique_fd.h" +#include "adb_utils.h" +#include "services.h" +#include "socket_spec.h" +#include "sysdeps.h" +#include "transport.h" + +#include "daemon/file_sync_service.h" +#include "daemon/framebuffer_service.h" +#include "daemon/remount_service.h" +#include "daemon/set_verity_enable_state_service.h" +#include "daemon/shell_service.h" + +void restart_root_service(unique_fd fd) { + if (getuid() == 0) { + WriteFdExactly(fd.get(), "adbd is already running as root\n"); + return; + } + if (!__android_log_is_debuggable()) { + WriteFdExactly(fd.get(), "adbd cannot run as root in production builds\n"); + return; + } + + android::base::SetProperty("service.adb.root", "1"); + WriteFdExactly(fd.get(), "restarting adbd as root\n"); +} + +void restart_unroot_service(unique_fd fd) { + if (getuid() != 0) { + WriteFdExactly(fd.get(), "adbd not running as root\n"); + return; + } + android::base::SetProperty("service.adb.root", "0"); + WriteFdExactly(fd.get(), "restarting adbd as non root\n"); +} + +void restart_tcp_service(unique_fd fd, int port) { + if (port <= 0) { + WriteFdFmt(fd.get(), "invalid port %d\n", port); + return; + } + + android::base::SetProperty("service.adb.tcp.port", android::base::StringPrintf("%d", port)); + WriteFdFmt(fd.get(), "restarting in TCP mode port: %d\n", port); +} + +void restart_usb_service(unique_fd fd) { + android::base::SetProperty("service.adb.tcp.port", "0"); + WriteFdExactly(fd.get(), "restarting in USB mode\n"); +} + +bool reboot_service_impl(unique_fd fd, const std::string& arg) { + std::string reboot_arg = arg; + bool auto_reboot = false; + + if (reboot_arg == "sideload-auto-reboot") { + auto_reboot = true; + reboot_arg = "sideload"; + } + + // It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot" + // in the command file. + if (reboot_arg == "sideload") { + if (getuid() != 0) { + WriteFdExactly(fd.get(), "'adb root' is required for 'adb reboot sideload'.\n"); + return false; + } + + const std::vector options = {auto_reboot ? "--sideload_auto_reboot" + : "--sideload"}; + std::string err; + if (!write_bootloader_message(options, &err)) { + D("Failed to set bootloader message: %s", err.c_str()); + return false; + } + + reboot_arg = "recovery"; + } + + sync(); + + if (reboot_arg.empty()) reboot_arg = "adb"; + std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str()); + if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) { + WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str()); + return false; + } + + return true; +} + +void reboot_service(unique_fd fd, const std::string& arg) { + if (!reboot_service_impl(std::move(fd), arg)) { + return; + } + // Don't return early. Give the reboot command time to take effect + // to avoid messing up scripts which do "adb reboot && adb wait-for-device" + while (true) { + pause(); + } +} + +void reconnect_service(unique_fd fd, atransport* t) { + WriteFdExactly(fd.get(), "done"); + kick_transport(t); +} + +unique_fd reverse_service(const char* command, atransport* transport) { + int s[2]; + if (adb_socketpair(s)) { + PLOG(ERROR) << "cannot create service socket pair."; + return unique_fd{}; + } + VLOG(SERVICES) << "service socketpair: " << s[0] << ", " << s[1]; + if (handle_forward_request(command, transport, s[1]) < 0) { + SendFail(s[1], "not a reverse forwarding command"); + } + adb_close(s[1]); + return unique_fd{s[0]}; +} + +// Shell service string can look like: +// shell[,arg1,arg2,...]:[command] +unique_fd ShellService(const std::string& args, const atransport* transport) { + size_t delimiter_index = args.find(':'); + if (delimiter_index == std::string::npos) { + LOG(ERROR) << "No ':' found in shell service arguments: " << args; + return unique_fd{}; + } + + const std::string service_args = args.substr(0, delimiter_index); + const std::string command = args.substr(delimiter_index + 1); + + // Defaults: + // PTY for interactive, raw for non-interactive. + // No protocol. + // $TERM set to "dumb". + SubprocessType type(command.empty() ? SubprocessType::kPty : SubprocessType::kRaw); + SubprocessProtocol protocol = SubprocessProtocol::kNone; + std::string terminal_type = "dumb"; + + for (const std::string& arg : android::base::Split(service_args, ",")) { + if (arg == kShellServiceArgRaw) { + type = SubprocessType::kRaw; + } else if (arg == kShellServiceArgPty) { + type = SubprocessType::kPty; + } else if (arg == kShellServiceArgShellProtocol) { + protocol = SubprocessProtocol::kShell; + } else if (android::base::StartsWith(arg, "TERM=")) { + terminal_type = arg.substr(5); + } else if (!arg.empty()) { + // This is not an error to allow for future expansion. + LOG(WARNING) << "Ignoring unknown shell service argument: " << arg; + } + } + + return StartSubprocess(command.c_str(), terminal_type.c_str(), type, protocol); +} + +unique_fd daemon_service_to_fd(const char* name, atransport* transport) { + if (!strncmp("dev:", name, 4)) { + return unique_fd{unix_open(name + 4, O_RDWR | O_CLOEXEC)}; + } else if (!strncmp(name, "framebuffer:", 12)) { + return create_service_thread("fb", framebuffer_service); + } else if (!strncmp(name, "jdwp:", 5)) { + return create_jdwp_connection_fd(atoi(name + 5)); + } else if (!strncmp(name, "shell", 5)) { + return ShellService(name + 5, transport); + } else if (!strncmp(name, "exec:", 5)) { + return StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); + } else if (!strncmp(name, "sync:", 5)) { + return create_service_thread("sync", file_sync_service); + } else if (!strncmp(name, "remount:", 8)) { + std::string options(name + strlen("remount:")); + return create_service_thread("remount", + std::bind(remount_service, std::placeholders::_1, options)); + } else if (!strncmp(name, "reboot:", 7)) { + std::string arg(name + strlen("reboot:")); + return create_service_thread("reboot", + std::bind(reboot_service, std::placeholders::_1, arg)); + } else if (!strncmp(name, "root:", 5)) { + return create_service_thread("root", restart_root_service); + } else if (!strncmp(name, "unroot:", 7)) { + return create_service_thread("unroot", restart_unroot_service); + } else if (!strncmp(name, "backup:", 7)) { + return StartSubprocess( + android::base::StringPrintf("/system/bin/bu backup %s", (name + 7)).c_str(), + nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); + } else if (!strncmp(name, "restore:", 8)) { + return StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw, + SubprocessProtocol::kNone); + } else if (!strncmp(name, "tcpip:", 6)) { + int port; + if (sscanf(name + 6, "%d", &port) != 1) { + return unique_fd{}; + } + return create_service_thread("tcp", + std::bind(restart_tcp_service, std::placeholders::_1, port)); + } else if (!strncmp(name, "usb:", 4)) { + return create_service_thread("usb", restart_usb_service); + } else if (!strncmp(name, "reverse:", 8)) { + return reverse_service(name + 8, transport); + } else if (!strncmp(name, "disable-verity:", 15)) { + return create_service_thread("verity-on", std::bind(set_verity_enabled_state_service, + std::placeholders::_1, false)); + } else if (!strncmp(name, "enable-verity:", 15)) { + return create_service_thread("verity-off", std::bind(set_verity_enabled_state_service, + std::placeholders::_1, true)); + } else if (!strcmp(name, "reconnect")) { + return create_service_thread( + "reconnect", std::bind(reconnect_service, std::placeholders::_1, transport)); + } + return unique_fd{}; +} diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp index b042e5f67..01097ac32 100644 --- a/adb/daemon/shell_service.cpp +++ b/adb/daemon/shell_service.cpp @@ -716,38 +716,37 @@ void Subprocess::WaitForExit() { } // namespace // Create a pipe containing the error. -static int ReportError(SubprocessProtocol protocol, const std::string& message) { - int pipefd[2]; - if (pipe(pipefd) != 0) { - LOG(ERROR) << "failed to create pipe to report error"; - return -1; +static unique_fd ReportError(SubprocessProtocol protocol, const std::string& message) { + unique_fd read, write; + if (!Pipe(&read, &write)) { + PLOG(ERROR) << "failed to create pipe to report error"; + return unique_fd{}; } std::string buf = android::base::StringPrintf("error: %s\n", message.c_str()); if (protocol == SubprocessProtocol::kShell) { ShellProtocol::Id id = ShellProtocol::kIdStderr; uint32_t length = buf.length(); - WriteFdExactly(pipefd[1], &id, sizeof(id)); - WriteFdExactly(pipefd[1], &length, sizeof(length)); + WriteFdExactly(write.get(), &id, sizeof(id)); + WriteFdExactly(write.get(), &length, sizeof(length)); } - WriteFdExactly(pipefd[1], buf.data(), buf.length()); + WriteFdExactly(write.get(), buf.data(), buf.length()); if (protocol == SubprocessProtocol::kShell) { ShellProtocol::Id id = ShellProtocol::kIdExit; uint32_t length = 1; char exit_code = 126; - WriteFdExactly(pipefd[1], &id, sizeof(id)); - WriteFdExactly(pipefd[1], &length, sizeof(length)); - WriteFdExactly(pipefd[1], &exit_code, sizeof(exit_code)); + WriteFdExactly(write.get(), &id, sizeof(id)); + WriteFdExactly(write.get(), &length, sizeof(length)); + WriteFdExactly(write.get(), &exit_code, sizeof(exit_code)); } - adb_close(pipefd[1]); - return pipefd[0]; + return read; } -int StartSubprocess(const char* name, const char* terminal_type, - SubprocessType type, SubprocessProtocol protocol) { +unique_fd StartSubprocess(const char* name, const char* terminal_type, SubprocessType type, + SubprocessProtocol protocol) { D("starting %s subprocess (protocol=%s, TERM=%s): '%s'", type == SubprocessType::kRaw ? "raw" : "PTY", protocol == SubprocessProtocol::kNone ? "none" : "shell", @@ -774,5 +773,5 @@ int StartSubprocess(const char* name, const char* terminal_type, return ReportError(protocol, error); } - return local_socket.release(); + return local_socket; } diff --git a/adb/daemon/shell_service.h b/adb/daemon/shell_service.h index 3ffffa7ac..2a48923dd 100644 --- a/adb/daemon/shell_service.h +++ b/adb/daemon/shell_service.h @@ -16,6 +16,8 @@ #pragma once +#include "adb_unique_fd.h" + enum class SubprocessType { kPty, kRaw, @@ -30,5 +32,5 @@ enum class SubprocessProtocol { // shell is started, otherwise |name| is executed non-interactively. // // Returns an open FD connected to the subprocess or -1 on failure. -int StartSubprocess(const char* name, const char* terminal_type, SubprocessType type, - SubprocessProtocol protocol); +unique_fd StartSubprocess(const char* name, const char* terminal_type, SubprocessType type, + SubprocessProtocol protocol); diff --git a/adb/daemon/shell_service_test.cpp b/adb/daemon/shell_service_test.cpp index d0735373c..323bceced 100644 --- a/adb/daemon/shell_service_test.cpp +++ b/adb/daemon/shell_service_test.cpp @@ -55,7 +55,7 @@ class ShellServiceTest : public ::testing::Test { static sighandler_t saved_sigpipe_handler_; - int subprocess_fd_ = -1; + unique_fd subprocess_fd_; }; sighandler_t ShellServiceTest::saved_sigpipe_handler_ = nullptr; @@ -67,10 +67,6 @@ void ShellServiceTest::StartTestSubprocess( } void ShellServiceTest::CleanupTestSubprocess() { - if (subprocess_fd_ >= 0) { - adb_close(subprocess_fd_); - subprocess_fd_ = -1; - } } namespace { diff --git a/adb/services.cpp b/adb/services.cpp index 639bb463a..4b033bd20 100644 --- a/adb/services.cpp +++ b/adb/services.cpp @@ -24,39 +24,15 @@ #include #include -#ifndef _WIN32 -#include -#include -#include -#include -#endif - #include - -#include -#include #include #include #include -#if !ADB_HOST -#include -#include -#include -#include -#endif - #include "adb.h" #include "adb_io.h" #include "adb_unique_fd.h" #include "adb_utils.h" -#if !ADB_HOST -#include "daemon/file_sync_service.h" -#include "daemon/framebuffer_service.h" -#include "daemon/remount_service.h" -#include "daemon/set_verity_enable_state_service.h" -#include "daemon/shell_service.h" -#endif #include "services.h" #include "socket_spec.h" #include "sysdeps.h" @@ -70,157 +46,7 @@ void service_bootstrap_func(std::string service_name, std::function options = { - auto_reboot ? "--sideload_auto_reboot" : "--sideload" - }; - std::string err; - if (!write_bootloader_message(options, &err)) { - D("Failed to set bootloader message: %s", err.c_str()); - return false; - } - - reboot_arg = "recovery"; - } - - sync(); - - if (reboot_arg.empty()) reboot_arg = "adb"; - std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str()); - if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) { - WriteFdFmt(fd, "reboot (%s) failed\n", reboot_string.c_str()); - return false; - } - - return true; -} - -void reboot_service(unique_fd fd, const std::string& arg) { - if (!reboot_service_impl(std::move(fd), arg)) { - return; - } - // Don't return early. Give the reboot command time to take effect - // to avoid messing up scripts which do "adb reboot && adb wait-for-device" - while (true) { - pause(); - } -} - -void reconnect_service(unique_fd fd, atransport* t) { - WriteFdExactly(fd, "done"); - kick_transport(t); -} - -int reverse_service(const char* command, atransport* transport) { - int s[2]; - if (adb_socketpair(s)) { - PLOG(ERROR) << "cannot create service socket pair."; - return -1; - } - VLOG(SERVICES) << "service socketpair: " << s[0] << ", " << s[1]; - if (handle_forward_request(command, transport, s[1]) < 0) { - SendFail(s[1], "not a reverse forwarding command"); - } - adb_close(s[1]); - return s[0]; -} - -// Shell service string can look like: -// shell[,arg1,arg2,...]:[command] -int ShellService(const std::string& args, const atransport* transport) { - size_t delimiter_index = args.find(':'); - if (delimiter_index == std::string::npos) { - LOG(ERROR) << "No ':' found in shell service arguments: " << args; - return -1; - } - - const std::string service_args = args.substr(0, delimiter_index); - const std::string command = args.substr(delimiter_index + 1); - - // Defaults: - // PTY for interactive, raw for non-interactive. - // No protocol. - // $TERM set to "dumb". - SubprocessType type(command.empty() ? SubprocessType::kPty - : SubprocessType::kRaw); - SubprocessProtocol protocol = SubprocessProtocol::kNone; - std::string terminal_type = "dumb"; - - for (const std::string& arg : android::base::Split(service_args, ",")) { - if (arg == kShellServiceArgRaw) { - type = SubprocessType::kRaw; - } else if (arg == kShellServiceArgPty) { - type = SubprocessType::kPty; - } else if (arg == kShellServiceArgShellProtocol) { - protocol = SubprocessProtocol::kShell; - } else if (android::base::StartsWith(arg, "TERM=")) { - terminal_type = arg.substr(5); - } else if (!arg.empty()) { - // This is not an error to allow for future expansion. - LOG(WARNING) << "Ignoring unknown shell service argument: " << arg; - } - } - - return StartSubprocess(command.c_str(), terminal_type.c_str(), type, protocol); -} - -#endif // !ADB_HOST +} // namespace unique_fd create_service_thread(const char* service_name, std::function func) { int s[2]; @@ -245,8 +71,6 @@ unique_fd create_service_thread(const char* service_name, std::function= 0) { close_on_exec(ret); } diff --git a/adb/services.h b/adb/services.h index 0428ca4ae..0ce25ba73 100644 --- a/adb/services.h +++ b/adb/services.h @@ -17,8 +17,11 @@ #ifndef SERVICES_H_ #define SERVICES_H_ +#include "adb_unique_fd.h" + constexpr char kShellServiceArgRaw[] = "raw"; constexpr char kShellServiceArgPty[] = "pty"; constexpr char kShellServiceArgShellProtocol[] = "v2"; +unique_fd create_service_thread(const char* service_name, std::function func); #endif // SERVICES_H_