Merge "Move jdwp connection abstraction from ART apex to adbd apex."

This commit is contained in:
Josh Gao 2020-01-29 00:03:22 +00:00 committed by Gerrit Code Review
commit e30aa60128
8 changed files with 450 additions and 5 deletions

View file

@ -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",
],
}

View file

@ -0,0 +1 @@
../../.clang-format-2

View 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();
}

View 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(), &register_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);
}
}
}
}

View 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);
}

View 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));
}

View 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:
*;
};

View file

@ -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",