Merge "fs_mgr: Add a library for managing logical partitions."
diff --git a/adb/Android.bp b/adb/Android.bp
index 53bf7e3..97c9762 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -104,6 +104,7 @@
"socket_spec.cpp",
"sysdeps/errno.cpp",
"transport.cpp",
+ "transport_fd.cpp",
"transport_local.cpp",
"transport_usb.cpp",
]
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 06fcf16..e07dba7 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1795,6 +1795,11 @@
}
else if (!strcmp(argv[0], "track-devices")) {
return adb_connect_command("host:track-devices");
+ } else if (!strcmp(argv[0], "raw")) {
+ if (argc != 2) {
+ return syntax_error("adb raw SERVICE");
+ }
+ return adb_connect_command(argv[1]);
}
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 1b7758c..f98c11a 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -21,6 +21,7 @@
#include "fdevent.h"
#include <fcntl.h>
+#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -34,6 +35,7 @@
#include <unordered_map>
#include <vector>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
@@ -75,6 +77,8 @@
static bool main_thread_valid;
static uint64_t main_thread_id;
+static uint64_t fdevent_id;
+
static bool run_needs_flush = false;
static auto& run_queue_notify_fd = *new unique_fd();
static auto& run_queue_mutex = *new std::mutex();
@@ -111,7 +115,8 @@
if (fde->state & FDE_ERROR) {
state += "E";
}
- return android::base::StringPrintf("(fdevent %d %s)", fde->fd.get(), state.c_str());
+ return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(),
+ state.c_str());
}
void fdevent_install(fdevent* fde, int fd, fd_func func, void* arg) {
@@ -125,6 +130,7 @@
CHECK_GE(fd, 0);
fdevent* fde = new fdevent();
+ fde->id = fdevent_id++;
fde->state = FDE_ACTIVE;
fde->fd.reset(fd);
fde->func = func;
@@ -352,10 +358,56 @@
}
}
+static void fdevent_check_spin(uint64_t cycle) {
+ // Check to see if we're spinning because we forgot about an fdevent
+ // by keeping track of how long fdevents have been continuously pending.
+ struct SpinCheck {
+ fdevent* fde;
+ std::chrono::steady_clock::time_point timestamp;
+ uint64_t cycle;
+ };
+ static auto& g_continuously_pending = *new std::unordered_map<uint64_t, SpinCheck>();
+
+ auto now = std::chrono::steady_clock::now();
+ for (auto* fde : g_pending_list) {
+ auto it = g_continuously_pending.find(fde->id);
+ if (it == g_continuously_pending.end()) {
+ g_continuously_pending[fde->id] =
+ SpinCheck{.fde = fde, .timestamp = now, .cycle = cycle};
+ } else {
+ it->second.cycle = cycle;
+ }
+ }
+
+ for (auto it = g_continuously_pending.begin(); it != g_continuously_pending.end();) {
+ if (it->second.cycle != cycle) {
+ it = g_continuously_pending.erase(it);
+ } else {
+ // Use an absurdly long window, since all we really care about is
+ // getting a bugreport eventually.
+ if (now - it->second.timestamp > std::chrono::minutes(5)) {
+ LOG(FATAL_WITHOUT_ABORT) << "detected spin in fdevent: " << dump_fde(it->second.fde);
+#if defined(__linux__)
+ int fd = it->second.fde->fd.get();
+ std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
+ std::string path;
+ if (!android::base::Readlink(fd_path, &path)) {
+ PLOG(FATAL_WITHOUT_ABORT) << "readlink of fd " << fd << " failed";
+ }
+ LOG(FATAL_WITHOUT_ABORT) << "fd " << fd << " = " << path;
+#endif
+ abort();
+ }
+ ++it;
+ }
+ }
+}
+
void fdevent_loop() {
set_main_thread();
fdevent_run_setup();
+ uint64_t cycle = 0;
while (true) {
if (terminate_loop) {
return;
@@ -365,6 +417,8 @@
fdevent_process();
+ fdevent_check_spin(cycle++);
+
while (!g_pending_list.empty()) {
fdevent* fde = g_pending_list.front();
g_pending_list.pop_front();
diff --git a/adb/fdevent.h b/adb/fdevent.h
index 69c4072..d501b86 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -32,8 +32,7 @@
typedef void (*fd_func)(int fd, unsigned events, void *userdata);
struct fdevent {
- fdevent* next = nullptr;
- fdevent* prev = nullptr;
+ uint64_t id;
unique_fd fd;
int force_eof = 0;
diff --git a/adb/services.cpp b/adb/services.cpp
index a757d90..b613d83 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -181,6 +181,29 @@
kick_transport(t);
}
+static void spin_service(int fd, void*) {
+ unique_fd sfd(fd);
+
+ if (!__android_log_is_debuggable()) {
+ WriteFdExactly(sfd.get(), "refusing to spin on non-debuggable build\n");
+ return;
+ }
+
+ // A service that creates an fdevent that's always pending, and then ignores it.
+ unique_fd pipe_read, pipe_write;
+ if (!Pipe(&pipe_read, &pipe_write)) {
+ WriteFdExactly(sfd.get(), "failed to create pipe\n");
+ return;
+ }
+
+ fdevent_run_on_main_thread([fd = pipe_read.release()]() {
+ fdevent* fde = fdevent_create(fd, [](int, unsigned, void*) {}, nullptr);
+ fdevent_add(fde, FDE_READ);
+ });
+
+ WriteFdExactly(sfd.get(), "spinning\n");
+}
+
int reverse_service(const char* command, atransport* transport) {
int s[2];
if (adb_socketpair(s)) {
@@ -328,6 +351,8 @@
reinterpret_cast<void*>(1));
} else if (!strcmp(name, "reconnect")) {
ret = create_service_thread("reconnect", reconnect_service, transport);
+ } else if (!strcmp(name, "spin")) {
+ ret = create_service_thread("spin", spin_service, nullptr);
#endif
}
if (ret >= 0) {
diff --git a/adb/transport.h b/adb/transport.h
index ae9cc02..cb20615 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -92,6 +92,8 @@
std::string transport_name_;
ReadCallback read_callback_;
ErrorCallback error_callback_;
+
+ static std::unique_ptr<Connection> FromFd(unique_fd fd);
};
// Abstraction for a blocking packet transport.
diff --git a/adb/transport_benchmark.cpp b/adb/transport_benchmark.cpp
index da24aa7..022808f 100644
--- a/adb/transport_benchmark.cpp
+++ b/adb/transport_benchmark.cpp
@@ -24,13 +24,19 @@
#include "sysdeps.h"
#include "transport.h"
-#define ADB_CONNECTION_BENCHMARK(benchmark_name, ...) \
- BENCHMARK_TEMPLATE(benchmark_name, FdConnection, ##__VA_ARGS__) \
- ->Arg(1) \
- ->Arg(16384) \
- ->Arg(MAX_PAYLOAD) \
+#define ADB_CONNECTION_BENCHMARK(benchmark_name, ...) \
+ BENCHMARK_TEMPLATE(benchmark_name, FdConnection, ##__VA_ARGS__) \
+ ->Arg(1) \
+ ->Arg(16384) \
+ ->Arg(MAX_PAYLOAD) \
+ ->UseRealTime(); \
+ BENCHMARK_TEMPLATE(benchmark_name, NonblockingFdConnection, ##__VA_ARGS__) \
+ ->Arg(1) \
+ ->Arg(16384) \
+ ->Arg(MAX_PAYLOAD) \
->UseRealTime()
+struct NonblockingFdConnection;
template <typename ConnectionType>
std::unique_ptr<Connection> MakeConnection(unique_fd fd);
@@ -40,6 +46,11 @@
return std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection));
}
+template <>
+std::unique_ptr<Connection> MakeConnection<NonblockingFdConnection>(unique_fd fd) {
+ return Connection::FromFd(std::move(fd));
+}
+
template <typename ConnectionType>
void BM_Connection_Unidirectional(benchmark::State& state) {
int fds[2];
diff --git a/adb/transport_fd.cpp b/adb/transport_fd.cpp
new file mode 100644
index 0000000..85f3c52
--- /dev/null
+++ b/adb/transport_fd.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2018 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 <stdint.h>
+
+#include <deque>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
+
+#include "adb_unique_fd.h"
+#include "adb_utils.h"
+#include "sysdeps.h"
+#include "sysdeps/memory.h"
+#include "transport.h"
+#include "types.h"
+
+static void CreateWakeFds(unique_fd* read, unique_fd* write) {
+ // TODO: eventfd on linux?
+ int wake_fds[2];
+ int rc = adb_socketpair(wake_fds);
+ set_file_block_mode(wake_fds[0], false);
+ set_file_block_mode(wake_fds[1], false);
+ CHECK_EQ(0, rc);
+ *read = unique_fd(wake_fds[0]);
+ *write = unique_fd(wake_fds[1]);
+}
+
+struct NonblockingFdConnection : public Connection {
+ NonblockingFdConnection(unique_fd fd) : started_(false), fd_(std::move(fd)) {
+ set_file_block_mode(fd_.get(), false);
+ CreateWakeFds(&wake_fd_read_, &wake_fd_write_);
+ }
+
+ void SetRunning(bool value) {
+ std::lock_guard<std::mutex> lock(run_mutex_);
+ running_ = value;
+ }
+
+ bool IsRunning() {
+ std::lock_guard<std::mutex> lock(run_mutex_);
+ return running_;
+ }
+
+ void Run(std::string* error) {
+ SetRunning(true);
+ while (IsRunning()) {
+ adb_pollfd pfds[2] = {
+ {.fd = fd_.get(), .events = POLLIN},
+ {.fd = wake_fd_read_.get(), .events = POLLIN},
+ };
+
+ {
+ std::lock_guard<std::mutex> lock(this->write_mutex_);
+ if (!writable_) {
+ pfds[0].events |= POLLOUT;
+ }
+ }
+
+ int rc = adb_poll(pfds, 2, -1);
+ if (rc == -1) {
+ *error = android::base::StringPrintf("poll failed: %s", strerror(errno));
+ return;
+ } else if (rc == 0) {
+ LOG(FATAL) << "poll timed out with an infinite timeout?";
+ }
+
+ if (pfds[0].revents) {
+ if ((pfds[0].revents & POLLOUT)) {
+ std::lock_guard<std::mutex> lock(this->write_mutex_);
+ WriteResult result = DispatchWrites();
+ switch (result) {
+ case WriteResult::Error:
+ *error = "write failed";
+ return;
+
+ case WriteResult::Completed:
+ writable_ = true;
+ break;
+
+ case WriteResult::TryAgain:
+ break;
+ }
+ }
+
+ if (pfds[0].revents & POLLIN) {
+ // TODO: Should we be getting blocks from a free list?
+ auto block = std::make_unique<IOVector::block_type>(MAX_PAYLOAD);
+ rc = adb_read(fd_.get(), &(*block)[0], block->size());
+ if (rc == -1) {
+ *error = std::string("read failed: ") + strerror(errno);
+ return;
+ } else if (rc == 0) {
+ *error = "read failed: EOF";
+ return;
+ }
+ block->resize(rc);
+ read_buffer_.append(std::move(block));
+
+ if (!read_header_ && read_buffer_.size() >= sizeof(amessage)) {
+ auto header_buf = read_buffer_.take_front(sizeof(amessage)).coalesce();
+ CHECK_EQ(sizeof(amessage), header_buf.size());
+ read_header_ = std::make_unique<amessage>();
+ memcpy(read_header_.get(), header_buf.data(), sizeof(amessage));
+ }
+
+ if (read_header_ && read_buffer_.size() >= read_header_->data_length) {
+ auto data_chain = read_buffer_.take_front(read_header_->data_length);
+
+ // TODO: Make apacket carry around a IOVector instead of coalescing.
+ auto payload = data_chain.coalesce<apacket::payload_type>();
+ auto packet = std::make_unique<apacket>();
+ packet->msg = *read_header_;
+ packet->payload = std::move(payload);
+ read_header_ = nullptr;
+ read_callback_(this, std::move(packet));
+ }
+ }
+ }
+
+ if (pfds[1].revents) {
+ uint64_t buf;
+ rc = adb_read(wake_fd_read_.get(), &buf, sizeof(buf));
+ CHECK_EQ(static_cast<int>(sizeof(buf)), rc);
+
+ // We were woken up either to add POLLOUT to our events, or to exit.
+ // Do nothing.
+ }
+ }
+ }
+
+ void Start() override final {
+ if (started_.exchange(true)) {
+ LOG(FATAL) << "Connection started multiple times?";
+ }
+
+ thread_ = std::thread([this]() {
+ std::string error = "connection closed";
+ Run(&error);
+ this->error_callback_(this, error);
+ });
+ }
+
+ void Stop() override final {
+ SetRunning(false);
+ WakeThread();
+ thread_.join();
+ }
+
+ void WakeThread() {
+ uint64_t buf = 0;
+ if (TEMP_FAILURE_RETRY(adb_write(wake_fd_write_.get(), &buf, sizeof(buf))) != sizeof(buf)) {
+ LOG(FATAL) << "failed to wake up thread";
+ }
+ }
+
+ enum class WriteResult {
+ Error,
+ Completed,
+ TryAgain,
+ };
+
+ WriteResult DispatchWrites() REQUIRES(write_mutex_) {
+ CHECK(!write_buffer_.empty());
+ if (!writable_) {
+ return WriteResult::TryAgain;
+ }
+
+ auto iovs = write_buffer_.iovecs();
+ ssize_t rc = adb_writev(fd_.get(), iovs.data(), iovs.size());
+ if (rc == -1) {
+ return WriteResult::Error;
+ } else if (rc == 0) {
+ errno = 0;
+ return WriteResult::Error;
+ }
+
+ // TODO: Implement a more efficient drop_front?
+ write_buffer_.take_front(rc);
+ if (write_buffer_.empty()) {
+ return WriteResult::Completed;
+ }
+
+ // There's data left in the range, which means our write returned early.
+ return WriteResult::TryAgain;
+ }
+
+ bool Write(std::unique_ptr<apacket> packet) final {
+ std::lock_guard<std::mutex> lock(write_mutex_);
+ const char* header_begin = reinterpret_cast<const char*>(&packet->msg);
+ const char* header_end = header_begin + sizeof(packet->msg);
+ auto header_block = std::make_unique<IOVector::block_type>(header_begin, header_end);
+ write_buffer_.append(std::move(header_block));
+ if (!packet->payload.empty()) {
+ write_buffer_.append(std::make_unique<IOVector::block_type>(std::move(packet->payload)));
+ }
+ return DispatchWrites() != WriteResult::Error;
+ }
+
+ std::thread thread_;
+
+ std::atomic<bool> started_;
+ std::mutex run_mutex_;
+ bool running_ GUARDED_BY(run_mutex_);
+
+ std::unique_ptr<amessage> read_header_;
+ IOVector read_buffer_;
+
+ unique_fd fd_;
+ unique_fd wake_fd_read_;
+ unique_fd wake_fd_write_;
+
+ std::mutex write_mutex_;
+ bool writable_ GUARDED_BY(write_mutex_) = true;
+ IOVector write_buffer_ GUARDED_BY(write_mutex_);
+
+ IOVector incoming_queue_;
+};
+
+std::unique_ptr<Connection> Connection::FromFd(unique_fd fd) {
+ return std::make_unique<NonblockingFdConnection>(std::move(fd));
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 70b6a3e..478b8d0 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -201,6 +201,7 @@
$$(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $$@
$$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $$@
$$(hide) sed -i -e 's?%VNDK_VER%?$$(PRIVATE_VNDK_VERSION)?g' $$@
+ $$(hide) sed -i -e 's?%PRODUCT%?$$(TARGET_COPY_OUT_PRODUCT)?g' $$@
llndk_libraries_list :=
vndksp_libraries_list :=
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index eebad2b..42dc7ab 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -7,7 +7,7 @@
# absolute path of an executable is selected.
dir.system = /system/bin/
dir.system = /system/xbin/
-dir.system = /product/bin/
+dir.system = /%PRODUCT%/bin/
dir.vendor = /odm/bin/
dir.vendor = /vendor/bin/
@@ -39,7 +39,7 @@
namespace.default.isolated = true
namespace.default.search.paths = /system/${LIB}
-namespace.default.search.paths += /product/${LIB}
+namespace.default.search.paths += /%PRODUCT%/${LIB}
# We can't have entire /system/${LIB} as permitted paths because doing so
# makes it possible to load libs in /system/${LIB}/vndk* directories by
@@ -51,8 +51,7 @@
namespace.default.permitted.paths = /system/${LIB}/drm
namespace.default.permitted.paths += /system/${LIB}/extractors
namespace.default.permitted.paths += /system/${LIB}/hw
-namespace.default.permitted.paths += /product/${LIB}
-namespace.default.permitted.paths += /system/product/${LIB}
+namespace.default.permitted.paths += /%PRODUCT%/${LIB}
# These are where odex files are located. libart has to be able to dlopen the files
namespace.default.permitted.paths += /system/framework
namespace.default.permitted.paths += /system/app
@@ -64,12 +63,9 @@
namespace.default.permitted.paths += /odm/app
namespace.default.permitted.paths += /odm/priv-app
namespace.default.permitted.paths += /oem/app
-namespace.default.permitted.paths += /product/framework
-namespace.default.permitted.paths += /product/app
-namespace.default.permitted.paths += /product/priv-app
-namespace.default.permitted.paths += /system/product/framework
-namespace.default.permitted.paths += /system/product/app
-namespace.default.permitted.paths += /system/product/priv-app
+namespace.default.permitted.paths += /%PRODUCT%/framework
+namespace.default.permitted.paths += /%PRODUCT%/app
+namespace.default.permitted.paths += /%PRODUCT%/priv-app
namespace.default.permitted.paths += /data
namespace.default.permitted.paths += /mnt/expand
@@ -92,14 +88,10 @@
namespace.default.asan.permitted.paths += /odm/app
namespace.default.asan.permitted.paths += /odm/priv-app
namespace.default.asan.permitted.paths += /oem/app
-namespace.default.asan.permitted.paths += /product/${LIB}
-namespace.default.asan.permitted.paths += /product/framework
-namespace.default.asan.permitted.paths += /product/app
-namespace.default.asan.permitted.paths += /product/priv-app
-namespace.default.asan.permitted.paths += /system/product/${LIB}
-namespace.default.asan.permitted.paths += /system/product/framework
-namespace.default.asan.permitted.paths += /system/product/app
-namespace.default.asan.permitted.paths += /system/product/priv-app
+namespace.default.asan.permitted.paths += /%PRODUCT%/${LIB}
+namespace.default.asan.permitted.paths += /%PRODUCT%/framework
+namespace.default.asan.permitted.paths += /%PRODUCT%/app
+namespace.default.asan.permitted.paths += /%PRODUCT%/priv-app
namespace.default.asan.permitted.paths += /mnt/expand
###############################################################################
@@ -335,7 +327,7 @@
namespace.system.isolated = false
namespace.system.search.paths = /system/${LIB}
-namespace.system.search.paths += /product/${LIB}
+namespace.system.search.paths += /%PRODUCT%/${LIB}
namespace.system.asan.search.paths = /data/asan/system/${LIB}
namespace.system.asan.search.paths += /system/${LIB}
@@ -353,4 +345,4 @@
[postinstall]
namespace.default.isolated = false
namespace.default.search.paths = /system/${LIB}
-namespace.default.search.paths += /product/${LIB}
+namespace.default.search.paths += /%PRODUCT%/${LIB}