2009-03-04 04:32:55 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007 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.
|
|
|
|
*/
|
|
|
|
|
2015-09-23 00:52:57 +02:00
|
|
|
#define TRACE_TAG SERVICES
|
2015-03-19 23:21:08 +01:00
|
|
|
|
|
|
|
#include "sysdeps.h"
|
|
|
|
|
2015-02-25 00:51:19 +01:00
|
|
|
#include <errno.h>
|
2013-03-30 02:22:36 +01:00
|
|
|
#include <stddef.h>
|
2009-03-04 04:32:55 +01:00
|
|
|
#include <stdio.h>
|
2015-02-25 00:51:19 +01:00
|
|
|
#include <stdlib.h>
|
2009-03-04 04:32:55 +01:00
|
|
|
#include <string.h>
|
2015-02-25 00:51:19 +01:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2017-04-13 02:00:49 +02:00
|
|
|
#include <thread>
|
|
|
|
|
2015-12-05 07:00:26 +01:00
|
|
|
#include <android-base/file.h>
|
2016-01-21 17:40:59 +01:00
|
|
|
#include <android-base/parsenetaddress.h>
|
2015-12-05 07:00:26 +01:00
|
|
|
#include <android-base/stringprintf.h>
|
|
|
|
#include <android-base/strings.h>
|
2018-07-19 04:40:12 +02:00
|
|
|
#include <android-base/unique_fd.h>
|
2015-07-24 02:12:58 +02:00
|
|
|
#include <cutils/sockets.h>
|
2015-04-18 05:11:08 +02:00
|
|
|
|
2015-02-25 00:51:19 +01:00
|
|
|
#if !ADB_HOST
|
2016-09-24 00:40:03 +02:00
|
|
|
#include <android-base/properties.h>
|
2017-01-06 03:01:01 +01:00
|
|
|
#include <bootloader_message/bootloader_message.h>
|
2016-03-29 00:52:13 +02:00
|
|
|
#include <cutils/android_reboot.h>
|
2017-04-14 08:48:57 +02:00
|
|
|
#include <log/log_properties.h>
|
2015-02-25 00:51:19 +01:00
|
|
|
#endif
|
2009-03-04 04:32:55 +01:00
|
|
|
|
|
|
|
#include "adb.h"
|
2015-02-25 06:26:58 +01:00
|
|
|
#include "adb_io.h"
|
2015-07-18 21:21:30 +02:00
|
|
|
#include "adb_utils.h"
|
2018-07-19 04:40:12 +02:00
|
|
|
#if !ADB_HOST
|
|
|
|
#include "daemon/framebuffer_service.h"
|
|
|
|
#include "daemon/set_verity_enable_state_service.h"
|
|
|
|
#endif
|
2009-03-04 04:32:55 +01:00
|
|
|
#include "file_sync_service.h"
|
2015-03-16 22:58:32 +01:00
|
|
|
#include "remount_service.h"
|
2015-09-30 22:35:42 +02:00
|
|
|
#include "services.h"
|
2015-08-29 00:08:49 +02:00
|
|
|
#include "shell_service.h"
|
2016-08-25 03:38:44 +02:00
|
|
|
#include "socket_spec.h"
|
2016-02-19 19:42:40 +01:00
|
|
|
#include "sysdeps.h"
|
2015-02-25 00:51:19 +01:00
|
|
|
#include "transport.h"
|
2009-03-04 04:32:55 +01:00
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
namespace {
|
2009-03-04 04:32:55 +01:00
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
void service_bootstrap_func(std::string service_name,
|
|
|
|
std::function<void(android::base::unique_fd)> func,
|
|
|
|
android::base::unique_fd fd) {
|
|
|
|
adb_thread_setname(android::base::StringPrintf("%s svc %d", service_name.c_str(), fd.get()));
|
|
|
|
func(std::move(fd));
|
2009-03-04 04:32:55 +01:00
|
|
|
}
|
|
|
|
|
2013-02-21 00:04:53 +01:00
|
|
|
#if !ADB_HOST
|
2009-03-04 04:32:55 +01:00
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
void restart_root_service(android::base::unique_fd fd) {
|
2009-03-13 21:04:37 +01:00
|
|
|
if (getuid() == 0) {
|
2018-07-19 04:40:12 +02:00
|
|
|
WriteFdExactly(fd.get(), "adbd is already running as root\n");
|
|
|
|
return;
|
2009-03-13 21:04:37 +01:00
|
|
|
}
|
2018-07-19 04:40:12 +02:00
|
|
|
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");
|
2009-03-13 21:04:37 +01:00
|
|
|
}
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
void restart_unroot_service(android::base::unique_fd fd) {
|
2014-10-06 19:57:20 +02:00
|
|
|
if (getuid() != 0) {
|
2018-07-19 04:40:12 +02:00
|
|
|
WriteFdExactly(fd.get(), "adbd not running as root\n");
|
|
|
|
return;
|
2014-10-06 19:57:20 +02:00
|
|
|
}
|
2018-07-19 04:40:12 +02:00
|
|
|
android::base::SetProperty("service.adb.root", "0");
|
|
|
|
WriteFdExactly(fd.get(), "restarting adbd as non root\n");
|
2014-10-06 19:57:20 +02:00
|
|
|
}
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
void restart_tcp_service(android::base::unique_fd fd, int port) {
|
2009-08-25 00:58:40 +02:00
|
|
|
if (port <= 0) {
|
2018-07-19 04:40:12 +02:00
|
|
|
WriteFdFmt(fd.get(), "invalid port %d\n", port);
|
2009-08-25 00:58:40 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-24 00:40:03 +02:00
|
|
|
android::base::SetProperty("service.adb.tcp.port", android::base::StringPrintf("%d", port));
|
2018-07-19 04:40:12 +02:00
|
|
|
WriteFdFmt(fd.get(), "restarting in TCP mode port: %d\n", port);
|
2009-08-25 00:58:40 +02:00
|
|
|
}
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
void restart_usb_service(android::base::unique_fd fd) {
|
2016-09-24 00:40:03 +02:00
|
|
|
android::base::SetProperty("service.adb.tcp.port", "0");
|
2018-07-19 04:40:12 +02:00
|
|
|
WriteFdExactly(fd.get(), "restarting in USB mode\n");
|
2009-08-25 00:58:40 +02:00
|
|
|
}
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
bool reboot_service_impl(android::base::unique_fd fd, const std::string& arg) {
|
|
|
|
std::string reboot_arg = arg;
|
2015-03-29 20:22:34 +02:00
|
|
|
bool auto_reboot = false;
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
if (reboot_arg == "sideload-auto-reboot") {
|
2015-03-29 20:22:34 +02:00
|
|
|
auto_reboot = true;
|
|
|
|
reboot_arg = "sideload";
|
|
|
|
}
|
|
|
|
|
|
|
|
// It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot"
|
|
|
|
// in the command file.
|
2018-07-19 04:40:12 +02:00
|
|
|
if (reboot_arg == "sideload") {
|
2015-03-29 20:22:34 +02:00
|
|
|
if (getuid() != 0) {
|
2015-05-01 02:32:03 +02:00
|
|
|
WriteFdExactly(fd, "'adb root' is required for 'adb reboot sideload'.\n");
|
2015-03-29 20:22:34 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-01-06 03:01:01 +01:00
|
|
|
const std::vector<std::string> 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());
|
2015-03-29 20:22:34 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
reboot_arg = "recovery";
|
|
|
|
}
|
2009-08-05 02:37:51 +02:00
|
|
|
|
|
|
|
sync();
|
2010-02-24 22:07:23 +01:00
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
if (reboot_arg.empty()) reboot_arg = "adb";
|
|
|
|
std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
|
2016-09-24 00:40:03 +02:00
|
|
|
if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
|
|
|
|
WriteFdFmt(fd, "reboot (%s) failed\n", reboot_string.c_str());
|
2015-03-29 20:22:34 +02:00
|
|
|
return false;
|
2009-08-05 02:37:51 +02:00
|
|
|
}
|
2015-03-29 20:22:34 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
void reboot_service(android::base::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();
|
2015-03-29 20:22:34 +02:00
|
|
|
}
|
2009-08-05 02:37:51 +02:00
|
|
|
}
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
void reconnect_service(android::base::unique_fd fd, atransport* t) {
|
2016-04-05 22:50:44 +02:00
|
|
|
WriteFdExactly(fd, "done");
|
|
|
|
kick_transport(t);
|
|
|
|
}
|
|
|
|
|
2018-04-13 21:17:03 +02:00
|
|
|
int reverse_service(const char* command, atransport* transport) {
|
2015-10-31 02:37:26 +01:00
|
|
|
int s[2];
|
|
|
|
if (adb_socketpair(s)) {
|
|
|
|
PLOG(ERROR) << "cannot create service socket pair.";
|
|
|
|
return -1;
|
2013-03-21 21:07:42 +01:00
|
|
|
}
|
2015-10-31 02:37:26 +01:00
|
|
|
VLOG(SERVICES) << "service socketpair: " << s[0] << ", " << s[1];
|
2018-04-13 21:17:03 +02:00
|
|
|
if (handle_forward_request(command, transport, s[1]) < 0) {
|
2015-10-31 02:37:26 +01:00
|
|
|
SendFail(s[1], "not a reverse forwarding command");
|
|
|
|
}
|
|
|
|
adb_close(s[1]);
|
|
|
|
return s[0];
|
2013-03-21 21:07:42 +01:00
|
|
|
}
|
|
|
|
|
2015-09-22 19:43:08 +02:00
|
|
|
// Shell service string can look like:
|
2015-09-30 22:35:42 +02:00
|
|
|
// shell[,arg1,arg2,...]:[command]
|
2018-07-19 04:40:12 +02:00
|
|
|
int ShellService(const std::string& args, const atransport* transport) {
|
2015-09-22 19:43:08 +02:00
|
|
|
size_t delimiter_index = args.find(':');
|
|
|
|
if (delimiter_index == std::string::npos) {
|
|
|
|
LOG(ERROR) << "No ':' found in shell service arguments: " << args;
|
|
|
|
return -1;
|
|
|
|
}
|
2015-09-30 22:35:42 +02:00
|
|
|
|
2015-09-22 19:43:08 +02:00
|
|
|
const std::string service_args = args.substr(0, delimiter_index);
|
|
|
|
const std::string command = args.substr(delimiter_index + 1);
|
|
|
|
|
2015-09-30 22:35:42 +02:00
|
|
|
// Defaults:
|
|
|
|
// PTY for interactive, raw for non-interactive.
|
|
|
|
// No protocol.
|
2015-11-16 19:55:34 +01:00
|
|
|
// $TERM set to "dumb".
|
2015-09-30 22:35:42 +02:00
|
|
|
SubprocessType type(command.empty() ? SubprocessType::kPty
|
|
|
|
: SubprocessType::kRaw);
|
|
|
|
SubprocessProtocol protocol = SubprocessProtocol::kNone;
|
2015-11-16 19:55:34 +01:00
|
|
|
std::string terminal_type = "dumb";
|
2015-09-30 22:35:42 +02:00
|
|
|
|
|
|
|
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;
|
2015-11-16 19:55:34 +01:00
|
|
|
} 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;
|
2015-09-30 22:35:42 +02:00
|
|
|
}
|
2015-09-22 19:43:08 +02:00
|
|
|
}
|
|
|
|
|
2015-11-16 19:55:34 +01:00
|
|
|
return StartSubprocess(command.c_str(), terminal_type.c_str(), type, protocol);
|
2015-09-22 19:43:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif // !ADB_HOST
|
2009-03-04 04:32:55 +01:00
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
android::base::unique_fd create_service_thread(const char* service_name,
|
|
|
|
std::function<void(android::base::unique_fd)> func) {
|
2009-03-04 04:32:55 +01:00
|
|
|
int s[2];
|
2015-02-26 02:51:28 +01:00
|
|
|
if (adb_socketpair(s)) {
|
2009-03-04 04:32:55 +01:00
|
|
|
printf("cannot create service socket pair\n");
|
2018-07-19 04:40:12 +02:00
|
|
|
return android::base::unique_fd();
|
2009-03-04 04:32:55 +01:00
|
|
|
}
|
2015-09-03 02:44:28 +02:00
|
|
|
D("socketpair: (%d,%d)", s[0], s[1]);
|
2009-03-04 04:32:55 +01:00
|
|
|
|
2017-02-11 02:45:27 +01:00
|
|
|
#if !ADB_HOST
|
2018-07-19 04:40:12 +02:00
|
|
|
if (strcmp(service_name, "sync") == 0) {
|
2017-02-11 02:45:27 +01:00
|
|
|
// Set file sync service socket to maximum size
|
|
|
|
int max_buf = LINUX_MAX_SOCKET_SIZE;
|
|
|
|
adb_setsockopt(s[0], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
|
|
|
|
adb_setsockopt(s[1], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
|
|
|
|
}
|
|
|
|
#endif // !ADB_HOST
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
std::thread(service_bootstrap_func, service_name, func, android::base::unique_fd(s[1])).detach();
|
2009-03-04 04:32:55 +01:00
|
|
|
|
2015-09-03 02:44:28 +02:00
|
|
|
D("service thread started, %d:%d",s[0], s[1]);
|
2018-07-19 04:40:12 +02:00
|
|
|
return android::base::unique_fd(s[0]);
|
2009-03-04 04:32:55 +01:00
|
|
|
}
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
} // namespace
|
|
|
|
|
2018-04-13 21:17:03 +02:00
|
|
|
int service_to_fd(const char* name, atransport* transport) {
|
2009-03-04 04:32:55 +01:00
|
|
|
int ret = -1;
|
|
|
|
|
2016-08-25 03:38:44 +02:00
|
|
|
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;
|
2009-03-04 04:32:55 +01:00
|
|
|
}
|
2013-02-21 00:04:53 +01:00
|
|
|
#if !ADB_HOST
|
2009-03-04 04:32:55 +01:00
|
|
|
} else if(!strncmp("dev:", name, 4)) {
|
2014-07-19 05:57:35 +02:00
|
|
|
ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
|
2018-07-19 04:40:12 +02:00
|
|
|
} else if (!strncmp(name, "framebuffer:", 12)) {
|
|
|
|
ret = create_service_thread("fb", framebuffer_service).release();
|
2009-03-04 04:32:55 +01:00
|
|
|
} else if (!strncmp(name, "jdwp:", 5)) {
|
2018-07-19 04:40:12 +02:00
|
|
|
ret = create_jdwp_connection_fd(atoi(name + 5));
|
|
|
|
} else if (!strncmp(name, "shell", 5)) {
|
2015-09-22 19:43:08 +02:00
|
|
|
ret = ShellService(name + 5, transport);
|
2018-07-19 04:40:12 +02:00
|
|
|
} else if (!strncmp(name, "exec:", 5)) {
|
2015-11-16 19:55:34 +01:00
|
|
|
ret = StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
|
2018-07-19 04:40:12 +02:00
|
|
|
} else if (!strncmp(name, "sync:", 5)) {
|
|
|
|
ret = create_service_thread("sync", file_sync_service).release();
|
|
|
|
} else if (!strncmp(name, "remount:", 8)) {
|
|
|
|
std::string options(name + strlen("remount:"));
|
|
|
|
ret = create_service_thread("remount",
|
|
|
|
std::bind(remount_service, std::placeholders::_1, options))
|
|
|
|
.release();
|
|
|
|
} else if (!strncmp(name, "reboot:", 7)) {
|
|
|
|
std::string arg(name + strlen("reboot:"));
|
|
|
|
ret = create_service_thread("reboot", std::bind(reboot_service, std::placeholders::_1, arg))
|
|
|
|
.release();
|
|
|
|
} else if (!strncmp(name, "root:", 5)) {
|
|
|
|
ret = create_service_thread("root", restart_root_service).release();
|
|
|
|
} else if (!strncmp(name, "unroot:", 7)) {
|
|
|
|
ret = create_service_thread("unroot", restart_unroot_service).release();
|
|
|
|
} 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)) {
|
2015-11-16 19:55:34 +01:00
|
|
|
ret = StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw,
|
2015-08-31 19:42:13 +02:00
|
|
|
SubprocessProtocol::kNone);
|
2018-07-19 04:40:12 +02:00
|
|
|
} else if (!strncmp(name, "tcpip:", 6)) {
|
2009-08-25 00:58:40 +02:00
|
|
|
int port;
|
2015-01-26 02:38:36 +01:00
|
|
|
if (sscanf(name + 6, "%d", &port) != 1) {
|
2015-07-22 01:13:40 +02:00
|
|
|
return -1;
|
2009-08-25 00:58:40 +02:00
|
|
|
}
|
2018-07-19 04:40:12 +02:00
|
|
|
ret = create_service_thread("tcp",
|
|
|
|
std::bind(restart_tcp_service, std::placeholders::_1, port))
|
|
|
|
.release();
|
|
|
|
} else if (!strncmp(name, "usb:", 4)) {
|
|
|
|
ret = create_service_thread("usb", restart_usb_service).release();
|
2013-03-21 21:07:42 +01:00
|
|
|
} else if (!strncmp(name, "reverse:", 8)) {
|
2018-04-13 21:17:03 +02:00
|
|
|
ret = reverse_service(name + 8, transport);
|
2018-07-19 04:40:12 +02:00
|
|
|
} else if (!strncmp(name, "disable-verity:", 15)) {
|
|
|
|
ret = create_service_thread("verity-on", std::bind(set_verity_enabled_state_service,
|
|
|
|
std::placeholders::_1, false))
|
|
|
|
.release();
|
|
|
|
} else if (!strncmp(name, "enable-verity:", 15)) {
|
|
|
|
ret = create_service_thread("verity-off", std::bind(set_verity_enabled_state_service,
|
|
|
|
std::placeholders::_1, true))
|
|
|
|
.release();
|
2016-04-05 22:50:44 +02:00
|
|
|
} else if (!strcmp(name, "reconnect")) {
|
2018-07-19 04:40:12 +02:00
|
|
|
ret = create_service_thread("reconnect",
|
|
|
|
std::bind(reconnect_service, std::placeholders::_1, transport))
|
|
|
|
.release();
|
2009-03-04 04:32:55 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if (ret >= 0) {
|
|
|
|
close_on_exec(ret);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if ADB_HOST
|
|
|
|
struct state_info {
|
2015-05-05 22:10:43 +02:00
|
|
|
TransportType transport_type;
|
2015-11-27 18:56:48 +01:00
|
|
|
std::string serial;
|
2017-08-17 01:57:01 +02:00
|
|
|
TransportId transport_id;
|
2015-05-19 01:43:57 +02:00
|
|
|
ConnectionState state;
|
2009-03-04 04:32:55 +01:00
|
|
|
};
|
|
|
|
|
2015-11-27 18:56:48 +01:00
|
|
|
static void wait_for_state(int fd, void* data) {
|
|
|
|
std::unique_ptr<state_info> sinfo(reinterpret_cast<state_info*>(data));
|
2009-03-04 04:32:55 +01:00
|
|
|
|
2015-09-03 02:44:28 +02:00
|
|
|
D("wait_for_state %d", sinfo->state);
|
2009-03-04 04:32:55 +01:00
|
|
|
|
2015-10-07 23:55:10 +02:00
|
|
|
while (true) {
|
|
|
|
bool is_ambiguous = false;
|
|
|
|
std::string error = "unknown error";
|
2018-07-14 03:15:16 +02:00
|
|
|
const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : nullptr;
|
2017-08-17 01:57:01 +02:00
|
|
|
atransport* t = acquire_one_transport(sinfo->transport_type, serial, sinfo->transport_id,
|
|
|
|
&is_ambiguous, &error);
|
adb: fix two device offline problems.
When device goes offline, user usually has to manually replug the
usb device. This patch tries to solve two offline situations, all
because when adb on host is killed, the adbd on device is not notified.
1. When adb server is killed while pushing a large file to device,
the device is still reading the unfinished large message. So the
device thinks of the CNXN message as part of the previous unfinished
message, so it doesn't reply and the device is in offline state.
The solution is to add a write_msg_lock in atransport struct. And it
kicks the transport only after sending a whole message. By kicking
all transports before exit, we ensure that we don't write part of
a message to any device. So next time we start adb server, the device
should be waiting for a new message.
2. When adb server is killed while pulling a large file from device,
the device is still trying to send the unfinished large message. So
adb on host usually reads data with EOVERFLOW error. This is because
adb on host is reading less than one packet sent from device.
The solution is to use buffered read on host. The max packet size
of bulk transactions in USB 3.0 is 1024 bytes. By preparing an at least
1024 bytes buffer when reading, EOVERFLOW no longer occurs. And teach
adb host to ignore wrong messages.
To be safe, this patch doesn't change any logic on device.
Bug: http://b/32952319
Test: run python -m unittest -q test_device.DeviceOfflineTest
Test: on linux/mac/windows with bullhead, ryu.
Change-Id: Ib149d30028a62a6f03857b8a95ab5a1d6e9b9c4e
2017-03-11 01:01:01 +01:00
|
|
|
if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
|
2015-10-07 23:55:10 +02:00
|
|
|
SendOkay(fd);
|
|
|
|
break;
|
|
|
|
} else if (!is_ambiguous) {
|
2016-02-19 19:42:40 +01:00
|
|
|
adb_pollfd pfd = {.fd = fd, .events = POLLIN };
|
|
|
|
int rc = adb_poll(&pfd, 1, 1000);
|
|
|
|
if (rc < 0) {
|
|
|
|
SendFail(fd, error);
|
|
|
|
break;
|
|
|
|
} else if (rc > 0 && (pfd.revents & POLLHUP) != 0) {
|
|
|
|
// The other end of the socket is closed, probably because the other side was
|
|
|
|
// terminated, bail out.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-10-07 23:55:10 +02:00
|
|
|
// Try again...
|
|
|
|
} else {
|
|
|
|
SendFail(fd, error);
|
|
|
|
break;
|
|
|
|
}
|
2009-03-04 04:32:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
adb_close(fd);
|
2015-09-03 02:44:28 +02:00
|
|
|
D("wait_for_state is done");
|
2009-03-04 04:32:55 +01:00
|
|
|
}
|
2013-03-30 02:22:36 +01:00
|
|
|
|
2015-05-01 02:32:03 +02:00
|
|
|
void connect_emulator(const std::string& port_spec, std::string* response) {
|
|
|
|
std::vector<std::string> pieces = android::base::Split(port_spec, ",");
|
|
|
|
if (pieces.size() != 2) {
|
|
|
|
*response = android::base::StringPrintf("unable to parse '%s' as <console port>,<adb port>",
|
|
|
|
port_spec.c_str());
|
2013-03-30 02:22:36 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-14 03:15:16 +02:00
|
|
|
int console_port = strtol(pieces[0].c_str(), nullptr, 0);
|
|
|
|
int adb_port = strtol(pieces[1].c_str(), nullptr, 0);
|
2015-05-01 02:32:03 +02:00
|
|
|
if (console_port <= 0 || adb_port <= 0) {
|
|
|
|
*response = android::base::StringPrintf("Invalid port numbers: %s", port_spec.c_str());
|
2013-03-30 02:22:36 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-01 02:32:03 +02:00
|
|
|
// Check if the emulator is already known.
|
|
|
|
// Note: There's a small but harmless race condition here: An emulator not
|
|
|
|
// present just yet could be registered by another invocation right
|
|
|
|
// after doing this check here. However, local_connect protects
|
|
|
|
// against double-registration too. From here, a better error message
|
|
|
|
// can be produced. In the case of the race condition, the very specific
|
|
|
|
// error message won't be shown, but the data doesn't get corrupted.
|
2013-03-30 02:22:36 +01:00
|
|
|
atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
|
2015-05-01 02:32:03 +02:00
|
|
|
if (known_emulator != nullptr) {
|
|
|
|
*response = android::base::StringPrintf("Emulator already registered on port %d", adb_port);
|
2013-03-30 02:22:36 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-01 02:32:03 +02:00
|
|
|
// Preconditions met, try to connect to the emulator.
|
2015-07-24 02:12:58 +02:00
|
|
|
std::string error;
|
|
|
|
if (!local_connect_arbitrary_ports(console_port, adb_port, &error)) {
|
2015-05-01 02:32:03 +02:00
|
|
|
*response = android::base::StringPrintf("Connected to emulator on ports %d,%d",
|
|
|
|
console_port, adb_port);
|
2013-03-30 02:22:36 +01:00
|
|
|
} else {
|
2015-07-24 02:12:58 +02:00
|
|
|
*response = android::base::StringPrintf("Could not connect to emulator on ports %d,%d: %s",
|
|
|
|
console_port, adb_port, error.c_str());
|
2013-03-30 02:22:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
static void connect_service(android::base::unique_fd fd, std::string host) {
|
2015-05-01 02:32:03 +02:00
|
|
|
std::string response;
|
2018-07-19 04:40:12 +02:00
|
|
|
if (!strncmp(host.c_str(), "emu:", 4)) {
|
|
|
|
connect_emulator(host.c_str() + 4, &response);
|
2013-03-30 02:22:36 +01:00
|
|
|
} else {
|
2018-07-19 04:40:12 +02:00
|
|
|
connect_device(host.c_str(), &response);
|
2013-03-30 02:22:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Send response for emulator and device
|
2018-07-19 04:40:12 +02:00
|
|
|
SendProtocolString(fd.get(), response);
|
2013-03-30 02:22:36 +01:00
|
|
|
}
|
2009-03-04 04:32:55 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ADB_HOST
|
2017-08-17 01:57:01 +02:00
|
|
|
asocket* host_service_to_socket(const char* name, const char* serial, TransportId transport_id) {
|
2009-03-04 04:32:55 +01:00
|
|
|
if (!strcmp(name,"track-devices")) {
|
2017-08-15 03:57:54 +02:00
|
|
|
return create_device_tracker(false);
|
|
|
|
} else if (!strcmp(name, "track-devices-l")) {
|
|
|
|
return create_device_tracker(true);
|
2015-11-27 18:56:48 +01:00
|
|
|
} else if (android::base::StartsWith(name, "wait-for-")) {
|
|
|
|
name += strlen("wait-for-");
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
std::unique_ptr<state_info> sinfo = std::make_unique<state_info>();
|
2015-04-22 04:39:52 +02:00
|
|
|
if (sinfo == nullptr) {
|
|
|
|
fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
|
2015-11-27 18:56:48 +01:00
|
|
|
return nullptr;
|
2015-04-22 04:39:52 +02:00
|
|
|
}
|
2009-03-04 04:32:55 +01:00
|
|
|
|
2015-11-27 18:56:48 +01:00
|
|
|
if (serial) sinfo->serial = serial;
|
2017-08-17 01:57:01 +02:00
|
|
|
sinfo->transport_id = transport_id;
|
2009-03-04 04:32:55 +01:00
|
|
|
|
2015-11-27 18:56:48 +01:00
|
|
|
if (android::base::StartsWith(name, "local")) {
|
|
|
|
name += strlen("local");
|
2015-05-05 22:10:43 +02:00
|
|
|
sinfo->transport_type = kTransportLocal;
|
2015-11-27 18:56:48 +01:00
|
|
|
} else if (android::base::StartsWith(name, "usb")) {
|
|
|
|
name += strlen("usb");
|
2015-05-05 22:10:43 +02:00
|
|
|
sinfo->transport_type = kTransportUsb;
|
2015-11-27 18:56:48 +01:00
|
|
|
} else if (android::base::StartsWith(name, "any")) {
|
|
|
|
name += strlen("any");
|
2015-05-05 22:10:43 +02:00
|
|
|
sinfo->transport_type = kTransportAny;
|
2015-11-27 18:56:48 +01:00
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(name, "-device")) {
|
2015-05-19 01:43:57 +02:00
|
|
|
sinfo->state = kCsDevice;
|
2015-11-27 18:56:48 +01:00
|
|
|
} else if (!strcmp(name, "-recovery")) {
|
|
|
|
sinfo->state = kCsRecovery;
|
|
|
|
} else if (!strcmp(name, "-sideload")) {
|
|
|
|
sinfo->state = kCsSideload;
|
|
|
|
} else if (!strcmp(name, "-bootloader")) {
|
|
|
|
sinfo->state = kCsBootloader;
|
2016-04-13 21:18:58 +02:00
|
|
|
} else if (!strcmp(name, "-any")) {
|
|
|
|
sinfo->state = kCsAny;
|
2009-03-04 04:32:55 +01:00
|
|
|
} else {
|
2015-11-27 18:56:48 +01:00
|
|
|
return nullptr;
|
2009-03-04 04:32:55 +01:00
|
|
|
}
|
|
|
|
|
2018-07-19 04:40:12 +02:00
|
|
|
int fd = create_service_thread(
|
|
|
|
"wait", std::bind(wait_for_state, std::placeholders::_1, sinfo.get()))
|
|
|
|
.release();
|
2017-08-16 00:07:21 +02:00
|
|
|
if (fd != -1) {
|
|
|
|
sinfo.release();
|
|
|
|
}
|
2009-03-04 04:32:55 +01:00
|
|
|
return create_local_socket(fd);
|
2013-03-30 02:22:36 +01:00
|
|
|
} else if (!strncmp(name, "connect:", 8)) {
|
2018-07-19 04:40:12 +02:00
|
|
|
std::string host(name + strlen("connect:"));
|
|
|
|
int fd = create_service_thread("connect",
|
|
|
|
std::bind(connect_service, std::placeholders::_1, host))
|
|
|
|
.release();
|
2013-03-30 02:22:36 +01:00
|
|
|
return create_local_socket(fd);
|
2009-03-04 04:32:55 +01:00
|
|
|
}
|
2018-07-14 03:15:16 +02:00
|
|
|
return nullptr;
|
2009-03-04 04:32:55 +01:00
|
|
|
}
|
|
|
|
#endif /* ADB_HOST */
|