Merge "Move jdwp connection abstraction from ART apex to adbd apex."
This commit is contained in:
commit
e30aa60128
8 changed files with 450 additions and 5 deletions
|
@ -114,6 +114,61 @@ cc_defaults {
|
|||
},
|
||||
}
|
||||
|
||||
// libadbconnection
|
||||
// =========================================================
|
||||
// libadbconnection_client/server implement the socket handling for jdwp
|
||||
// forwarding and the track-jdwp service.
|
||||
cc_library {
|
||||
name: "libadbconnection_server",
|
||||
srcs: ["adbconnection/adbconnection_server.cpp"],
|
||||
|
||||
export_include_dirs: ["adbconnection/include"],
|
||||
|
||||
stl: "libc++_static",
|
||||
shared_libs: ["liblog"],
|
||||
static_libs: ["libbase"],
|
||||
|
||||
defaults: ["adbd_defaults", "host_adbd_supported"],
|
||||
|
||||
// Avoid getting duplicate symbol of android::build::getbuildnumber().
|
||||
use_version_lib: false,
|
||||
|
||||
recovery_available: true,
|
||||
compile_multilib: "both",
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libadbconnection_client",
|
||||
srcs: ["adbconnection/adbconnection_client.cpp"],
|
||||
|
||||
export_include_dirs: ["adbconnection/include"],
|
||||
|
||||
stl: "libc++_static",
|
||||
shared_libs: ["liblog"],
|
||||
static_libs: ["libbase"],
|
||||
|
||||
defaults: ["adbd_defaults"],
|
||||
visibility: [
|
||||
"//art:__subpackages__",
|
||||
"//system/core/adb/apex:__subpackages__",
|
||||
],
|
||||
apex_available: [
|
||||
"com.android.adbd",
|
||||
"test_com.android.adbd",
|
||||
],
|
||||
|
||||
// libadbconnection_client doesn't need an embedded build number.
|
||||
use_version_lib: false,
|
||||
|
||||
stubs: {
|
||||
symbol_file: "adbconnection/libadbconnection_client.map.txt",
|
||||
versions: ["1"],
|
||||
},
|
||||
|
||||
host_supported: true,
|
||||
compile_multilib: "both",
|
||||
}
|
||||
|
||||
// libadb
|
||||
// =========================================================
|
||||
// These files are compiled for both the host and the device.
|
||||
|
@ -358,11 +413,11 @@ cc_library_static {
|
|||
generated_headers: ["platform_tools_version"],
|
||||
|
||||
static_libs: [
|
||||
"libadbconnection_server",
|
||||
"libdiagnose_usb",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libadbconnection_server",
|
||||
"libadbd_auth",
|
||||
"libasyncio",
|
||||
"libbase",
|
||||
|
@ -411,12 +466,12 @@ cc_library {
|
|||
],
|
||||
|
||||
static_libs: [
|
||||
"libadbconnection_server",
|
||||
"libadbd_core",
|
||||
"libdiagnose_usb",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libadbconnection_server",
|
||||
"libadbd_auth",
|
||||
"libasyncio",
|
||||
"libbase",
|
||||
|
@ -452,7 +507,7 @@ cc_library {
|
|||
defaults: ["adbd_defaults", "host_adbd_supported"],
|
||||
recovery_available: true,
|
||||
|
||||
// Avoid getting duplicate symbol of android::build::GetBuildNumber().
|
||||
// avoid getting duplicate symbol of android::build::getbuildnumber().
|
||||
use_version_lib: false,
|
||||
|
||||
// libminadbd wants both, as it's used to build native tests.
|
||||
|
@ -460,11 +515,11 @@ cc_library {
|
|||
|
||||
// libadbd doesn't build any additional source, but to expose libadbd_core as a shared library.
|
||||
whole_static_libs: [
|
||||
"libadbconnection_server",
|
||||
"libadbd_core",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libadbconnection_server",
|
||||
"libadbd_auth",
|
||||
"libadbd_services",
|
||||
"libasyncio",
|
||||
|
@ -500,6 +555,7 @@ cc_binary {
|
|||
|
||||
stl: "libc++_static",
|
||||
static_libs: [
|
||||
"libadbconnection_server",
|
||||
"libadbd",
|
||||
"libadbd_auth",
|
||||
"libadbd_services",
|
||||
|
@ -516,7 +572,6 @@ cc_binary {
|
|||
],
|
||||
|
||||
shared_libs: [
|
||||
"libadbconnection_server",
|
||||
"libcrypto",
|
||||
],
|
||||
}
|
||||
|
|
1
adb/adbconnection/.clang-format
Symbolic link
1
adb/adbconnection/.clang-format
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../.clang-format-2
|
148
adb/adbconnection/adbconnection_client.cpp
Normal file
148
adb/adbconnection/adbconnection_client.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#include "adbconnection/client.h"
|
||||
|
||||
#include <pwd.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <android-base/cmsg.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
using android::base::unique_fd;
|
||||
|
||||
static constexpr char kJdwpControlName[] = "\0jdwp-control";
|
||||
|
||||
struct AdbConnectionClientContext {
|
||||
unique_fd control_socket_;
|
||||
};
|
||||
|
||||
bool SocketPeerIsTrusted(int fd) {
|
||||
ucred cr;
|
||||
socklen_t cr_length = sizeof(cr);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_length) != 0) {
|
||||
PLOG(ERROR) << "couldn't get socket credentials";
|
||||
return false;
|
||||
}
|
||||
|
||||
passwd* shell = getpwnam("shell");
|
||||
if (cr.uid != 0 && cr.uid != shell->pw_uid) {
|
||||
LOG(ERROR) << "untrusted uid " << cr.uid << " on other end of socket";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AdbConnectionClientContext* adbconnection_client_new(
|
||||
const AdbConnectionClientInfo* const* info_elems, size_t info_count) {
|
||||
auto ctx = std::make_unique<AdbConnectionClientContext>();
|
||||
|
||||
std::optional<uint64_t> pid;
|
||||
std::optional<bool> debuggable;
|
||||
|
||||
for (size_t i = 0; i < info_count; ++i) {
|
||||
auto info = info_elems[i];
|
||||
switch (info->type) {
|
||||
case AdbConnectionClientInfoType::pid:
|
||||
if (pid) {
|
||||
LOG(ERROR) << "multiple pid entries in AdbConnectionClientInfo, ignoring";
|
||||
continue;
|
||||
}
|
||||
pid = info->data.pid;
|
||||
break;
|
||||
|
||||
case AdbConnectionClientInfoType::debuggable:
|
||||
if (debuggable) {
|
||||
LOG(ERROR) << "multiple debuggable entries in AdbConnectionClientInfo, ignoring";
|
||||
continue;
|
||||
}
|
||||
debuggable = info->data.pid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pid) {
|
||||
LOG(ERROR) << "AdbConnectionClientInfo missing required field pid";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!debuggable) {
|
||||
LOG(ERROR) << "AdbConnectionClientInfo missing required field debuggable";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ctx->control_socket_.reset(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
|
||||
if (ctx->control_socket_ < 0) {
|
||||
PLOG(ERROR) << "failed to create Unix domain socket";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
setsockopt(ctx->control_socket_.get(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
sockaddr_un addr = {};
|
||||
addr.sun_family = AF_UNIX;
|
||||
memcpy(addr.sun_path, kJdwpControlName, sizeof(kJdwpControlName));
|
||||
size_t addr_len = offsetof(sockaddr_un, sun_path) + sizeof(kJdwpControlName) - 1;
|
||||
|
||||
int rc = connect(ctx->control_socket_.get(), reinterpret_cast<sockaddr*>(&addr), addr_len);
|
||||
if (rc != 0) {
|
||||
PLOG(ERROR) << "failed to connect to jdwp control socket";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool trusted = SocketPeerIsTrusted(ctx->control_socket_.get());
|
||||
if (!trusted) {
|
||||
LOG(ERROR) << "adb socket is not trusted, aborting connection";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t pid_u32 = static_cast<uint32_t>(*pid);
|
||||
rc = TEMP_FAILURE_RETRY(write(ctx->control_socket_.get(), &pid_u32, sizeof(pid_u32)));
|
||||
if (rc != sizeof(pid_u32)) {
|
||||
PLOG(ERROR) << "failed to send JDWP process pid to adbd";
|
||||
}
|
||||
|
||||
return ctx.release();
|
||||
}
|
||||
|
||||
void adbconnection_client_destroy(AdbConnectionClientContext* ctx) {
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
int adbconnection_client_pollfd(AdbConnectionClientContext* ctx) {
|
||||
return ctx->control_socket_.get();
|
||||
}
|
||||
|
||||
int adbconnection_client_receive_jdwp_fd(AdbConnectionClientContext* ctx) {
|
||||
char dummy;
|
||||
unique_fd jdwp_fd;
|
||||
ssize_t rc = android::base::ReceiveFileDescriptors(ctx->control_socket_, &dummy, 1, &jdwp_fd);
|
||||
if (rc != 1) {
|
||||
return rc;
|
||||
}
|
||||
return jdwp_fd.release();
|
||||
}
|
129
adb/adbconnection/adbconnection_server.cpp
Normal file
129
adb/adbconnection/adbconnection_server.cpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (C) 2019 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.
|
||||
*/
|
||||
|
||||
#include "adbconnection/server.h"
|
||||
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
using android::base::unique_fd;
|
||||
|
||||
#define JDWP_CONTROL_NAME "\0jdwp-control"
|
||||
#define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME) - 1)
|
||||
|
||||
static_assert(JDWP_CONTROL_NAME_LEN <= sizeof(reinterpret_cast<sockaddr_un*>(0)->sun_path));
|
||||
|
||||
// Listen for incoming jdwp clients forever.
|
||||
void adbconnection_listen(void (*callback)(int fd, pid_t pid)) {
|
||||
sockaddr_un addr = {};
|
||||
socklen_t addrlen = JDWP_CONTROL_NAME_LEN + sizeof(addr.sun_family);
|
||||
|
||||
addr.sun_family = AF_UNIX;
|
||||
memcpy(addr.sun_path, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN);
|
||||
|
||||
unique_fd s(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
if (s < 0) {
|
||||
PLOG(ERROR) << "failed to create JDWP control socket";
|
||||
return;
|
||||
}
|
||||
|
||||
if (bind(s.get(), reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
|
||||
PLOG(ERROR) << "failed to bind JDWP control socket";
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen(s.get(), 4) < 0) {
|
||||
PLOG(ERROR) << "failed to listen on JDWP control socket";
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<unique_fd> pending_connections;
|
||||
|
||||
unique_fd epfd(epoll_create1(EPOLL_CLOEXEC));
|
||||
std::array<epoll_event, 16> events;
|
||||
|
||||
events[0].events = EPOLLIN;
|
||||
events[0].data.fd = -1;
|
||||
if (epoll_ctl(epfd.get(), EPOLL_CTL_ADD, s.get(), &events[0]) != 0) {
|
||||
LOG(FATAL) << "failed to register event with epoll fd";
|
||||
}
|
||||
|
||||
while (true) {
|
||||
int epoll_rc = TEMP_FAILURE_RETRY(epoll_wait(epfd.get(), events.data(), events.size(), -1));
|
||||
if (epoll_rc == -1) {
|
||||
PLOG(FATAL) << "epoll_wait failed";
|
||||
}
|
||||
|
||||
for (int i = 0; i < epoll_rc; ++i) {
|
||||
const epoll_event& event = events[i];
|
||||
if (event.data.fd == -1) {
|
||||
unique_fd client(
|
||||
TEMP_FAILURE_RETRY(accept4(s.get(), nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC)));
|
||||
|
||||
if (client == -1) {
|
||||
PLOG(WARNING) << "failed to accept client on JDWP control socket";
|
||||
continue;
|
||||
}
|
||||
|
||||
epoll_event register_event;
|
||||
register_event.events = EPOLLIN;
|
||||
register_event.data.fd = client.get();
|
||||
|
||||
if (epoll_ctl(epfd.get(), EPOLL_CTL_ADD, client.get(), ®ister_event) != 0) {
|
||||
PLOG(FATAL) << "failed to register JDWP client with epoll";
|
||||
}
|
||||
|
||||
pending_connections.emplace_back(std::move(client));
|
||||
} else {
|
||||
// n^2, but the backlog should be short.
|
||||
auto it = std::find_if(pending_connections.begin(), pending_connections.end(),
|
||||
[&](const unique_fd& fd) { return fd.get() == event.data.fd; });
|
||||
|
||||
if (it == pending_connections.end()) {
|
||||
LOG(FATAL) << "failed to find JDWP client (" << event.data.fd
|
||||
<< ") in pending connections";
|
||||
}
|
||||
|
||||
// Massively oversized buffer: we're expecting an int32_t from the other end.
|
||||
char buf[32];
|
||||
int rc = TEMP_FAILURE_RETRY(recv(it->get(), buf, sizeof(buf), MSG_DONTWAIT));
|
||||
if (rc != 4) {
|
||||
LOG(ERROR) << "received data of incorrect size from JDWP client: read " << rc
|
||||
<< ", expected 4";
|
||||
} else {
|
||||
int32_t pid;
|
||||
memcpy(&pid, buf, sizeof(pid));
|
||||
callback(it->release(), static_cast<pid_t>(pid));
|
||||
}
|
||||
|
||||
if (epoll_ctl(epfd.get(), EPOLL_CTL_DEL, event.data.fd, nullptr) != 0) {
|
||||
LOG(FATAL) << "failed to delete fd from JDWP epoll fd";
|
||||
}
|
||||
|
||||
pending_connections.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
55
adb/adbconnection/include/adbconnection/client.h
Normal file
55
adb/adbconnection/include/adbconnection/client.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2019 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct AdbConnectionClientContext;
|
||||
|
||||
enum AdbConnectionClientInfoType {
|
||||
pid,
|
||||
debuggable,
|
||||
};
|
||||
|
||||
struct AdbConnectionClientInfo {
|
||||
AdbConnectionClientInfoType type;
|
||||
union {
|
||||
uint64_t pid;
|
||||
bool debuggable;
|
||||
} data;
|
||||
};
|
||||
|
||||
// Construct a context and connect to adbd.
|
||||
// Returns null if we fail to connect to adbd.
|
||||
AdbConnectionClientContext* adbconnection_client_new(
|
||||
const AdbConnectionClientInfo* const* info_elems, size_t info_count);
|
||||
|
||||
void adbconnection_client_destroy(AdbConnectionClientContext* ctx);
|
||||
|
||||
// Get an fd which can be polled upon to detect when a jdwp socket is available.
|
||||
// You do not own this fd. Do not close it.
|
||||
int adbconnection_client_pollfd(AdbConnectionClientContext* ctx);
|
||||
|
||||
// Receive a jdwp client fd.
|
||||
// Ownership is transferred to the caller of this function.
|
||||
int adbconnection_client_receive_jdwp_fd(AdbConnectionClientContext* ctx);
|
||||
}
|
26
adb/adbconnection/include/adbconnection/server.h
Normal file
26
adb/adbconnection/include/adbconnection/server.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) 2019 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
void adbconnection_listen(void (*callback)(int fd, pid_t pid));
|
||||
}
|
25
adb/adbconnection/libadbconnection_client.map.txt
Normal file
25
adb/adbconnection/libadbconnection_client.map.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
# Copyright (C) 2019 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.
|
||||
#
|
||||
|
||||
LIBADBCONNECTION_CLIENT_1 {
|
||||
global:
|
||||
adbconnection_client_new;
|
||||
adbconnection_client_destroy;
|
||||
adbconnection_client_pollfd;
|
||||
adbconnection_client_receive_jdwp_fd;
|
||||
local:
|
||||
*;
|
||||
};
|
|
@ -2,6 +2,12 @@ apex_defaults {
|
|||
name: "com.android.adbd-defaults",
|
||||
|
||||
binaries: ["adbd"],
|
||||
compile_multilib: "both",
|
||||
multilib: {
|
||||
both: {
|
||||
native_shared_libs: ["libadbconnection_client"],
|
||||
},
|
||||
},
|
||||
prebuilts: ["com.android.adbd.init.rc", "com.android.adbd.ld.config.txt"],
|
||||
|
||||
key: "com.android.adbd.key",
|
||||
|
|
Loading…
Reference in a new issue