summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Gao <jmgao@google.com>2020-01-22 18:02:19 -0800
committerJosh Gao <jmgao@google.com>2020-01-29 00:03:20 +0000
commitbd396c001fd3b13a7451876ec8c535bb597ea350 (patch)
tree0323ee2c9bc30732dacf42e985282086338723f2
parent3f0dca119df45ef2a7fdfc26c070677953cfcce4 (diff)
downloadplatform_art-bd396c001fd3b13a7451876ec8c535bb597ea350.tar.gz
platform_art-bd396c001fd3b13a7451876ec8c535bb597ea350.tar.bz2
platform_art-bd396c001fd3b13a7451876ec8c535bb597ea350.zip
Move jdwp connection abstraction from ART apex to adbd apex.
Test: ./art/tools/run-jdwp-tests.sh Change-Id: I3114b8403f3548700a45df5d7bb72ebe727adec1
-rw-r--r--Android.mk2
-rw-r--r--adbconnection/Android.bp27
-rw-r--r--adbconnection/adbconnection.cc115
-rw-r--r--adbconnection/adbconnection.h6
-rw-r--r--adbconnection/adbconnection_server.cc133
-rw-r--r--adbconnection/include/adbconnection/server.h30
-rw-r--r--adbconnection/libadbconnection_server.map.txt22
-rw-r--r--build/apex/Android.bp1
-rwxr-xr-xbuild/apex/art_apex_test.py1
-rw-r--r--build/apex/ld.config.txt25
10 files changed, 56 insertions, 306 deletions
diff --git a/Android.mk b/Android.mk
index 6e41516c8a1..fc44da43aac 100644
--- a/Android.mk
+++ b/Android.mk
@@ -537,7 +537,6 @@ PRIVATE_ART_APEX_DEPENDENCY_FILES := \
PRIVATE_ART_APEX_DEPENDENCY_LIBS := \
lib/libadbconnectiond.so \
- lib/libadbconnection_server.so \
lib/libadbconnection.so \
lib/libandroidicu.so \
lib/libandroidio.so \
@@ -591,7 +590,6 @@ PRIVATE_ART_APEX_DEPENDENCY_LIBS := \
lib/libziparchive.so \
lib/libz.so \
lib64/libadbconnectiond.so \
- lib64/libadbconnection_server.so \
lib64/libadbconnection.so \
lib64/libandroidicu.so \
lib64/libandroidio.so \
diff --git a/adbconnection/Android.bp b/adbconnection/Android.bp
index b2503e1b495..b03cd0d07b7 100644
--- a/adbconnection/Android.bp
+++ b/adbconnection/Android.bp
@@ -28,6 +28,7 @@ cc_defaults {
shared_libs: [
"libbase",
+ "libadbconnection_client",
],
target: {
host: {
@@ -59,32 +60,6 @@ art_cc_library {
],
}
-// We export a library to do the server-side socket handling that gets loaded
-// by adbd from the art apex, so that we can update the socket handling
-// independently from the adbd apex.
-cc_library {
- name: "libadbconnection_server",
- srcs: ["adbconnection_server.cc"],
-
- export_include_dirs: ["include"],
-
- stl: "libc++_static",
- shared_libs: ["liblog"],
- whole_static_libs: ["libbase"],
-
- defaults: ["art_defaults"],
- visibility: [
- "//system/core/adb",
- ],
- stubs: {
- symbol_file: "libadbconnection_server.map.txt",
- versions: ["1"],
- },
-
- host_supported: true,
- recovery_available: true,
-}
-
art_cc_library {
name: "libadbconnectiond",
defaults: [
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index 0824eb459b6..2234ce4fa24 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -15,16 +15,17 @@
*/
#include <array>
+#include <iterator>
#include "adbconnection.h"
+#include "adbconnection/client.h"
#include "android-base/endian.h"
#include "android-base/stringprintf.h"
#include "base/file_utils.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex.h"
-#include "base/socket_peer_is_trusted.h"
#include "jni/java_vm_ext.h"
#include "jni/jni_env_ext.h"
#include "mirror/throwable.h"
@@ -66,7 +67,6 @@ static constexpr const char kJdwpHandshake[14] = {
static constexpr int kEventfdLocked = 0;
static constexpr int kEventfdUnlocked = 1;
-static constexpr int kControlSockSendTimeout = 10;
static constexpr size_t kPacketHeaderLen = 11;
static constexpr off_t kPacketSizeOff = 0;
@@ -125,7 +125,7 @@ AdbConnectionState::AdbConnectionState(const std::string& agent_name)
controller_(this),
ddm_callback_(this),
sleep_event_fd_(-1),
- control_sock_(-1),
+ control_ctx_(nullptr, adbconnection_client_destroy),
local_agent_control_sock_(-1),
remote_agent_control_sock_(-1),
adb_connection_socket_(-1),
@@ -447,57 +447,18 @@ void AdbConnectionState::SendAgentFds(bool require_handshake) {
}
android::base::unique_fd AdbConnectionState::ReadFdFromAdb() {
- // We don't actually care about the data that is sent. We do need to receive something though.
- char dummy = '!';
- union {
- cmsghdr cm;
- char buffer[CMSG_SPACE(sizeof(int))];
- } cm_un;
-
- iovec iov;
- iov.iov_base = &dummy;
- iov.iov_len = 1;
-
- msghdr msg;
- msg.msg_name = nullptr;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_flags = 0;
- msg.msg_control = cm_un.buffer;
- msg.msg_controllen = sizeof(cm_un.buffer);
-
- cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = msg.msg_controllen;
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- (reinterpret_cast<int*>(CMSG_DATA(cmsg)))[0] = -1;
-
- int rc = TEMP_FAILURE_RETRY(recvmsg(control_sock_, &msg, 0));
-
- if (rc <= 0) {
- return android::base::unique_fd(-1);
- } else {
- VLOG(jdwp) << "Fds have been received from ADB!";
- }
-
- return android::base::unique_fd((reinterpret_cast<int*>(CMSG_DATA(cmsg)))[0]);
+ return android::base::unique_fd(adbconnection_client_receive_jdwp_fd(control_ctx_.get()));
}
bool AdbConnectionState::SetupAdbConnection() {
- int sleep_ms = 500;
- const int sleep_max_ms = 2*1000;
+ int sleep_ms = 500;
+ const int sleep_max_ms = 2 * 1000;
- android::base::unique_fd sock(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
- if (sock < 0) {
- PLOG(ERROR) << "Could not create ADB control socket";
- return false;
- }
- struct timeval timeout;
- timeout.tv_sec = kControlSockSendTimeout;
- timeout.tv_usec = 0;
- setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
- int32_t pid = getpid();
+ const AdbConnectionClientInfo infos[] = {
+ {.type = AdbConnectionClientInfoType::pid, .data.pid = static_cast<uint64_t>(getpid())},
+ {.type = AdbConnectionClientInfoType::debuggable, .data.debuggable = true},
+ };
+ const AdbConnectionClientInfo* info_ptrs[] = {&infos[0], &infos[1]};
while (!shutting_down_) {
// If adbd isn't running, because USB debugging was disabled or
@@ -511,39 +472,20 @@ bool AdbConnectionState::SetupAdbConnection() {
// of battery life, we should consider timing out and giving
// up after a few minutes in case somebody ships an app with
// the debuggable flag set.
- int ret = connect(sock, &control_addr_.controlAddrPlain, control_addr_len_);
- if (ret == 0) {
- bool trusted = sock >= 0 && art::SocketPeerIsTrusted(sock);
- if (!trusted) {
- LOG(ERROR) << "adb socket is not trusted. Aborting connection.";
- if (sock >= 0 && shutdown(sock, SHUT_RDWR)) {
- PLOG(ERROR) << "trouble shutting down socket";
- }
- return false;
- }
- /* now try to send our pid to the ADB daemon */
- ret = TEMP_FAILURE_RETRY(send(sock, &pid, sizeof(pid), 0));
- if (ret == sizeof(pid)) {
- VLOG(jdwp) << "PID " << pid << " sent to adb";
- control_sock_ = std::move(sock);
- return true;
- } else {
- PLOG(ERROR) << "Weird, can't send JDWP process pid to ADB. Aborting connection.";
- return false;
- }
- } else {
- if (VLOG_IS_ON(jdwp)) {
- PLOG(ERROR) << "Can't connect to ADB control socket. Will retry.";
- }
+ control_ctx_.reset(adbconnection_client_new(info_ptrs, std::size(infos)));
+ if (control_ctx_) {
+ return true;
+ }
- usleep(sleep_ms * 1000);
+ // We failed to connect.
+ usleep(sleep_ms * 1000);
- sleep_ms += (sleep_ms >> 1);
- if (sleep_ms > sleep_max_ms) {
- sleep_ms = sleep_max_ms;
- }
+ sleep_ms += (sleep_ms >> 1);
+ if (sleep_ms > sleep_max_ms) {
+ sleep_ms = sleep_max_ms;
}
}
+
return false;
}
@@ -554,12 +496,12 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) {
self->SetState(art::kWaitingInMainDebuggerLoop);
// shutting_down_ set by StopDebuggerThreads
while (!shutting_down_) {
- // First get the control_sock_ from adb if we don't have one. We only need to do this once.
- if (control_sock_ == -1 && !SetupAdbConnection()) {
+ // First, connect to adbd if we haven't already.
+ if (!control_ctx_ && !SetupAdbConnection()) {
LOG(ERROR) << "Failed to setup adb connection.";
return;
}
- while (!shutting_down_ && control_sock_ != -1) {
+ while (!shutting_down_ && control_ctx_) {
bool should_listen_on_connection = !agent_has_socket_ && !sent_agent_fds_;
struct pollfd pollfds[4] = {
{ sleep_event_fd_, POLLIN, 0 },
@@ -567,7 +509,8 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) {
{ (agent_loaded_ ? local_agent_control_sock_ : -1), POLLIN, 0 },
// Check for the control_sock_ actually going away. Only do this if we don't have an active
// connection.
- { (adb_connection_socket_ == -1 ? control_sock_ : -1), POLLIN | POLLRDHUP, 0 },
+ { (adb_connection_socket_ == -1 ? adbconnection_client_pollfd(control_ctx_.get()) : -1),
+ POLLIN | POLLRDHUP, 0 },
// if we have not loaded the agent either the adb_connection_socket_ is -1 meaning we don't
// have a real connection yet or the socket through adb needs to be listened to for incoming
// data that the agent or this plugin can handle.
@@ -617,10 +560,10 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) {
{
// Hold onto this lock so that concurrent ddm publishes don't try to use an illegal fd.
ScopedEventFdLock sefdl(adb_write_event_fd_);
- android::base::unique_fd new_fd(ReadFdFromAdb());
+ android::base::unique_fd new_fd(adbconnection_client_receive_jdwp_fd(control_ctx_.get()));
if (new_fd == -1) {
// Something went wrong. We need to retry getting the control socket.
- control_sock_.reset();
+ control_ctx_.reset();
break;
} else if (adb_connection_socket_ != -1) {
// We already have a connection.
@@ -645,7 +588,7 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) {
// Reset the connection since we don't have an active socket through the adb server.
DCHECK(!agent_has_socket_) << "We shouldn't be doing anything if there is already a "
<< "connection active";
- control_sock_.reset();
+ control_ctx_.reset();
break;
} else if (FlagsSet(adb_socket_poll.revents, POLLIN)) {
DCHECK(!agent_has_socket_);
diff --git a/adbconnection/adbconnection.h b/adbconnection/adbconnection.h
index c51f981f40e..f9b0928298e 100644
--- a/adbconnection/adbconnection.h
+++ b/adbconnection/adbconnection.h
@@ -18,10 +18,12 @@
#define ART_ADBCONNECTION_ADBCONNECTION_H_
#include <stdint.h>
+#include <memory>
#include <vector>
#include <limits>
#include "android-base/unique_fd.h"
+#include "adbconnection/client.h"
#include "base/mutex.h"
#include "base/array_ref.h"
@@ -127,8 +129,8 @@ class AdbConnectionState {
// Eventfd used to allow the StopDebuggerThreads function to wake up sleeping threads
android::base::unique_fd sleep_event_fd_;
- // Socket that we use to talk to adbd.
- android::base::unique_fd control_sock_;
+ // Context which wraps the socket which we use to talk to adbd.
+ std::unique_ptr<AdbConnectionClientContext, void(*)(AdbConnectionClientContext*)> control_ctx_;
// Socket that we use to talk to the agent (if it's loaded).
android::base::unique_fd local_agent_control_sock_;
diff --git a/adbconnection/adbconnection_server.cc b/adbconnection/adbconnection_server.cc
deleted file mode 100644
index f69f4a71966..00000000000
--- a/adbconnection/adbconnection_server.cc
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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);
- }
- }
- }
-}
diff --git a/adbconnection/include/adbconnection/server.h b/adbconnection/include/adbconnection/server.h
deleted file mode 100644
index 8d1d69a771a..00000000000
--- a/adbconnection/include/adbconnection/server.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef ART_ADBCONNECTION_INCLUDE_ADBCONNECTION_SERVER_H_
-#define ART_ADBCONNECTION_INCLUDE_ADBCONNECTION_SERVER_H_
-
-/*
- * 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 <sys/types.h>
-
-#include <android-base/unique_fd.h>
-
-extern "C" {
-
-void adbconnection_listen(void (*callback)(int fd, pid_t pid));
-
-}
-
-#endif // ART_ADBCONNECTION_INCLUDE_ADBCONNECTION_SERVER_H_
diff --git a/adbconnection/libadbconnection_server.map.txt b/adbconnection/libadbconnection_server.map.txt
deleted file mode 100644
index b6315810315..00000000000
--- a/adbconnection/libadbconnection_server.map.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# 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_SERVER_1 {
- global:
- adbconnection_listen;
- local:
- *;
-};
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index 70e4988d741..738a8700cbc 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -27,7 +27,6 @@ art_runtime_base_binaries_prefer32 = [
// the ART APEX.
art_runtime_base_native_shared_libs = [
// External API (having APEX stubs).
- "libadbconnection_server",
"libdexfile_external",
"libnativebridge",
"libnativehelper",
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
index 4062676b254..f2ec6e43780 100755
--- a/build/apex/art_apex_test.py
+++ b/build/apex/art_apex_test.py
@@ -492,7 +492,6 @@ class ReleaseChecker:
self._checker.check_native_library('libnativebridge')
self._checker.check_native_library('libnativehelper')
self._checker.check_native_library('libnativeloader')
- self._checker.check_native_library('libadbconnection_server')
# Check internal libraries for ART.
self._checker.check_native_library('libadbconnection')
diff --git a/build/apex/ld.config.txt b/build/apex/ld.config.txt
index b2eefcfc091..4121e9f8bcd 100644
--- a/build/apex/ld.config.txt
+++ b/build/apex/ld.config.txt
@@ -8,15 +8,16 @@
dir.art = /apex/com.android.art/bin/
[art]
-additional.namespaces = platform,conscrypt,art,neuralnetworks
+additional.namespaces = platform,conscrypt,art,neuralnetworks,adbd
# The default namespace here only links to other namespaces, in particular "art"
# where the real library loading takes place. Any outgoing links from "art" also
# need to be present here.
namespace.default.isolated = true
-namespace.default.links = art,platform
+namespace.default.links = art,platform,adbd
namespace.default.link.art.allow_all_shared_libs = true
namespace.default.link.platform.allow_all_shared_libs = true
+namespace.default.link.adbd.shared_libs = libadbconnection_client.so
###############################################################################
# "art" APEX namespace
@@ -47,13 +48,14 @@ namespace.art.permitted.paths += /apex/com.android.art/javalib
# the APEX namespaces, because searching of the libs are NOT done in
# /system/lib, but in /apex/<module>/lib directory.
namespace.art.permitted.paths += /system/${LIB}
-namespace.art.links = platform,neuralnetworks
+namespace.art.links = platform,neuralnetworks,adbd
# Need allow_all_shared_libs because libart.so can dlopen oat files in
# /system/framework and /data.
# TODO(b/130340935): Use a dynamically created linker namespace similar to
# classloader-namespace for oat files, and tighten this up.
namespace.art.link.platform.allow_all_shared_libs = true
namespace.art.link.neuralnetworks.shared_libs = libneuralnetworks.so
+namespace.art.link.adbd.shared_libs = libadbconnection_client.so
###############################################################################
# "platform" namespace
@@ -155,3 +157,20 @@ namespace.neuralnetworks.link.platform.shared_libs += libnativewindow.so
namespace.neuralnetworks.link.platform.shared_libs += libneuralnetworks_packageinfo.so
namespace.neuralnetworks.link.platform.shared_libs += libsync.so
namespace.neuralnetworks.link.platform.shared_libs += libvndksupport.so
+
+###############################################################################
+# "adbd" APEX namespace
+#
+# This namespace is for libraries within the adbd APEX.
+###############################################################################
+
+namespace.adbd.isolated = true
+namespace.adbd.visible = true
+
+namespace.adbd.search.paths = /apex/com.android.adbd/${LIB}
+namespace.adbd.asan.search.paths = /apex/com.android.adbd/${LIB}
+namespace.adbd.links = platform
+namespace.adbd.link.platform.shared_libs = libc.so
+namespace.adbd.link.platform.shared_libs += libm.so
+namespace.adbd.link.platform.shared_libs += libdl.so
+namespace.adbd.link.platform.shared_libs += liblog.so