// Shell service string can look like: // shell[,arg1,arg2,...]:[command] static 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. SubprocessType type(command.empty() ? SubprocessType::kPty : SubprocessType::kRaw); SubprocessProtocol protocol = SubprocessProtocol::kNone; 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 (!arg.empty()) { LOG(ERROR) << "Unsupported shell service arguments: " << args; return -1; } } return StartSubprocess(command.c_str(), type, protocol); }
void ShellServiceTest::StartTestSubprocess( const char* command, SubprocessType type, SubprocessProtocol protocol) { // We want to intercept the shell exit message to make sure it's sent. saved_shell_exit_fd_ = SHELL_EXIT_NOTIFY_FD; int fd[2]; ASSERT_TRUE(adb_socketpair(fd) >= 0); SHELL_EXIT_NOTIFY_FD = fd[0]; shell_exit_receiver_fd_ = fd[1]; subprocess_fd_ = StartSubprocess(command, type, protocol); ASSERT_TRUE(subprocess_fd_ >= 0); }
// Shell service string can look like: // shell[,arg1,arg2,...]:[command] static 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); }
int service_to_fd(const char* name, const atransport* transport) { int ret = -1; if(!strncmp(name, "tcp:", 4)) { int port = atoi(name + 4); name = strchr(name + 4, ':'); if(name == 0) { std::string error; ret = network_loopback_client(port, SOCK_STREAM, &error); if (ret >= 0) disable_tcp_nagle(ret); } else { #if ADB_HOST std::string error; ret = network_connect(name + 1, port, SOCK_STREAM, 0, &error); #else return -1; #endif } #if !defined(_WIN32) /* winsock doesn't implement unix domain sockets */ } else if(!strncmp(name, "local:", 6)) { ret = socket_local_client(name + 6, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); } else if(!strncmp(name, "localreserved:", 14)) { ret = socket_local_client(name + 14, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); } else if(!strncmp(name, "localabstract:", 14)) { ret = socket_local_client(name + 14, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); } else if(!strncmp(name, "localfilesystem:", 16)) { ret = socket_local_client(name + 16, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); #endif #if !ADB_HOST } else if(!strncmp("dev:", name, 4)) { ret = unix_open(name + 4, O_RDWR | O_CLOEXEC); } else if(!strncmp(name, "framebuffer:", 12)) { ret = create_service_thread(framebuffer_service, 0); } else if (!strncmp(name, "jdwp:", 5)) { ret = create_jdwp_connection_fd(atoi(name+5)); } else if(!strncmp(name, "shell", 5)) { ret = ShellService(name + 5, transport); } else if(!strncmp(name, "exec:", 5)) { ret = StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); } else if(!strncmp(name, "sync:", 5)) { ret = create_service_thread(file_sync_service, NULL); } else if(!strncmp(name, "remount:", 8)) { ret = create_service_thread(remount_service, NULL); } else if(!strncmp(name, "reboot:", 7)) { void* arg = strdup(name + 7); if (arg == NULL) return -1; ret = create_service_thread(reboot_service, arg); } else if(!strncmp(name, "root:", 5)) { ret = create_service_thread(restart_root_service, NULL); } else if(!strncmp(name, "unroot:", 7)) { ret = create_service_thread(restart_unroot_service, NULL); } else if(!strncmp(name, "backup:", 7)) { ret = StartSubprocess(android::base::StringPrintf("/system/bin/bu backup %s", (name + 7)).c_str(), nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); } else if(!strncmp(name, "restore:", 8)) { ret = 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 -1; } ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port); } else if(!strncmp(name, "usb:", 4)) { ret = create_service_thread(restart_usb_service, NULL); } else if (!strncmp(name, "reverse:", 8)) { ret = reverse_service(name + 8); } else if(!strncmp(name, "disable-verity:", 15)) { ret = create_service_thread(set_verity_enabled_state_service, (void*)0); } else if(!strncmp(name, "enable-verity:", 15)) { ret = create_service_thread(set_verity_enabled_state_service, (void*)1); #endif } if (ret >= 0) { close_on_exec(ret); } return ret; }
int service_to_fd(const char* name, const atransport* transport) { int ret = -1; if (is_socket_spec(name)) { std::string error; ret = socket_spec_connect(name, &error); if (ret < 0) { LOG(ERROR) << "failed to connect to socket '" << name << "': " << error; } #if !ADB_HOST } else if(!strncmp("dev:", name, 4)) { ret = unix_open(name + 4, O_RDWR | O_CLOEXEC); } else if(!strncmp(name, "framebuffer:", 12)) { ret = create_service_thread(framebuffer_service, 0); } else if (!strncmp(name, "jdwp:", 5)) { ret = create_jdwp_connection_fd(atoi(name+5)); } else if(!strncmp(name, "shell", 5)) { ret = ShellService(name + 5, transport); } else if(!strncmp(name, "exec:", 5)) { ret = StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); } else if(!strncmp(name, "sync:", 5)) { ret = create_service_thread(file_sync_service, NULL); } else if(!strncmp(name, "remount:", 8)) { ret = create_service_thread(remount_service, NULL); } else if(!strncmp(name, "reboot:", 7)) { void* arg = strdup(name + 7); if (arg == NULL) return -1; ret = create_service_thread(reboot_service, arg); } else if(!strncmp(name, "root:", 5)) { ret = create_service_thread(restart_root_service, NULL); } else if(!strncmp(name, "unroot:", 7)) { ret = create_service_thread(restart_unroot_service, NULL); } else if(!strncmp(name, "backup:", 7)) { ret = StartSubprocess(android::base::StringPrintf("/system/bin/bu backup %s", (name + 7)).c_str(), nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); } else if(!strncmp(name, "restore:", 8)) { ret = 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 -1; } ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port); } else if(!strncmp(name, "usb:", 4)) { ret = create_service_thread(restart_usb_service, NULL); } else if (!strncmp(name, "reverse:", 8)) { ret = reverse_service(name + 8); } else if(!strncmp(name, "disable-verity:", 15)) { ret = create_service_thread(set_verity_enabled_state_service, (void*)0); } else if(!strncmp(name, "enable-verity:", 15)) { ret = create_service_thread(set_verity_enabled_state_service, (void*)1); } else if (!strcmp(name, "reconnect")) { ret = create_service_thread(reconnect_service, const_cast<atransport*>(transport)); #endif } if (ret >= 0) { close_on_exec(ret); } return ret; }