Merge "Fix memory order and race bugs in Refbase.h & RefBase.cpp"
diff --git a/adb/Android.mk b/adb/Android.mk
index 6693619..6188184 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -58,6 +58,7 @@
LIBADB_TEST_SRCS := \
adb_io_test.cpp \
+ adb_listeners_test.cpp \
adb_utils_test.cpp \
fdevent_test.cpp \
socket_test.cpp \
@@ -207,24 +208,6 @@
include $(BUILD_HOST_NATIVE_TEST)
-# adb device tracker (used by ddms) test tool
-# =========================================================
-
-ifeq ($(HOST_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_MODULE := adb_device_tracker_test
-LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
-LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
-LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
-LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
-LOCAL_SRC_FILES := test_track_devices.cpp
-LOCAL_SANITIZE := $(adb_host_sanitize)
-LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_STATIC_LIBRARIES := libadb libcrypto_utils_static libcrypto_static libcutils
-LOCAL_LDLIBS += -lrt -ldl -lpthread
-include $(BUILD_HOST_EXECUTABLE)
-endif
-
# adb host tool
# =========================================================
include $(CLEAR_VARS)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 49d2936..3f14f1a 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -65,21 +65,34 @@
void fatal(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "error: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
+ char buf[1024];
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+
+#if ADB_HOST
+ fprintf(stderr, "error: %s\n", buf);
+#else
+ LOG(ERROR) << "error: " << buf;
+#endif
+
va_end(ap);
- exit(-1);
+ abort();
}
void fatal_errno(const char* fmt, ...) {
+ int err = errno;
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "error: %s: ", strerror(errno));
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
+ char buf[1024];
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+
+#if ADB_HOST
+ fprintf(stderr, "error: %s: %s\n", buf, strerror(err));
+#else
+ LOG(ERROR) << "error: " << buf << ": " << strerror(err);
+#endif
+
va_end(ap);
- exit(-1);
+ abort();
}
apacket* get_apacket(void)
@@ -955,18 +968,25 @@
std::string error;
InstallStatus r;
+ int resolved_tcp_port = 0;
if (kill_forward) {
r = remove_listener(pieces[0].c_str(), transport);
} else {
- r = install_listener(pieces[0], pieces[1].c_str(), transport,
- no_rebind, &error);
+ r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind,
+ &resolved_tcp_port, &error);
}
if (r == INSTALL_STATUS_OK) {
#if ADB_HOST
- /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+ // On the host: 1st OKAY is connect, 2nd OKAY is status.
SendOkay(reply_fd);
#endif
SendOkay(reply_fd);
+
+ // If a TCP port was resolved, send the actual port number back.
+ if (resolved_tcp_port != 0) {
+ SendProtocolString(reply_fd, android::base::StringPrintf("%d", resolved_tcp_port));
+ }
+
return 1;
}
diff --git a/adb/adb.h b/adb/adb.h
index ea20800..cb38e61 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -50,7 +50,7 @@
std::string adb_version();
// Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 36
+#define ADB_SERVER_VERSION 37
class atransport;
struct usb_handle;
@@ -116,29 +116,6 @@
kCsUnauthorized,
};
-/* A listener is an entity which binds to a local port
-** and, upon receiving a connection on that port, creates
-** an asocket to connect the new local connection to a
-** specific remote service.
-**
-** TODO: some listeners read from the new connection to
-** determine what exact service to connect to on the far
-** side.
-*/
-struct alistener
-{
- alistener *next;
- alistener *prev;
-
- fdevent fde;
- int fd;
-
- char *local_name;
- char *connect_to;
- atransport *transport;
- adisconnect disconnect;
-};
-
void print_packet(const char *label, apacket *p);
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index e8c2338..f54603c 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -20,18 +20,55 @@
#include <stdlib.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <cutils/sockets.h>
#include "sysdeps.h"
#include "transport.h"
-int gListenAll = 0; /* Not static because it is used in commandline.c. */
+// Not static because it is used in commandline.c.
+int gListenAll = 0;
-static alistener listener_list = {
- .next = &listener_list,
- .prev = &listener_list,
+// A listener is an entity which binds to a local port and, upon receiving a connection on that
+// port, creates an asocket to connect the new local connection to a specific remote service.
+//
+// TODO: some listeners read from the new connection to determine what exact service to connect to
+// on the far side.
+class alistener {
+ public:
+ alistener(const std::string& _local_name, const std::string& _connect_to);
+ ~alistener();
+
+ fdevent fde;
+ int fd = -1;
+
+ std::string local_name;
+ std::string connect_to;
+ atransport* transport = nullptr;
+ adisconnect disconnect;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(alistener);
};
+alistener::alistener(const std::string& _local_name, const std::string& _connect_to)
+ : local_name(_local_name), connect_to(_connect_to) {
+}
+
+alistener::~alistener() {
+ // Closes the corresponding fd.
+ fdevent_remove(&fde);
+
+ if (transport) {
+ transport->RemoveDisconnect(&disconnect);
+ }
+}
+
+// listener_list retains ownership of all created alistener objects. Removing an alistener from
+// this list will cause it to be deleted.
+typedef std::list<std::unique_ptr<alistener>> ListenerList;
+static ListenerList& listener_list = *new ListenerList();
+
static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
if (ev & FDE_READ) {
sockaddr_storage ss;
@@ -73,7 +110,7 @@
s = create_local_socket(fd);
if (s) {
s->transport = listener->transport;
- connect_to_remote(s, listener->connect_to);
+ connect_to_remote(s, listener->connect_to.c_str());
return;
}
@@ -81,66 +118,63 @@
}
}
-static void free_listener(alistener* l)
-{
- if (l->next) {
- l->next->prev = l->prev;
- l->prev->next = l->next;
- l->next = l->prev = l;
- }
-
- // closes the corresponding fd
- fdevent_remove(&l->fde);
-
- if (l->local_name)
- free((char*)l->local_name);
-
- if (l->connect_to)
- free((char*)l->connect_to);
-
- if (l->transport) {
- l->transport->RemoveDisconnect(&l->disconnect);
- }
- free(l);
-}
-
+// Called as a transport disconnect function. |arg| is the raw alistener*.
static void listener_disconnect(void* arg, atransport*) {
- alistener* listener = reinterpret_cast<alistener*>(arg);
- listener->transport = nullptr;
- free_listener(listener);
-}
-
-static int local_name_to_fd(const char* name, std::string* error) {
- if (!strncmp("tcp:", name, 4)) {
- int port = atoi(name + 4);
- if (gListenAll > 0) {
- return network_inaddr_any_server(port, SOCK_STREAM, error);
- } else {
- return network_loopback_server(port, SOCK_STREAM, error);
+ for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
+ if (iter->get() == arg) {
+ (*iter)->transport = nullptr;
+ listener_list.erase(iter);
+ return;
}
}
+}
+
+int local_name_to_fd(alistener* listener, int* resolved_tcp_port, std::string* error) {
+ if (android::base::StartsWith(listener->local_name, "tcp:")) {
+ int requested_port = atoi(&listener->local_name[4]);
+ int sock = -1;
+ if (gListenAll > 0) {
+ sock = network_inaddr_any_server(requested_port, SOCK_STREAM, error);
+ } else {
+ sock = network_loopback_server(requested_port, SOCK_STREAM, error);
+ }
+
+ // If the caller requested port 0, update the listener name with the resolved port.
+ if (sock >= 0 && requested_port == 0) {
+ int local_port = adb_socket_get_local_port(sock);
+ if (local_port > 0) {
+ listener->local_name = android::base::StringPrintf("tcp:%d", local_port);
+ if (resolved_tcp_port != nullptr) {
+ *resolved_tcp_port = local_port;
+ }
+ }
+ }
+
+ return sock;
+ }
#if !defined(_WIN32) // No Unix-domain sockets on Windows.
- // It's nonsensical to support the "reserved" space on the adb host side
- if (!strncmp(name, "local:", 6)) {
- return network_local_server(name + 6,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
- } else if (!strncmp(name, "localabstract:", 14)) {
- return network_local_server(name + 14,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
- } else if (!strncmp(name, "localfilesystem:", 16)) {
- return network_local_server(name + 16,
- ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM, error);
+ // It's nonsensical to support the "reserved" space on the adb host side.
+ if (android::base::StartsWith(listener->local_name, "local:")) {
+ return network_local_server(&listener->local_name[6], ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+ SOCK_STREAM, error);
+ } else if (android::base::StartsWith(listener->local_name, "localabstract:")) {
+ return network_local_server(&listener->local_name[14], ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+ SOCK_STREAM, error);
+ } else if (android::base::StartsWith(listener->local_name, "localfilesystem:")) {
+ return network_local_server(&listener->local_name[16], ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
+ SOCK_STREAM, error);
}
#endif
- *error = android::base::StringPrintf("unknown local portname '%s'", name);
+ *error = android::base::StringPrintf("unknown local portname '%s'",
+ listener->local_name.c_str());
return -1;
}
// Write the list of current listeners (network redirections) into a string.
std::string format_listeners() {
std::string result;
- for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
+ for (auto& l : listener_list) {
// Ignore special listeners like those for *smartsocket*
if (l->connect_to[0] == '*') {
continue;
@@ -149,65 +183,51 @@
// Entries from "adb reverse" have no serial.
android::base::StringAppendF(&result, "%s %s %s\n",
l->transport->serial ? l->transport->serial : "(reverse)",
- l->local_name, l->connect_to);
+ l->local_name.c_str(), l->connect_to.c_str());
}
return result;
}
-InstallStatus remove_listener(const char *local_name, atransport* transport) {
- alistener *l;
-
- for (l = listener_list.next; l != &listener_list; l = l->next) {
- if (!strcmp(local_name, l->local_name)) {
- free_listener(l);
+InstallStatus remove_listener(const char* local_name, atransport* transport) {
+ for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
+ if (local_name == (*iter)->local_name) {
+ listener_list.erase(iter);
return INSTALL_STATUS_OK;
}
}
return INSTALL_STATUS_LISTENER_NOT_FOUND;
}
-void remove_all_listeners(void)
-{
- alistener *l, *l_next;
- for (l = listener_list.next; l != &listener_list; l = l_next) {
- l_next = l->next;
+void remove_all_listeners() {
+ auto iter = listener_list.begin();
+ while (iter != listener_list.end()) {
// Never remove smart sockets.
- if (l->connect_to[0] == '*')
- continue;
- free_listener(l);
+ if ((*iter)->connect_to[0] == '*') {
+ ++iter;
+ } else {
+ iter = listener_list.erase(iter);
+ }
}
}
-InstallStatus install_listener(const std::string& local_name,
- const char *connect_to,
- atransport* transport,
- int no_rebind,
- std::string* error)
-{
- for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
+InstallStatus install_listener(const std::string& local_name, const char* connect_to,
+ atransport* transport, int no_rebind, int* resolved_tcp_port,
+ std::string* error) {
+ for (auto& l : listener_list) {
if (local_name == l->local_name) {
- char* cto;
-
- /* can't repurpose a smartsocket */
+ // Can't repurpose a smartsocket.
if(l->connect_to[0] == '*') {
*error = "cannot repurpose smartsocket";
return INSTALL_STATUS_INTERNAL_ERROR;
}
- /* can't repurpose a listener if 'no_rebind' is true */
+ // Can't repurpose a listener if 'no_rebind' is true.
if (no_rebind) {
*error = "cannot rebind";
return INSTALL_STATUS_CANNOT_REBIND;
}
- cto = strdup(connect_to);
- if(cto == 0) {
- *error = "cannot duplicate string";
- return INSTALL_STATUS_INTERNAL_ERROR;
- }
-
- free((void*) l->connect_to);
- l->connect_to = cto;
+ l->connect_to = connect_to;
if (l->transport != transport) {
l->transport->RemoveDisconnect(&l->disconnect);
l->transport = transport;
@@ -217,54 +237,29 @@
}
}
- alistener* listener = reinterpret_cast<alistener*>(
- calloc(1, sizeof(alistener)));
- if (listener == nullptr) {
- goto nomem;
- }
+ std::unique_ptr<alistener> listener(new alistener(local_name, connect_to));
- listener->local_name = strdup(local_name.c_str());
- if (listener->local_name == nullptr) {
- goto nomem;
- }
-
- listener->connect_to = strdup(connect_to);
- if (listener->connect_to == nullptr) {
- goto nomem;
- }
-
- listener->fd = local_name_to_fd(listener->local_name, error);
+ listener->fd = local_name_to_fd(listener.get(), resolved_tcp_port, error);
if (listener->fd < 0) {
- free(listener->local_name);
- free(listener->connect_to);
- free(listener);
return INSTALL_STATUS_CANNOT_BIND;
}
close_on_exec(listener->fd);
- if (!strcmp(listener->connect_to, "*smartsocket*")) {
- fdevent_install(&listener->fde, listener->fd, ss_listener_event_func,
- listener);
+ if (listener->connect_to == "*smartsocket*") {
+ fdevent_install(&listener->fde, listener->fd, ss_listener_event_func, listener.get());
} else {
- fdevent_install(&listener->fde, listener->fd, listener_event_func,
- listener);
+ fdevent_install(&listener->fde, listener->fd, listener_event_func, listener.get());
}
fdevent_set(&listener->fde, FDE_READ);
- listener->next = &listener_list;
- listener->prev = listener_list.prev;
- listener->next->prev = listener;
- listener->prev->next = listener;
listener->transport = transport;
if (transport) {
- listener->disconnect.opaque = listener;
+ listener->disconnect.opaque = listener.get();
listener->disconnect.func = listener_disconnect;
transport->AddDisconnect(&listener->disconnect);
}
- return INSTALL_STATUS_OK;
-nomem:
- fatal("cannot allocate listener");
- return INSTALL_STATUS_INTERNAL_ERROR;
+ listener_list.push_back(std::move(listener));
+ return INSTALL_STATUS_OK;
}
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index fa98eed..8eba00a 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -21,6 +21,8 @@
#include <string>
+#include <android-base/macros.h>
+
// error/status codes for install_listener.
enum InstallStatus {
INSTALL_STATUS_OK = 0,
@@ -30,10 +32,8 @@
INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
};
-InstallStatus install_listener(const std::string& local_name,
- const char* connect_to,
- atransport* transport,
- int no_rebind,
+InstallStatus install_listener(const std::string& local_name, const char* connect_to,
+ atransport* transport, int no_rebind, int* resolved_tcp_port,
std::string* error);
std::string format_listeners();
diff --git a/adb/adb_listeners_test.cpp b/adb/adb_listeners_test.cpp
new file mode 100644
index 0000000..b697769
--- /dev/null
+++ b/adb/adb_listeners_test.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 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 "adb_listeners.h"
+
+#include <gtest/gtest.h>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include "fdevent.h"
+#include "sysdeps.h"
+#include "transport.h"
+
+// Returns true if the given listener is present in format_listeners(). Empty parameters will
+// be ignored.
+static bool listener_is_installed(const std::string& serial, const std::string& source,
+ const std::string& dest) {
+ // format_listeners() gives lines of "<serial> <source> <dest>\n".
+ for (const std::string& line : android::base::Split(format_listeners(), "\n")) {
+ std::vector<std::string> info = android::base::Split(line, " ");
+ if (info.size() == 3 &&
+ (serial.empty() || info[0] == serial) &&
+ (source.empty() || info[1] == source) &&
+ (dest.empty() || info[2] == dest)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+class AdbListenersTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ // We don't need an fdevent loop, but adding/removing listeners must be done from the
+ // fdevent thread if one exists. Since previously run tests may have created an fdevent
+ // thread, we need to reset to prevent the thread check.
+ fdevent_reset();
+ }
+
+ void TearDown() override {
+ // Clean up any listeners that may have been installed.
+ remove_all_listeners();
+
+ // Make sure we didn't leave any dangling events.
+ ASSERT_EQ(0u, fdevent_installed_count());
+ }
+
+ protected:
+ atransport transport_;
+};
+
+TEST_F(AdbListenersTest, test_install_listener) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_rebind) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9001", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9001"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_no_rebind) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, true, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_CANNOT_REBIND,
+ install_listener("tcp:9000", "tcp:9001", &transport_, true, nullptr, &error));
+ ASSERT_FALSE(error.empty());
+
+ ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_tcp_port_0) {
+ int port = 0;
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:0", "tcp:9000", &transport_, true, &port, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_TRUE(listener_is_installed("", android::base::StringPrintf("tcp:%d", port), "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_remove_listener) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_OK, remove_listener("tcp:9000", &transport_));
+ ASSERT_TRUE(format_listeners().empty());
+}
+
+TEST_F(AdbListenersTest, test_remove_nonexistent_listener) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_LISTENER_NOT_FOUND, remove_listener("tcp:1", &transport_));
+ ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_remove_all_listeners) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9001", "tcp:9001", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ remove_all_listeners();
+ ASSERT_TRUE(format_listeners().empty());
+}
+
+TEST_F(AdbListenersTest, test_transport_disconnect) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9001", "tcp:9001", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ transport_.RunDisconnects();
+ ASSERT_TRUE(format_listeners().empty());
+}
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index d50f947..5206a99 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -41,7 +41,7 @@
};
#define VLOG_IS_ON(TAG) \
- ((adb_trace_mask & (1 << TAG)) != 0)
+ ((adb_trace_mask & (1 << (TAG))) != 0)
#define VLOG(TAG) \
if (LIKELY(!VLOG_IS_ON(TAG))) \
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 3333fc6..5d4755f 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -27,6 +27,7 @@
#include <algorithm>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -230,3 +231,26 @@
return true;
}
#endif
+
+bool forward_targets_are_valid(const std::string& source, const std::string& dest,
+ std::string* error) {
+ if (android::base::StartsWith(source, "tcp:")) {
+ // The source port may be 0 to allow the system to select an open port.
+ int port;
+ if (!android::base::ParseInt(&source[4], &port) || port < 0) {
+ *error = android::base::StringPrintf("Invalid source port: '%s'", &source[4]);
+ return false;
+ }
+ }
+
+ if (android::base::StartsWith(dest, "tcp:")) {
+ // The destination port must be > 0.
+ int port;
+ if (!android::base::ParseInt(&dest[4], &port) || port <= 0) {
+ *error = android::base::StringPrintf("Invalid destination port: '%s'", &dest[4]);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 89fcd66..22eb4d2 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -20,6 +20,7 @@
#include <string>
#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
void close_stdin();
@@ -43,7 +44,22 @@
extern int adb_close(int fd);
+// Given forward/reverse targets, returns true if they look sane. If an error is found, fills
+// |error| and returns false.
+// Currently this only checks "tcp:" targets. Additional checking could be added for other targets
+// if needed.
+bool forward_targets_are_valid(const std::string& source, const std::string& dest,
+ std::string* error);
+
// Helper to automatically close an FD when it goes out of scope.
+struct AdbCloser {
+ static void Close(int fd) {
+ adb_close(fd);
+ }
+};
+
+using unique_fd = android::base::unique_fd_impl<AdbCloser>;
+
class ScopedFd {
public:
ScopedFd() {
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index f1ebaa1..aabc5d7 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -149,3 +149,24 @@
ASSERT_EQ(0, adb_close(fd));
}
#endif
+
+TEST(adb_utils, test_forward_targets_are_valid) {
+ std::string error;
+
+ // Source port can be >= 0.
+ EXPECT_FALSE(forward_targets_are_valid("tcp:-1", "tcp:9000", &error));
+ EXPECT_TRUE(forward_targets_are_valid("tcp:0", "tcp:9000", &error));
+ EXPECT_TRUE(forward_targets_are_valid("tcp:8000", "tcp:9000", &error));
+
+ // Destination port must be >0.
+ EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:-1", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:0", &error));
+
+ // Port must be a number.
+ EXPECT_FALSE(forward_targets_are_valid("tcp:", "tcp:9000", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:a", "tcp:9000", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:22x", "tcp:9000", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:a", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:22x", &error));
+}
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 27b7109..65640ad 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -117,7 +117,7 @@
std::string error;
std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
- if (install_listener(local_name, "*smartsocket*", nullptr, 0, &error)) {
+ if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
fatal("could not install *smartsocket* listener: %s", error.c_str());
}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 45c6142..868470c 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -126,7 +126,7 @@
" <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
" adb forward <local> <remote> - forward socket connections\n"
" forward specs are one of: \n"
- " tcp:<port>\n"
+ " tcp:<port> (<local> may be \"tcp:0\" to pick any open port)\n"
" localabstract:<unix domain socket name>\n"
" localreserved:<unix domain socket name>\n"
" localfilesystem:<unix domain socket name>\n"
@@ -140,7 +140,7 @@
" adb reverse --list - list all reverse socket connections from device\n"
" adb reverse <remote> <local> - reverse socket connections\n"
" reverse specs are one of:\n"
- " tcp:<port>\n"
+ " tcp:<port> (<remote> may be \"tcp:0\" to pick any open port)\n"
" localabstract:<unix domain socket name>\n"
" localreserved:<unix domain socket name>\n"
" localfilesystem:<unix domain socket name>\n"
@@ -1719,7 +1719,7 @@
}
}
- std::string cmd;
+ std::string cmd, error;
if (strcmp(argv[0], "--list") == 0) {
if (argc != 1) return usage();
return adb_query_command(host_prefix + ":list-forward");
@@ -1733,14 +1733,37 @@
} else if (strcmp(argv[0], "--no-rebind") == 0) {
// forward --no-rebind <local> <remote>
if (argc != 3) return usage();
- cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
+ if (forward_targets_are_valid(argv[1], argv[2], &error)) {
+ cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
+ }
} else {
// forward <local> <remote>
if (argc != 2) return usage();
- cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
+ if (forward_targets_are_valid(argv[0], argv[1], &error)) {
+ cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
+ }
}
- return adb_command(cmd) ? 0 : 1;
+ if (!error.empty()) {
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return 1;
+ }
+
+ int fd = adb_connect(cmd, &error);
+ if (fd < 0 || !adb_status(fd, &error)) {
+ adb_close(fd);
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return 1;
+ }
+
+ // Server or device may optionally return a resolved TCP port number.
+ std::string resolved_port;
+ if (ReadProtocolString(fd, &resolved_port, &error) && !resolved_port.empty()) {
+ printf("%s\n", resolved_port.c_str());
+ }
+
+ ReadOrderlyShutdown(fd);
+ return 0;
}
/* do_sync_*() commands */
else if (!strcmp(argv[0], "ls")) {
@@ -1879,6 +1902,14 @@
else if (!strcmp(argv[0], "jdwp")) {
return adb_connect_command("jdwp");
}
+ else if (!strcmp(argv[0], "track-jdwp")) {
+ return adb_connect_command("track-jdwp");
+ }
+ else if (!strcmp(argv[0], "track-devices")) {
+ return adb_connect_command("host:track-devices");
+ }
+
+
/* "adb /?" is a common idiom under Windows */
else if (!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
help();
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 7f40b96..916bedf 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -142,10 +142,8 @@
std::string error;
std::string local_name =
android::base::StringPrintf("tcp:%d", server_port);
- if (install_listener(local_name, "*smartsocket*", nullptr, 0,
- &error)) {
- LOG(FATAL) << "Could not install *smartsocket* listener: "
- << error;
+ if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
+ LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
}
}
}
diff --git a/adb/mutex_list.h b/adb/mutex_list.h
index b59c9f2..4a188ee 100644
--- a/adb/mutex_list.h
+++ b/adb/mutex_list.h
@@ -8,7 +8,6 @@
#endif
ADB_MUTEX(basename_lock)
ADB_MUTEX(dirname_lock)
-ADB_MUTEX(socket_list_lock)
ADB_MUTEX(transport_lock)
#if ADB_HOST
ADB_MUTEX(local_transports_lock)
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index 3eeed34..374b468 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -412,7 +412,7 @@
for (const char* message : messages) {
WriteFdExactly(error_sfd->fd(), message);
}
- exit(-1);
+ abort();
}
if (make_pty_raw_) {
@@ -421,7 +421,7 @@
int saved_errno = errno;
WriteFdExactly(error_sfd->fd(), "tcgetattr failed: ");
WriteFdExactly(error_sfd->fd(), strerror(saved_errno));
- exit(-1);
+ abort();
}
cfmakeraw(&tattr);
@@ -429,7 +429,7 @@
int saved_errno = errno;
WriteFdExactly(error_sfd->fd(), "tcsetattr failed: ");
WriteFdExactly(error_sfd->fd(), strerror(saved_errno));
- exit(-1);
+ abort();
}
}
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index aecaba2..b2555d0 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -26,6 +26,7 @@
#include <unistd.h>
#include <algorithm>
+#include <mutex>
#include <string>
#include <vector>
@@ -35,17 +36,14 @@
#include "adb.h"
#include "adb_io.h"
+#include "sysdeps/mutex.h"
#include "transport.h"
-ADB_MUTEX_DEFINE( socket_list_lock );
-
-static void local_socket_close_locked(asocket *s);
-
+static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
static unsigned local_socket_next_id = 1;
static asocket local_socket_list = {
- .next = &local_socket_list,
- .prev = &local_socket_list,
+ .next = &local_socket_list, .prev = &local_socket_list,
};
/* the the list of currently closing local sockets.
@@ -53,62 +51,53 @@
** write to their fd.
*/
static asocket local_socket_closing_list = {
- .next = &local_socket_closing_list,
- .prev = &local_socket_closing_list,
+ .next = &local_socket_closing_list, .prev = &local_socket_closing_list,
};
// Parse the global list of sockets to find one with id |local_id|.
// If |peer_id| is not 0, also check that it is connected to a peer
// with id |peer_id|. Returns an asocket handle on success, NULL on failure.
-asocket *find_local_socket(unsigned local_id, unsigned peer_id)
-{
- asocket *s;
- asocket *result = NULL;
+asocket* find_local_socket(unsigned local_id, unsigned peer_id) {
+ asocket* s;
+ asocket* result = NULL;
- adb_mutex_lock(&socket_list_lock);
+ std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
- if (s->id != local_id)
+ if (s->id != local_id) {
continue;
+ }
if (peer_id == 0 || (s->peer && s->peer->id == peer_id)) {
result = s;
}
break;
}
- adb_mutex_unlock(&socket_list_lock);
return result;
}
-static void
-insert_local_socket(asocket* s, asocket* list)
-{
- s->next = list;
- s->prev = s->next->prev;
+static void insert_local_socket(asocket* s, asocket* list) {
+ s->next = list;
+ s->prev = s->next->prev;
s->prev->next = s;
s->next->prev = s;
}
-
-void install_local_socket(asocket *s)
-{
- adb_mutex_lock(&socket_list_lock);
+void install_local_socket(asocket* s) {
+ std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
s->id = local_socket_next_id++;
// Socket ids should never be 0.
- if (local_socket_next_id == 0)
- local_socket_next_id = 1;
+ if (local_socket_next_id == 0) {
+ fatal("local socket id overflow");
+ }
insert_local_socket(s, &local_socket_list);
-
- adb_mutex_unlock(&socket_list_lock);
}
-void remove_socket(asocket *s)
-{
+void remove_socket(asocket* s) {
// socket_list_lock should already be held
- if (s->prev && s->next)
- {
+ if (s->prev && s->next) {
s->prev->next = s->next;
s->next->prev = s->prev;
s->next = 0;
@@ -117,50 +106,47 @@
}
}
-void close_all_sockets(atransport *t)
-{
- asocket *s;
+void close_all_sockets(atransport* t) {
+ asocket* s;
- /* this is a little gross, but since s->close() *will* modify
- ** the list out from under you, your options are limited.
- */
- adb_mutex_lock(&socket_list_lock);
+ /* this is a little gross, but since s->close() *will* modify
+ ** the list out from under you, your options are limited.
+ */
+ std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
restart:
- for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
- if(s->transport == t || (s->peer && s->peer->transport == t)) {
- local_socket_close_locked(s);
+ for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+ if (s->transport == t || (s->peer && s->peer->transport == t)) {
+ s->close(s);
goto restart;
}
}
- adb_mutex_unlock(&socket_list_lock);
}
-static int local_socket_enqueue(asocket *s, apacket *p)
-{
+static int local_socket_enqueue(asocket* s, apacket* p) {
D("LS(%d): enqueue %d", s->id, p->len);
p->ptr = p->data;
- /* if there is already data queue'd, we will receive
- ** events when it's time to write. just add this to
- ** the tail
- */
- if(s->pkt_first) {
+ /* if there is already data queue'd, we will receive
+ ** events when it's time to write. just add this to
+ ** the tail
+ */
+ if (s->pkt_first) {
goto enqueue;
}
- /* write as much as we can, until we
- ** would block or there is an error/eof
- */
- while(p->len > 0) {
+ /* write as much as we can, until we
+ ** would block or there is an error/eof
+ */
+ while (p->len > 0) {
int r = adb_write(s->fd, p->ptr, p->len);
- if(r > 0) {
+ if (r > 0) {
p->len -= r;
p->ptr += r;
continue;
}
- if((r == 0) || (errno != EAGAIN)) {
- D( "LS(%d): not ready, errno=%d: %s", s->id, errno, strerror(errno) );
+ if ((r == 0) || (errno != EAGAIN)) {
+ D("LS(%d): not ready, errno=%d: %s", s->id, errno, strerror(errno));
put_apacket(p);
s->has_write_error = true;
s->close(s);
@@ -170,55 +156,46 @@
}
}
- if(p->len == 0) {
+ if (p->len == 0) {
put_apacket(p);
return 0; /* ready for more data */
}
enqueue:
p->next = 0;
- if(s->pkt_first) {
+ if (s->pkt_first) {
s->pkt_last->next = p;
} else {
s->pkt_first = p;
}
s->pkt_last = p;
- /* make sure we are notified when we can drain the queue */
+ /* make sure we are notified when we can drain the queue */
fdevent_add(&s->fde, FDE_WRITE);
return 1; /* not ready (backlog) */
}
-static void local_socket_ready(asocket *s)
-{
+static void local_socket_ready(asocket* s) {
/* far side is ready for data, pay attention to
readable events */
fdevent_add(&s->fde, FDE_READ);
}
-static void local_socket_close(asocket *s)
-{
- adb_mutex_lock(&socket_list_lock);
- local_socket_close_locked(s);
- adb_mutex_unlock(&socket_list_lock);
-}
-
// be sure to hold the socket list lock when calling this
-static void local_socket_destroy(asocket *s)
-{
+static void local_socket_destroy(asocket* s) {
apacket *p, *n;
int exit_on_close = s->exit_on_close;
D("LS(%d): destroying fde.fd=%d", s->id, s->fde.fd);
- /* IMPORTANT: the remove closes the fd
- ** that belongs to this socket
- */
+ /* IMPORTANT: the remove closes the fd
+ ** that belongs to this socket
+ */
fdevent_remove(&s->fde);
- /* dispose of any unwritten data */
- for(p = s->pkt_first; p; p = n) {
+ /* dispose of any unwritten data */
+ for (p = s->pkt_first; p; p = n) {
D("LS(%d): discarding %d bytes", s->id, p->len);
n = p->next;
put_apacket(p);
@@ -232,41 +209,35 @@
}
}
-
-static void local_socket_close_locked(asocket *s)
-{
- D("entered local_socket_close_locked. LS(%d) fd=%d", s->id, s->fd);
- if(s->peer) {
- D("LS(%d): closing peer. peer->id=%d peer->fd=%d",
- s->id, s->peer->id, s->peer->fd);
+static void local_socket_close(asocket* s) {
+ D("entered local_socket_close. LS(%d) fd=%d", s->id, s->fd);
+ std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
+ if (s->peer) {
+ D("LS(%d): closing peer. peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
/* Note: it's important to call shutdown before disconnecting from
* the peer, this ensures that remote sockets can still get the id
* of the local socket they're connected to, to send a CLOSE()
* protocol event. */
- if (s->peer->shutdown)
- s->peer->shutdown(s->peer);
- s->peer->peer = 0;
- // tweak to avoid deadlock
- if (s->peer->close == local_socket_close) {
- local_socket_close_locked(s->peer);
- } else {
- s->peer->close(s->peer);
+ if (s->peer->shutdown) {
+ s->peer->shutdown(s->peer);
}
- s->peer = 0;
+ s->peer->peer = nullptr;
+ s->peer->close(s->peer);
+ s->peer = nullptr;
}
- /* If we are already closing, or if there are no
- ** pending packets, destroy immediately
- */
+ /* If we are already closing, or if there are no
+ ** pending packets, destroy immediately
+ */
if (s->closing || s->has_write_error || s->pkt_first == NULL) {
- int id = s->id;
+ int id = s->id;
local_socket_destroy(s);
D("LS(%d): closed", id);
return;
}
- /* otherwise, put on the closing list
- */
+ /* otherwise, put on the closing list
+ */
D("LS(%d): closing", s->id);
s->closing = 1;
fdevent_del(&s->fde, FDE_READ);
@@ -276,8 +247,7 @@
CHECK_EQ(FDE_WRITE, s->fde.state & FDE_WRITE);
}
-static void local_socket_event_func(int fd, unsigned ev, void* _s)
-{
+static void local_socket_event_func(int fd, unsigned ev, void* _s) {
asocket* s = reinterpret_cast<asocket*>(_s);
D("LS(%d): event_func(fd=%d(==%d), ev=%04x)", s->id, s->fd, fd, ev);
@@ -334,10 +304,9 @@
s->peer->ready(s->peer);
}
-
if (ev & FDE_READ) {
- apacket *p = get_apacket();
- unsigned char *x = p->data;
+ apacket* p = get_apacket();
+ unsigned char* x = p->data;
const size_t max_payload = s->get_max_payload();
size_t avail = max_payload;
int r = 0;
@@ -345,8 +314,8 @@
while (avail > 0) {
r = adb_read(fd, x, avail);
- D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu",
- s->id, s->fd, r, r < 0 ? errno : 0, avail);
+ D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu", s->id, s->fd, r,
+ r < 0 ? errno : 0, avail);
if (r == -1) {
if (errno == EAGAIN) {
break;
@@ -361,8 +330,8 @@
is_eof = 1;
break;
}
- D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d",
- s->id, s->fd, r, is_eof, s->fde.force_eof);
+ D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d", s->id, s->fd, r, is_eof,
+ s->fde.force_eof);
if ((avail == max_payload) || (s->peer == 0)) {
put_apacket(p);
} else {
@@ -376,48 +345,48 @@
D("LS(%u): fd=%d post peer->enqueue(). r=%d", saved_id, saved_fd, r);
if (r < 0) {
- /* error return means they closed us as a side-effect
- ** and we must return immediately.
- **
- ** note that if we still have buffered packets, the
- ** socket will be placed on the closing socket list.
- ** this handler function will be called again
- ** to process FDE_WRITE events.
- */
+ /* error return means they closed us as a side-effect
+ ** and we must return immediately.
+ **
+ ** note that if we still have buffered packets, the
+ ** socket will be placed on the closing socket list.
+ ** this handler function will be called again
+ ** to process FDE_WRITE events.
+ */
return;
}
if (r > 0) {
- /* if the remote cannot accept further events,
- ** we disable notification of READs. They'll
- ** be enabled again when we get a call to ready()
- */
+ /* if the remote cannot accept further events,
+ ** we disable notification of READs. They'll
+ ** be enabled again when we get a call to ready()
+ */
fdevent_del(&s->fde, FDE_READ);
}
}
/* Don't allow a forced eof if data is still there */
if ((s->fde.force_eof && !r) || is_eof) {
- D(" closing because is_eof=%d r=%d s->fde.force_eof=%d",
- is_eof, r, s->fde.force_eof);
+ D(" closing because is_eof=%d r=%d s->fde.force_eof=%d", is_eof, r, s->fde.force_eof);
s->close(s);
return;
}
}
- if (ev & FDE_ERROR){
- /* this should be caught be the next read or write
- ** catching it here means we may skip the last few
- ** bytes of readable data.
- */
+ if (ev & FDE_ERROR) {
+ /* this should be caught be the next read or write
+ ** catching it here means we may skip the last few
+ ** bytes of readable data.
+ */
D("LS(%d): FDE_ERROR (fd=%d)", s->id, s->fd);
return;
}
}
-asocket *create_local_socket(int fd)
-{
- asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
- if (s == NULL) fatal("cannot allocate socket");
+asocket* create_local_socket(int fd) {
+ asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
+ if (s == NULL) {
+ fatal("cannot allocate socket");
+ }
s->fd = fd;
s->enqueue = local_socket_enqueue;
s->ready = local_socket_ready;
@@ -430,32 +399,33 @@
return s;
}
-asocket *create_local_service_socket(const char *name,
- const atransport* transport)
-{
+asocket* create_local_service_socket(const char* name, const atransport* transport) {
#if !ADB_HOST
- if (!strcmp(name,"jdwp")) {
+ if (!strcmp(name, "jdwp")) {
return create_jdwp_service_socket();
}
- if (!strcmp(name,"track-jdwp")) {
+ if (!strcmp(name, "track-jdwp")) {
return create_jdwp_tracker_service_socket();
}
#endif
int fd = service_to_fd(name, transport);
- if(fd < 0) return 0;
+ if (fd < 0) {
+ return 0;
+ }
asocket* s = create_local_socket(fd);
D("LS(%d): bound to '%s' via %d", s->id, name, fd);
#if !ADB_HOST
char debug[PROPERTY_VALUE_MAX];
- if (!strncmp(name, "root:", 5))
+ if (!strncmp(name, "root:", 5)) {
property_get("ro.debuggable", debug, "");
+ }
- if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0)
- || (!strncmp(name, "unroot:", 7) && getuid() == 0)
- || !strncmp(name, "usb:", 4)
- || !strncmp(name, "tcpip:", 6)) {
+ if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) ||
+ (!strncmp(name, "unroot:", 7) && getuid() == 0) ||
+ !strncmp(name, "usb:", 4) ||
+ !strncmp(name, "tcpip:", 6)) {
D("LS(%d): enabling exit_on_close", s->id);
s->exit_on_close = 1;
}
@@ -465,9 +435,8 @@
}
#if ADB_HOST
-static asocket *create_host_service_socket(const char *name, const char* serial)
-{
- asocket *s;
+static asocket* create_host_service_socket(const char* name, const char* serial) {
+ asocket* s;
s = host_service_to_socket(name, serial);
@@ -480,10 +449,8 @@
}
#endif /* ADB_HOST */
-static int remote_socket_enqueue(asocket *s, apacket *p)
-{
- D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d",
- s->id, s->fd, s->peer->fd);
+static int remote_socket_enqueue(asocket* s, apacket* p) {
+ D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
p->msg.command = A_WRTE;
p->msg.arg0 = s->peer->id;
p->msg.arg1 = s->id;
@@ -492,40 +459,35 @@
return 1;
}
-static void remote_socket_ready(asocket *s)
-{
- D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d",
- s->id, s->fd, s->peer->fd);
- apacket *p = get_apacket();
+static void remote_socket_ready(asocket* s) {
+ D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
+ apacket* p = get_apacket();
p->msg.command = A_OKAY;
p->msg.arg0 = s->peer->id;
p->msg.arg1 = s->id;
send_packet(p, s->transport);
}
-static void remote_socket_shutdown(asocket *s)
-{
- D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d",
- s->id, s->fd, s->peer?s->peer->fd:-1);
- apacket *p = get_apacket();
+static void remote_socket_shutdown(asocket* s) {
+ D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd,
+ s->peer ? s->peer->fd : -1);
+ apacket* p = get_apacket();
p->msg.command = A_CLSE;
- if(s->peer) {
+ if (s->peer) {
p->msg.arg0 = s->peer->id;
}
p->msg.arg1 = s->id;
send_packet(p, s->transport);
}
-static void remote_socket_close(asocket *s)
-{
+static void remote_socket_close(asocket* s) {
if (s->peer) {
s->peer->peer = 0;
- D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d",
- s->id, s->peer->id, s->peer->fd);
+ D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
s->peer->close(s->peer);
}
- D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d",
- s->id, s->fd, s->peer?s->peer->fd:-1);
+ D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd,
+ s->peer ? s->peer->fd : -1);
D("RS(%d): closed", s->id);
free(s);
}
@@ -534,12 +496,15 @@
// |t|. Where |id| is the socket id of the corresponding service on the other
// side of the transport (it is allocated by the remote side and _cannot_ be 0).
// Returns a new non-NULL asocket handle.
-asocket *create_remote_socket(unsigned id, atransport *t)
-{
- if (id == 0) fatal("invalid remote socket id (0)");
+asocket* create_remote_socket(unsigned id, atransport* t) {
+ if (id == 0) {
+ fatal("invalid remote socket id (0)");
+ }
asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
- if (s == NULL) fatal("cannot allocate socket");
+ if (s == NULL) {
+ fatal("cannot allocate socket");
+ }
s->id = id;
s->enqueue = remote_socket_enqueue;
s->ready = remote_socket_ready;
@@ -551,13 +516,12 @@
return s;
}
-void connect_to_remote(asocket *s, const char *destination)
-{
+void connect_to_remote(asocket* s, const char* destination) {
D("Connect_to_remote call RS(%d) fd=%d", s->id, s->fd);
- apacket *p = get_apacket();
+ apacket* p = get_apacket();
size_t len = strlen(destination) + 1;
- if(len > (s->get_max_payload()-1)) {
+ if (len > (s->get_max_payload() - 1)) {
fatal("destination oversized");
}
@@ -565,15 +529,13 @@
p->msg.command = A_OPEN;
p->msg.arg0 = s->id;
p->msg.data_length = len;
- strcpy((char*) p->data, destination);
+ strcpy((char*)p->data, destination);
send_packet(p, s->transport);
}
-
/* this is used by magic sockets to rig local sockets to
send the go-ahead message when they connect */
-static void local_socket_ready_notify(asocket *s)
-{
+static void local_socket_ready_notify(asocket* s) {
s->ready = local_socket_ready;
s->shutdown = NULL;
s->close = local_socket_close;
@@ -584,8 +546,7 @@
/* this is used by magic sockets to rig local sockets to
send the failure message if they are closed before
connected (to avoid closing them without a status message) */
-static void local_socket_close_notify(asocket *s)
-{
+static void local_socket_close_notify(asocket* s) {
s->ready = local_socket_ready;
s->shutdown = NULL;
s->close = local_socket_close;
@@ -593,28 +554,41 @@
s->close(s);
}
-static unsigned unhex(unsigned char *s, int len)
-{
+static unsigned unhex(unsigned char* s, int len) {
unsigned n = 0, c;
- while(len-- > 0) {
- switch((c = *s++)) {
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- case '6': case '7': case '8':
- case '9':
- c -= '0';
- break;
- case 'a': case 'b': case 'c':
- case 'd': case 'e': case 'f':
- c = c - 'a' + 10;
- break;
- case 'A': case 'B': case 'C':
- case 'D': case 'E': case 'F':
- c = c - 'A' + 10;
- break;
- default:
- return 0xffffffff;
+ while (len-- > 0) {
+ switch ((c = *s++)) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ c -= '0';
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ c = c - 'a' + 10;
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ c = c - 'A' + 10;
+ break;
+ default:
+ return 0xffffffff;
}
n = (n << 4) | c;
@@ -671,31 +645,29 @@
} // namespace internal
-#endif // ADB_HOST
+#endif // ADB_HOST
-static int smart_socket_enqueue(asocket *s, apacket *p)
-{
+static int smart_socket_enqueue(asocket* s, apacket* p) {
unsigned len;
#if ADB_HOST
- char *service = nullptr;
+ char* service = nullptr;
char* serial = nullptr;
TransportType type = kTransportAny;
#endif
D("SS(%d): enqueue %d", s->id, p->len);
- if(s->pkt_first == 0) {
+ if (s->pkt_first == 0) {
s->pkt_first = p;
s->pkt_last = p;
} else {
- if((s->pkt_first->len + p->len) > s->get_max_payload()) {
+ if ((s->pkt_first->len + p->len) > s->get_max_payload()) {
D("SS(%d): overflow", s->id);
put_apacket(p);
goto fail;
}
- memcpy(s->pkt_first->data + s->pkt_first->len,
- p->data, p->len);
+ memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len);
s->pkt_first->len += p->len;
put_apacket(p);
@@ -703,7 +675,9 @@
}
/* don't bother if we can't decode the length */
- if(p->len < 4) return 0;
+ if (p->len < 4) {
+ return 0;
+ }
len = unhex(p->data, 4);
if ((len < 1) || (len > MAX_PAYLOAD_V1)) {
@@ -711,27 +685,27 @@
goto fail;
}
- D("SS(%d): len is %d", s->id, len );
+ D("SS(%d): len is %d", s->id, len);
/* can't do anything until we have the full header */
- if((len + 4) > p->len) {
- D("SS(%d): waiting for %d more bytes", s->id, len+4 - p->len);
+ if ((len + 4) > p->len) {
+ D("SS(%d): waiting for %d more bytes", s->id, len + 4 - p->len);
return 0;
}
p->data[len + 4] = 0;
- D("SS(%d): '%s'", s->id, (char*) (p->data + 4));
+ D("SS(%d): '%s'", s->id, (char*)(p->data + 4));
#if ADB_HOST
- service = (char *)p->data + 4;
- if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
+ service = (char*)p->data + 4;
+ if (!strncmp(service, "host-serial:", strlen("host-serial:"))) {
char* serial_end;
service += strlen("host-serial:");
// serial number should follow "host:" and could be a host:port string.
serial_end = internal::skip_host_serial(service);
if (serial_end) {
- *serial_end = 0; // terminate string
+ *serial_end = 0; // terminate string
serial = service;
service = serial_end + 1;
}
@@ -749,42 +723,42 @@
}
if (service) {
- asocket *s2;
+ asocket* s2;
- /* some requests are handled immediately -- in that
- ** case the handle_host_request() routine has sent
- ** the OKAY or FAIL message and all we have to do
- ** is clean up.
- */
- if(handle_host_request(service, type, serial, s->peer->fd, s) == 0) {
- /* XXX fail message? */
- D( "SS(%d): handled host service '%s'", s->id, service );
+ /* some requests are handled immediately -- in that
+ ** case the handle_host_request() routine has sent
+ ** the OKAY or FAIL message and all we have to do
+ ** is clean up.
+ */
+ if (handle_host_request(service, type, serial, s->peer->fd, s) == 0) {
+ /* XXX fail message? */
+ D("SS(%d): handled host service '%s'", s->id, service);
goto fail;
}
if (!strncmp(service, "transport", strlen("transport"))) {
- D( "SS(%d): okay transport", s->id );
+ D("SS(%d): okay transport", s->id);
p->len = 0;
return 0;
}
- /* try to find a local service with this name.
- ** if no such service exists, we'll fail out
- ** and tear down here.
- */
+ /* try to find a local service with this name.
+ ** if no such service exists, we'll fail out
+ ** and tear down here.
+ */
s2 = create_host_service_socket(service, serial);
- if(s2 == 0) {
- D( "SS(%d): couldn't create host service '%s'", s->id, service );
+ if (s2 == 0) {
+ D("SS(%d): couldn't create host service '%s'", s->id, service);
SendFail(s->peer->fd, "unknown host service");
goto fail;
}
- /* we've connected to a local host service,
- ** so we make our peer back into a regular
- ** local socket and bind it to the new local
- ** service socket, acknowledge the successful
- ** connection, and close this smart socket now
- ** that its work is done.
- */
+ /* we've connected to a local host service,
+ ** so we make our peer back into a regular
+ ** local socket and bind it to the new local
+ ** service socket, acknowledge the successful
+ ** connection, and close this smart socket now
+ ** that its work is done.
+ */
SendOkay(s->peer->fd);
s->peer->ready = local_socket_ready;
@@ -793,10 +767,10 @@
s->peer->peer = s2;
s2->peer = s->peer;
s->peer = 0;
- D( "SS(%d): okay", s->id );
+ D("SS(%d): okay", s->id);
s->close(s);
- /* initial state is "ready" */
+ /* initial state is "ready" */
s2->ready(s2);
return 0;
}
@@ -811,53 +785,50 @@
}
#endif
- if(!(s->transport) || (s->transport->connection_state == kCsOffline)) {
- /* if there's no remote we fail the connection
- ** right here and terminate it
- */
+ if (!(s->transport) || (s->transport->connection_state == kCsOffline)) {
+ /* if there's no remote we fail the connection
+ ** right here and terminate it
+ */
SendFail(s->peer->fd, "device offline (x)");
goto fail;
}
-
- /* instrument our peer to pass the success or fail
- ** message back once it connects or closes, then
- ** detach from it, request the connection, and
- ** tear down
- */
+ /* instrument our peer to pass the success or fail
+ ** message back once it connects or closes, then
+ ** detach from it, request the connection, and
+ ** tear down
+ */
s->peer->ready = local_socket_ready_notify;
s->peer->shutdown = nullptr;
s->peer->close = local_socket_close_notify;
s->peer->peer = 0;
- /* give him our transport and upref it */
+ /* give him our transport and upref it */
s->peer->transport = s->transport;
- connect_to_remote(s->peer, (char*) (p->data + 4));
+ connect_to_remote(s->peer, (char*)(p->data + 4));
s->peer = 0;
s->close(s);
return 1;
fail:
- /* we're going to close our peer as a side-effect, so
- ** return -1 to signal that state to the local socket
- ** who is enqueueing against us
- */
+ /* we're going to close our peer as a side-effect, so
+ ** return -1 to signal that state to the local socket
+ ** who is enqueueing against us
+ */
s->close(s);
return -1;
}
-static void smart_socket_ready(asocket *s)
-{
+static void smart_socket_ready(asocket* s) {
D("SS(%d): ready", s->id);
}
-static void smart_socket_close(asocket *s)
-{
+static void smart_socket_close(asocket* s) {
D("SS(%d): closed", s->id);
- if(s->pkt_first){
+ if (s->pkt_first) {
put_apacket(s->pkt_first);
}
- if(s->peer) {
+ if (s->peer) {
s->peer->peer = 0;
s->peer->close(s->peer);
s->peer = 0;
@@ -865,10 +836,9 @@
free(s);
}
-static asocket *create_smart_socket(void)
-{
+static asocket* create_smart_socket(void) {
D("Creating smart socket");
- asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
+ asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
if (s == NULL) fatal("cannot allocate socket");
s->enqueue = smart_socket_enqueue;
s->ready = smart_socket_ready;
@@ -879,10 +849,9 @@
return s;
}
-void connect_to_smartsocket(asocket *s)
-{
+void connect_to_smartsocket(asocket* s) {
D("Connecting to smart socket");
- asocket *ss = create_smart_socket();
+ asocket* ss = create_smart_socket();
s->peer = ss;
ss->peer = s;
s->ready(s);
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 81d201e..639f8eb 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -29,8 +29,9 @@
#include <string>
#include <vector>
-// Include this before open/unlink are defined as macros below.
+// Include this before open/close/unlink are defined as macros below.
#include <android-base/errors.h>
+#include <android-base/unique_fd.h>
#include <android-base/utf8.h>
/*
@@ -287,6 +288,9 @@
#undef accept
#define accept ___xxx_accept
+// Returns the local port number of a bound socket, or -1 on failure.
+int adb_socket_get_local_port(int fd);
+
extern int adb_setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen);
#undef setsockopt
@@ -691,6 +695,10 @@
#undef accept
#define accept ___xxx_accept
+inline int adb_socket_get_local_port(int fd) {
+ return socket_get_local_port(fd);
+}
+
// Operate on a file descriptor returned from unix_open() or a well-known file
// descriptor such as STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
//
diff --git a/adb/sysdeps/mutex.h b/adb/sysdeps/mutex.h
new file mode 100644
index 0000000..73c9e6e
--- /dev/null
+++ b/adb/sysdeps/mutex.h
@@ -0,0 +1,107 @@
+#pragma once
+
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#if defined(_WIN32)
+
+#include <windows.h>
+
+#include <android-base/macros.h>
+
+#include "adb.h"
+
+// The prebuilt version of mingw we use doesn't support mutex or recursive_mutex.
+// Therefore, implement our own using the Windows primitives.
+// Put them directly into the std namespace, so that when they're actually available, the build
+// breaks until they're removed.
+
+#include <mutex>
+namespace std {
+
+// CRITICAL_SECTION is recursive, so just wrap it in a Mutex-compatible class.
+class recursive_mutex {
+ public:
+ recursive_mutex() {
+ InitializeCriticalSection(&mutex_);
+ }
+
+ ~recursive_mutex() {
+ DeleteCriticalSection(&mutex_);
+ }
+
+ void lock() {
+ EnterCriticalSection(&mutex_);
+ }
+
+ bool try_lock() {
+ return TryEnterCriticalSection(&mutex_);
+ }
+
+ void unlock() {
+ LeaveCriticalSection(&mutex_);
+ }
+
+ private:
+ CRITICAL_SECTION mutex_;
+
+ DISALLOW_COPY_AND_ASSIGN(recursive_mutex);
+};
+
+class mutex {
+ public:
+ mutex() {
+ }
+
+ ~mutex() {
+ }
+
+ void lock() {
+ mutex_.lock();
+ if (++lock_count_ != 1) {
+ fatal("non-recursive mutex locked reentrantly");
+ }
+ }
+
+ void unlock() {
+ if (--lock_count_ != 0) {
+ fatal("non-recursive mutex unlock resulted in unexpected lock count: %d", lock_count_);
+ }
+ mutex_.unlock();
+ }
+
+ bool try_lock() {
+ if (!mutex_.try_lock()) {
+ return false;
+ }
+
+ if (lock_count_ != 0) {
+ mutex_.unlock();
+ return false;
+ }
+
+ ++lock_count_;
+ return true;
+ }
+
+ private:
+ recursive_mutex mutex_;
+ size_t lock_count_ = 0;
+};
+
+}
+
+#endif
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index fde344a..395d22d 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -244,3 +244,60 @@
adb_close(fd);
}
}
+
+#include "sysdeps/mutex.h"
+TEST(sysdeps_mutex, mutex_smoke) {
+ static std::atomic<bool> finished(false);
+ static std::mutex &m = *new std::mutex();
+ m.lock();
+ ASSERT_FALSE(m.try_lock());
+ adb_thread_create([](void*) {
+ ASSERT_FALSE(m.try_lock());
+ m.lock();
+ finished.store(true);
+ adb_sleep_ms(200);
+ m.unlock();
+ }, nullptr);
+
+ ASSERT_FALSE(finished.load());
+ adb_sleep_ms(100);
+ ASSERT_FALSE(finished.load());
+ m.unlock();
+ adb_sleep_ms(100);
+ m.lock();
+ ASSERT_TRUE(finished.load());
+ m.unlock();
+}
+
+// Our implementation on Windows aborts on double lock.
+#if defined(_WIN32)
+TEST(sysdeps_mutex, mutex_reentrant_lock) {
+ std::mutex &m = *new std::mutex();
+
+ m.lock();
+ ASSERT_FALSE(m.try_lock());
+ EXPECT_DEATH(m.lock(), "non-recursive mutex locked reentrantly");
+}
+#endif
+
+TEST(sysdeps_mutex, recursive_mutex_smoke) {
+ static std::recursive_mutex &m = *new std::recursive_mutex();
+
+ m.lock();
+ ASSERT_TRUE(m.try_lock());
+ m.unlock();
+
+ adb_thread_create([](void*) {
+ ASSERT_FALSE(m.try_lock());
+ m.lock();
+ adb_sleep_ms(500);
+ m.unlock();
+ }, nullptr);
+
+ adb_sleep_ms(100);
+ m.unlock();
+ adb_sleep_ms(100);
+ ASSERT_FALSE(m.try_lock());
+ m.lock();
+ m.unlock();
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index bc09fdc..faf7f3e 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -1128,6 +1128,24 @@
return result;
}
+int adb_socket_get_local_port(int fd) {
+ sockaddr_storage addr_storage;
+ socklen_t addr_len = sizeof(addr_storage);
+
+ if (adb_getsockname(fd, reinterpret_cast<sockaddr*>(&addr_storage), &addr_len) < 0) {
+ D("adb_socket_get_local_port: adb_getsockname failed: %s", strerror(errno));
+ return -1;
+ }
+
+ if (!(addr_storage.ss_family == AF_INET || addr_storage.ss_family == AF_INET6)) {
+ D("adb_socket_get_local_port: unknown address family received: %d", addr_storage.ss_family);
+ errno = ECONNABORTED;
+ return -1;
+ }
+
+ return ntohs(reinterpret_cast<sockaddr_in*>(&addr_storage)->sin_port);
+}
+
int adb_shutdown(int fd)
{
FH f = _fh_from_int(fd, __func__);
@@ -1154,9 +1172,7 @@
int server = -1;
int client = -1;
int accepted = -1;
- sockaddr_storage addr_storage;
- socklen_t addr_len = sizeof(addr_storage);
- sockaddr_in* addr = nullptr;
+ int local_port = -1;
std::string error;
server = network_loopback_server(0, SOCK_STREAM, &error);
@@ -1165,20 +1181,14 @@
goto fail;
}
- if (adb_getsockname(server, reinterpret_cast<sockaddr*>(&addr_storage), &addr_len) < 0) {
- D("adb_socketpair: adb_getsockname failed: %s", strerror(errno));
+ local_port = adb_socket_get_local_port(server);
+ if (local_port < 0) {
+ D("adb_socketpair: failed to get server port number: %s", error.c_str());
goto fail;
}
+ D("adb_socketpair: bound on port %d", local_port);
- if (addr_storage.ss_family != AF_INET) {
- D("adb_socketpair: unknown address family received: %d", addr_storage.ss_family);
- errno = ECONNABORTED;
- goto fail;
- }
-
- addr = reinterpret_cast<sockaddr_in*>(&addr_storage);
- D("adb_socketpair: bound on port %d", ntohs(addr->sin_port));
- client = network_loopback_client(ntohs(addr->sin_port), SOCK_STREAM, &error);
+ client = network_loopback_client(local_port, SOCK_STREAM, &error);
if (client < 0) {
D("adb_socketpair: failed to connect client: %s", error.c_str());
goto fail;
diff --git a/adb/test_device.py b/adb/test_device.py
index 2a3be88..cdc57c6 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -191,6 +191,22 @@
msg = self.device.forward_list()
self.assertEqual('', msg.strip())
+ def test_forward_tcp_port_0(self):
+ self.assertEqual('', self.device.forward_list().strip(),
+ 'Forwarding list must be empty to run this test.')
+
+ try:
+ # If resolving TCP port 0 is supported, `adb forward` will print
+ # the actual port number.
+ port = self.device.forward('tcp:0', 'tcp:8888').strip()
+ if not port:
+ raise unittest.SkipTest('Forwarding tcp:0 is not available.')
+
+ self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port),
+ self.device.forward_list()))
+ finally:
+ self.device.forward_remove_all()
+
def test_reverse(self):
msg = self.device.reverse_list()
self.assertEqual('', msg.strip(),
@@ -210,6 +226,22 @@
msg = self.device.reverse_list()
self.assertEqual('', msg.strip())
+ def test_reverse_tcp_port_0(self):
+ self.assertEqual('', self.device.reverse_list().strip(),
+ 'Reverse list must be empty to run this test.')
+
+ try:
+ # If resolving TCP port 0 is supported, `adb reverse` will print
+ # the actual port number.
+ port = self.device.reverse('tcp:0', 'tcp:8888').strip()
+ if not port:
+ raise unittest.SkipTest('Reversing tcp:0 is not available.')
+
+ self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port),
+ self.device.reverse_list()))
+ finally:
+ self.device.reverse_remove_all()
+
# Note: If you run this test when adb connect'd to a physical device over
# TCP, it will fail in adb reverse due to https://code.google.com/p/android/issues/detail?id=189821
def test_forward_reverse_echo(self):
diff --git a/adb/test_track_devices.cpp b/adb/test_track_devices.cpp
deleted file mode 100644
index b10f8ee..0000000
--- a/adb/test_track_devices.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-// TODO: replace this with a shell/python script.
-
-/* a simple test program, connects to ADB server, and opens a track-devices session */
-#include <errno.h>
-#include <memory.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <android-base/file.h>
-
-static void
-panic( const char* msg )
-{
- fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
- exit(1);
-}
-
-int main(int argc, char* argv[]) {
- const char* request = "host:track-devices";
-
- if (argv[1] && strcmp(argv[1], "--jdwp") == 0) {
- request = "track-jdwp";
- }
-
- int ret;
- struct sockaddr_in server;
- char buffer[1024];
-
- memset( &server, 0, sizeof(server) );
- server.sin_family = AF_INET;
- server.sin_port = htons(5037);
- server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- int s = socket( PF_INET, SOCK_STREAM, 0 );
- ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
- if (ret < 0) panic( "could not connect to server" );
-
- /* send the request */
- int len = snprintf(buffer, sizeof(buffer), "%04zx%s", strlen(request), request);
- if (!android::base::WriteFully(s, buffer, len))
- panic( "could not send request" );
-
- /* read the OKAY answer */
- if (!android::base::ReadFully(s, buffer, 4))
- panic( "could not read request" );
-
- printf( "server answer: %.*s\n", 4, buffer );
-
- /* now loop */
- while (true) {
- char head[5] = "0000";
-
- if (!android::base::ReadFully(s, head, 4))
- panic("could not read length");
-
- int len;
- if (sscanf(head, "%04x", &len) != 1 )
- panic("could not decode length");
-
- if (!android::base::ReadFully(s, buffer, len))
- panic("could not read data");
-
- printf( "received header %.*s (%d bytes):\n%.*s----\n", 4, head, len, len, buffer );
- }
- close(s);
-}
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index ab41c55..869e60f 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -39,25 +39,33 @@
namespace android {
namespace base {
-class unique_fd final {
+struct DefaultCloser {
+ static void Close(int fd) {
+ // Even if close(2) fails with EINTR, the fd will have been closed.
+ // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
+ // else's fd.
+ // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+ ::close(fd);
+ }
+};
+
+template <typename Closer>
+class unique_fd_impl final {
public:
- unique_fd() : value_(-1) {}
+ unique_fd_impl() : value_(-1) {}
- explicit unique_fd(int value) : value_(value) {}
- ~unique_fd() { clear(); }
+ explicit unique_fd_impl(int value) : value_(value) {}
+ ~unique_fd_impl() { clear(); }
- unique_fd(unique_fd&& other) : value_(other.release()) {}
- unique_fd& operator=(unique_fd&& s) {
+ unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
+ unique_fd_impl& operator=(unique_fd_impl&& s) {
reset(s.release());
return *this;
}
void reset(int new_value) {
if (value_ != -1) {
- // Even if close(2) fails with EINTR, the fd will have been closed.
- // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone else's fd.
- // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
- close(value_);
+ Closer::Close(value_);
}
value_ = new_value;
}
@@ -78,10 +86,12 @@
private:
int value_;
- unique_fd(const unique_fd&);
- void operator=(const unique_fd&);
+ unique_fd_impl(const unique_fd_impl&);
+ void operator=(const unique_fd_impl&);
};
+using unique_fd = unique_fd_impl<DefaultCloser>;
+
} // namespace base
} // namespace android
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 6469db4..9ce94c5 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -54,7 +54,7 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := crasher.c
+LOCAL_SRC_FILES := crasher.cpp
LOCAL_SRC_FILES_arm := arm/crashglue.S
LOCAL_SRC_FILES_arm64 := arm64/crashglue.S
LOCAL_SRC_FILES_mips := mips/crashglue.S
@@ -63,9 +63,9 @@
LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object -Wno-date-time
+LOCAL_CPPFLAGS := $(common_cppflags) -fstack-protector-all -Wno-free-nonheap-object -Wno-date-time
#LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+LOCAL_SHARED_LIBRARIES := libcutils liblog
# The arm emulator has VFP but not VFPv3-D32.
ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.cpp
similarity index 93%
rename from debuggerd/crasher.c
rename to debuggerd/crasher.cpp
index 75f070b..bdeaf0b 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.cpp
@@ -22,8 +22,9 @@
extern const char* __progname;
-void crash1(void);
-void crashnostack(void);
+extern "C" void crash1(void);
+extern "C" void crashnostack(void);
+
static int do_action(const char* arg);
static void maybe_abort() {
@@ -159,6 +160,10 @@
__assert("some_file.c", 123, "false");
} else if (!strcmp(arg, "assert2")) {
__assert2("some_file.c", 123, "some_function", "false");
+ } else if (!strcmp(arg, "fortify")) {
+ char buf[10];
+ __read_chk(-1, buf, 32, 10);
+ while (true) pause();
} else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
LOG_ALWAYS_FATAL("hello %s", "world");
} else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
@@ -172,7 +177,7 @@
} else if (!strcmp(arg, "heap-usage")) {
abuse_heap();
} else if (!strcmp(arg, "SIGSEGV-unmapped")) {
- char* map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ char* map = reinterpret_cast<char*>(mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
munmap(map, sizeof(int));
map[0] = '8';
}
@@ -189,6 +194,7 @@
fprintf(stderr, " abort call abort()\n");
fprintf(stderr, " assert call assert() without a function\n");
fprintf(stderr, " assert2 call assert() with a function\n");
+ fprintf(stderr, " fortify fail a _FORTIFY_SOURCE check\n");
fprintf(stderr, " LOG_ALWAYS_FATAL call LOG_ALWAYS_FATAL\n");
fprintf(stderr, " LOG_ALWAYS_FATAL_IF call LOG_ALWAYS_FATAL\n");
fprintf(stderr, " SIGFPE cause a SIGFPE\n");
diff --git a/debuggerd/elf_utils.cpp b/debuggerd/elf_utils.cpp
index 9959f2e..3d99cab 100644
--- a/debuggerd/elf_utils.cpp
+++ b/debuggerd/elf_utils.cpp
@@ -29,7 +29,7 @@
#include "elf_utils.h"
-#define NOTE_ALIGN(size) ((size + 3) & ~3)
+#define NOTE_ALIGN(size) (((size) + 3) & ~3)
template <typename HdrType, typename PhdrType, typename NhdrType>
static bool get_build_id(
diff --git a/debuggerd/test/host_signal_fixup.h b/debuggerd/test/host_signal_fixup.h
index c7796ef..762bae5 100644
--- a/debuggerd/test/host_signal_fixup.h
+++ b/debuggerd/test/host_signal_fixup.h
@@ -57,7 +57,7 @@
#endif
#if !defined(SI_DETHREAD)
-#define SI_DETHREAD -7
+#define SI_DETHREAD (-7)
#endif
#endif
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 94efcc3..1839d25 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -717,10 +717,10 @@
return partition_type == "ext4";
}
-static int load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
+static bool load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
int64_t sz = get_file_size(fd);
if (sz == -1) {
- return -1;
+ return false;
}
lseek64(fd, 0, SEEK_SET);
@@ -728,7 +728,7 @@
if (limit) {
sparse_file** s = load_sparse_files(fd, limit);
if (s == nullptr) {
- return -1;
+ return false;
}
buf->type = FB_BUFFER_SPARSE;
buf->data = s;
@@ -740,18 +740,14 @@
buf->sz = sz;
}
- return 0;
+ return true;
}
-static int load_buf(Transport* transport, const char *fname, struct fastboot_buffer *buf)
-{
- int fd;
-
- fd = open(fname, O_RDONLY | O_BINARY);
- if (fd < 0) {
- return -1;
+static bool load_buf(Transport* transport, const char* fname, struct fastboot_buffer* buf) {
+ int fd = open(fname, O_RDONLY | O_BINARY);
+ if (fd == -1) {
+ return false;
}
-
return load_buf_fd(transport, fd, buf);
}
@@ -895,8 +891,8 @@
static void do_flash(Transport* transport, const char* pname, const char* fname) {
struct fastboot_buffer buf;
- if (load_buf(transport, fname, &buf)) {
- die("cannot load '%s'", fname);
+ if (!load_buf(transport, fname, &buf)) {
+ die("cannot load '%s': %s", fname, strerror(errno));
}
flash_buf(pname, &buf);
}
@@ -940,8 +936,9 @@
exit(1); // unzip_to_file already explained why.
}
fastboot_buffer buf;
- int rc = load_buf_fd(transport, fd, &buf);
- if (rc) die("cannot load %s from flash", images[i].img_name);
+ if (!load_buf_fd(transport, fd, &buf)) {
+ die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
+ }
auto update = [&](const std::string &partition) {
do_update_signature(zip, images[i].sig_name);
@@ -994,10 +991,9 @@
for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
fname = find_item(images[i].part_name, product);
fastboot_buffer buf;
- if (load_buf(transport, fname.c_str(), &buf)) {
- if (images[i].is_optional)
- continue;
- die("could not load %s\n", images[i].img_name);
+ if (!load_buf(transport, fname.c_str(), &buf)) {
+ if (images[i].is_optional) continue;
+ die("could not load '%s': %s", images[i].img_name, strerror(errno));
}
auto flashall = [&](const std::string &partition) {
@@ -1164,7 +1160,7 @@
return;
}
- if (load_buf_fd(transport, fd, &buf)) {
+ if (!load_buf_fd(transport, fd, &buf)) {
fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
close(fd);
return;
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 129a5bb..72554a8 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -30,6 +30,7 @@
#include <unistd.h>
#include <android-base/file.h>
+#include <android-base/strings.h>
#include <crypto_utils/android_pubkey.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
@@ -211,7 +212,7 @@
}
struct verity_table_params {
- const char *table;
+ char *table;
int mode;
struct fec_ecc_metadata ecc;
const char *ecc_dev;
@@ -843,15 +844,42 @@
return rc;
}
+static void update_verity_table_blk_device(char *blk_device, char **table)
+{
+ std::string result, word;
+ auto tokens = android::base::Split(*table, " ");
+
+ for (const auto token : tokens) {
+ if (android::base::StartsWith(token, "/dev/block/") &&
+ android::base::StartsWith(blk_device, token.c_str())) {
+ word = blk_device;
+ } else {
+ word = token;
+ }
+
+ if (result.empty()) {
+ result = word;
+ } else {
+ result += " " + word;
+ }
+ }
+
+ if (result.empty()) {
+ return;
+ }
+
+ free(*table);
+ *table = strdup(result.c_str());
+}
+
int fs_mgr_setup_verity(struct fstab_rec *fstab)
{
int retval = FS_MGR_SETUP_VERITY_FAIL;
int fd = -1;
- char *invalid_table = NULL;
char *verity_blk_name = NULL;
struct fec_handle *f = NULL;
struct fec_verity_metadata verity;
- struct verity_table_params params;
+ struct verity_table_params params = { .table = NULL };
alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
@@ -912,8 +940,17 @@
params.mode = VERITY_MODE_EIO;
}
+ if (!verity.table) {
+ goto out;
+ }
+
+ params.table = strdup(verity.table);
+ if (!params.table) {
+ goto out;
+ }
+
// verify the signature on the table
- if (verify_table(verity.signature, sizeof(verity.signature), verity.table,
+ if (verify_table(verity.signature, sizeof(verity.signature), params.table,
verity.table_length) < 0) {
if (params.mode == VERITY_MODE_LOGGING) {
// the user has been warned, allow mounting without dm-verity
@@ -922,20 +959,18 @@
}
// invalidate root hash and salt to trigger device-specific recovery
- invalid_table = strdup(verity.table);
-
- if (!invalid_table ||
- invalidate_table(invalid_table, verity.table_length) < 0) {
+ if (invalidate_table(params.table, verity.table_length) < 0) {
goto out;
}
-
- params.table = invalid_table;
- } else {
- params.table = verity.table;
}
INFO("Enabling dm-verity for %s (mode %d)\n", mount_point, params.mode);
+ if (fstab->fs_mgr_flags & MF_SLOTSELECT) {
+ // Update the verity params using the actual block device path
+ update_verity_table_blk_device(fstab->blk_device, ¶ms.table);
+ }
+
// load the verity mapping table
if (load_verity_table(io, mount_point, verity.data_size, fd, ¶ms,
format_verity_table) == 0) {
@@ -1001,7 +1036,7 @@
}
fec_close(f);
- free(invalid_table);
+ free(params.table);
free(verity_blk_name);
return retval;
diff --git a/include/cutils/ashmem.h b/include/cutils/ashmem.h
index 25b233e..acedf73 100644
--- a/include/cutils/ashmem.h
+++ b/include/cutils/ashmem.h
@@ -12,6 +12,10 @@
#include <stddef.h>
+#if defined(__BIONIC__)
+#include <linux/ashmem.h>
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -26,20 +30,4 @@
}
#endif
-#ifndef __ASHMEMIOC /* in case someone included <linux/ashmem.h> too */
-
-#define ASHMEM_NAME_LEN 256
-
-#define ASHMEM_NAME_DEF "dev/ashmem"
-
-/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
-#define ASHMEM_NOT_PURGED 0
-#define ASHMEM_WAS_PURGED 1
-
-/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
-#define ASHMEM_IS_UNPINNED 0
-#define ASHMEM_IS_PINNED 1
-
-#endif /* ! __ASHMEMIOC */
-
#endif /* _CUTILS_ASHMEM_H */
diff --git a/include/private/canned_fs_config.h b/include/private/canned_fs_config.h
new file mode 100644
index 0000000..d9f51ca
--- /dev/null
+++ b/include/private/canned_fs_config.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef _CANNED_FS_CONFIG_H
+#define _CANNED_FS_CONFIG_H
+
+#include <inttypes.h>
+
+int load_canned_fs_config(const char* fn);
+void canned_fs_config(const char* path, int dir, const char* target_out_path,
+ unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities);
+
+#endif
diff --git a/init/devices.cpp b/init/devices.cpp
index d452dd3..1410e3b 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -43,6 +43,7 @@
#include <sys/wait.h>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <cutils/list.h>
#include <cutils/uevent.h>
@@ -130,49 +131,6 @@
return 0;
}
-void fixup_sys_perms(const char *upath)
-{
- char buf[512];
- struct listnode *node;
- struct perms_ *dp;
-
- /* upaths omit the "/sys" that paths in this list
- * contain, so we add 4 when comparing...
- */
- list_for_each(node, &sys_perms) {
- dp = &(node_to_item(node, struct perm_node, plist))->dp;
- if (dp->prefix) {
- if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
- continue;
- } else if (dp->wildcard) {
- if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0)
- continue;
- } else {
- if (strcmp(upath, dp->name + 4))
- continue;
- }
-
- if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
- break;
-
- snprintf(buf, sizeof(buf), "/sys%s/%s", upath, dp->attr);
- INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm);
- chown(buf, dp->uid, dp->gid);
- chmod(buf, dp->perm);
- }
-
- // Now fixup SELinux file labels
- int len = snprintf(buf, sizeof(buf), "/sys%s", upath);
- if ((len < 0) || ((size_t) len >= sizeof(buf))) {
- // Overflow
- return;
- }
- if (access(buf, F_OK) == 0) {
- INFO("restorecon_recursive: %s\n", buf);
- restorecon_recursive(buf);
- }
-}
-
static bool perm_path_matches(const char *path, struct perms_ *dp)
{
if (dp->prefix) {
@@ -189,6 +147,44 @@
return false;
}
+static bool match_subsystem(perms_* dp, const char* pattern,
+ const char* path, const char* subsystem) {
+ if (!pattern || !subsystem || strstr(dp->name, subsystem) == NULL) {
+ return false;
+ }
+
+ std::string subsys_path = android::base::StringPrintf(pattern, subsystem, basename(path));
+ return perm_path_matches(subsys_path.c_str(), dp);
+}
+
+static void fixup_sys_perms(const char* upath, const char* subsystem) {
+ // upaths omit the "/sys" that paths in this list
+ // contain, so we prepend it...
+ std::string path = std::string(SYSFS_PREFIX) + upath;
+
+ listnode* node;
+ list_for_each(node, &sys_perms) {
+ perms_* dp = &(node_to_item(node, perm_node, plist))->dp;
+ if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem)) {
+ ; // matched
+ } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(), subsystem)) {
+ ; // matched
+ } else if (!perm_path_matches(path.c_str(), dp)) {
+ continue;
+ }
+
+ std::string attr_file = path + "/" + dp->attr;
+ INFO("fixup %s %d %d 0%o\n", attr_file.c_str(), dp->uid, dp->gid, dp->perm);
+ chown(attr_file.c_str(), dp->uid, dp->gid);
+ chmod(attr_file.c_str(), dp->perm);
+ }
+
+ if (access(path.c_str(), F_OK) == 0) {
+ INFO("restorecon_recursive: %s\n", path.c_str());
+ restorecon_recursive(path.c_str());
+ }
+}
+
static mode_t get_device_perm(const char *path, const char **links,
unsigned *uid, unsigned *gid)
{
@@ -747,7 +743,7 @@
static void handle_device_event(struct uevent *uevent)
{
if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
- fixup_sys_perms(uevent->path);
+ fixup_sys_perms(uevent->path, uevent->subsystem);
if (!strncmp(uevent->subsystem, "block", 5)) {
handle_block_device_event(uevent);
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
index b4dc48d..6d750ea 100644
--- a/libbacktrace/GetPss.cpp
+++ b/libbacktrace/GetPss.cpp
@@ -24,7 +24,7 @@
// This is an extremely simplified version of libpagemap.
-#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << (bits)) - 1))
+#define _BITS(x, offset, bits) (((x) >> (offset)) & ((1LL << (bits)) - 1))
#define PAGEMAP_PRESENT(x) (_BITS(x, 63, 1))
#define PAGEMAP_SWAPPED(x) (_BITS(x, 62, 1))
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index df6c6c1..7066c79 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -1420,7 +1420,7 @@
#if defined(ENABLE_PSS_TESTS)
#include "GetPss.h"
-#define MAX_LEAK_BYTES 32*1024UL
+#define MAX_LEAK_BYTES (32*1024UL)
void CheckForLeak(pid_t pid, pid_t tid) {
// Do a few runs to get the PSS stable.
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index b5780b8..822a7d3 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -19,6 +19,7 @@
libcutils_common_sources := \
config_utils.c \
fs_config.c \
+ canned_fs_config.c \
hashmap.c \
iosched_policy.c \
load_file.c \
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index c85f06b..1f9f753 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -62,12 +62,12 @@
int ashmem_pin_region(int fd __unused, size_t offset __unused, size_t len __unused)
{
- return ASHMEM_NOT_PURGED;
+ return 0 /*ASHMEM_NOT_PURGED*/;
}
int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __unused)
{
- return ASHMEM_IS_UNPINNED;
+ return 0 /*ASHMEM_IS_UNPINNED*/;
}
int ashmem_get_size_region(int fd)
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.c
new file mode 100644
index 0000000..5800857
--- /dev/null
+++ b/libcutils/canned_fs_config.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 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 <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/canned_fs_config.h>
+
+typedef struct {
+ const char* path;
+ unsigned uid;
+ unsigned gid;
+ unsigned mode;
+ uint64_t capabilities;
+} Path;
+
+static Path* canned_data = NULL;
+static int canned_alloc = 0;
+static int canned_used = 0;
+
+static int path_compare(const void* a, const void* b) {
+ return strcmp(((Path*)a)->path, ((Path*)b)->path);
+}
+
+int load_canned_fs_config(const char* fn) {
+ FILE* f = fopen(fn, "r");
+ if (f == NULL) {
+ fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno));
+ return -1;
+ }
+
+ char line[PATH_MAX + 200];
+ while (fgets(line, sizeof(line), f)) {
+ while (canned_used >= canned_alloc) {
+ canned_alloc = (canned_alloc+1) * 2;
+ canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
+ }
+ Path* p = canned_data + canned_used;
+ p->path = strdup(strtok(line, " "));
+ p->uid = atoi(strtok(NULL, " "));
+ p->gid = atoi(strtok(NULL, " "));
+ p->mode = strtol(strtok(NULL, " "), NULL, 8); // mode is in octal
+ p->capabilities = 0;
+
+ char* token = NULL;
+ do {
+ token = strtok(NULL, " ");
+ if (token && strncmp(token, "capabilities=", 13) == 0) {
+ p->capabilities = strtoll(token+13, NULL, 0);
+ break;
+ }
+ } while (token);
+
+ canned_used++;
+ }
+
+ fclose(f);
+
+ qsort(canned_data, canned_used, sizeof(Path), path_compare);
+ printf("loaded %d fs_config entries\n", canned_used);
+
+ return 0;
+}
+
+static const int kDebugCannedFsConfig = 0;
+
+void canned_fs_config(const char* path, int dir, const char* target_out_path,
+ unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) {
+ Path key;
+ key.path = path;
+ if (path[0] == '/')
+ key.path++; // canned paths lack the leading '/'
+ Path* p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare);
+ if (p == NULL) {
+ fprintf(stderr, "failed to find [%s] in canned fs_config\n", path);
+ exit(1);
+ }
+ *uid = p->uid;
+ *gid = p->gid;
+ *mode = p->mode;
+ *capabilities = p->capabilities;
+
+ if (kDebugCannedFsConfig) {
+ // for debugging, run the built-in fs_config and compare the results.
+
+ unsigned c_uid, c_gid, c_mode;
+ uint64_t c_capabilities;
+ fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities);
+
+ if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid);
+ if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid);
+ if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode);
+ if (c_capabilities != *capabilities)
+ printf("%s capabilities %" PRIx64 " %" PRIx64 "\n",
+ path,
+ *capabilities,
+ c_capabilities);
+ }
+}
diff --git a/libion/kernel-headers/linux/ion.h b/libion/kernel-headers/linux/ion.h
index 5af39d0..3c28080 100644
--- a/libion/kernel-headers/linux/ion.h
+++ b/libion/kernel-headers/linux/ion.h
@@ -38,7 +38,7 @@
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
-#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8
+#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
#define ION_FLAG_CACHED 1
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ION_FLAG_CACHED_NEEDS_SYNC 2
diff --git a/liblog/config_read.h b/liblog/config_read.h
index 67f4c20..49a3b75 100644
--- a/liblog/config_read.h
+++ b/liblog/config_read.h
@@ -27,21 +27,21 @@
extern LIBLOG_HIDDEN struct listnode __android_log_persist_read;
#define read_transport_for_each(transp, transports) \
- for (transp = node_to_item((transports)->next, \
+ for ((transp) = node_to_item((transports)->next, \
struct android_log_transport_read, node); \
- (transp != node_to_item(transports, \
+ ((transp) != node_to_item(transports, \
struct android_log_transport_read, node)); \
- transp = node_to_item(transp->node.next, \
+ (transp) = node_to_item((transp)->node.next, \
struct android_log_transport_read, node)) \
#define read_transport_for_each_safe(transp, n, transports) \
- for (transp = node_to_item((transports)->next, \
+ for ((transp) = node_to_item((transports)->next, \
struct android_log_transport_read, node), \
- n = transp->node.next; \
- (transp != node_to_item(transports, \
+ (n) = (transp)->node.next; \
+ ((transp) != node_to_item(transports, \
struct android_log_transport_read, node)); \
- transp = node_to_item(n, struct android_log_transport_read, node), \
- n = transp->node.next)
+ (transp) = node_to_item(n, struct android_log_transport_read, node), \
+ (n) = (transp)->node.next)
LIBLOG_HIDDEN void __android_log_config_read();
diff --git a/liblog/config_write.h b/liblog/config_write.h
index 3a02a4e..3b01a9a 100644
--- a/liblog/config_write.h
+++ b/liblog/config_write.h
@@ -27,21 +27,21 @@
extern LIBLOG_HIDDEN struct listnode __android_log_persist_write;
#define write_transport_for_each(transp, transports) \
- for (transp = node_to_item((transports)->next, \
- struct android_log_transport_write, node); \
- (transp != node_to_item(transports, \
+ for ((transp) = node_to_item((transports)->next, \
+ struct android_log_transport_write, node); \
+ ((transp) != node_to_item(transports, \
struct android_log_transport_write, node)); \
- transp = node_to_item(transp->node.next, \
- struct android_log_transport_write, node)) \
+ (transp) = node_to_item((transp)->node.next, \
+ struct android_log_transport_write, node)) \
#define write_transport_for_each_safe(transp, n, transports) \
- for (transp = node_to_item((transports)->next, \
- struct android_log_transport_write, node), \
- n = transp->node.next; \
- (transp != node_to_item(transports, \
- struct android_log_transport_write, node)); \
- transp = node_to_item(n, struct android_log_transport_write, node), \
- n = transp->node.next)
+ for ((transp) = node_to_item((transports)->next, \
+ struct android_log_transport_write, node), \
+ (n) = (transp)->node.next; \
+ ((transp) != node_to_item(transports, \
+ struct android_log_transport_write, node)); \
+ (transp) = node_to_item(n, struct android_log_transport_write, node), \
+ (n) = (transp)->node.next)
LIBLOG_HIDDEN void __android_log_config_write();
diff --git a/liblog/logger.h b/liblog/logger.h
index c727f29..5087256 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -124,23 +124,23 @@
/* assumes caller has structures read-locked, single threaded, or fenced */
#define transport_context_for_each(transp, logger_list) \
- for (transp = node_to_item((logger_list)->transport.next, \
+ for ((transp) = node_to_item((logger_list)->transport.next, \
struct android_log_transport_context, \
node); \
- (transp != node_to_item(&(logger_list)->transport, \
+ ((transp) != node_to_item(&(logger_list)->transport, \
struct android_log_transport_context, \
node)) && \
- (transp->parent == (logger_list)); \
- transp = node_to_item(transp->node.next, \
+ ((transp)->parent == (logger_list)); \
+ (transp) = node_to_item((transp)->node.next, \
struct android_log_transport_context, node))
#define logger_for_each(logp, logger_list) \
- for (logp = node_to_item((logger_list)->logger.next, \
+ for ((logp) = node_to_item((logger_list)->logger.next, \
struct android_log_logger, node); \
- (logp != node_to_item(&(logger_list)->logger, \
+ ((logp) != node_to_item(&(logger_list)->logger, \
struct android_log_logger, node)) && \
- (logp->parent == (logger_list)); \
- logp = node_to_item((logp)->node.next, \
+ ((logp)->parent == (logger_list)); \
+ (logp) = node_to_item((logp)->node.next, \
struct android_log_logger, node))
/* OS specific dribs and drabs */
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index 0d6ba08..00157b7 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -125,7 +125,7 @@
ssize_t ret = -EINVAL; \
struct android_log_transport_context *transp; \
struct android_log_logger *logger_internal = \
- (struct android_log_logger *)logger; \
+ (struct android_log_logger *)(logger); \
\
if (!logger_internal) { \
return ret; \
@@ -186,7 +186,7 @@
#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...) \
struct android_log_transport_context *transp; \
struct android_log_logger_list *logger_list_internal = \
- (struct android_log_logger_list *)logger_list; \
+ (struct android_log_logger_list *)(logger_list); \
\
ssize_t ret = init_transport_context(logger_list_internal); \
if (ret < 0) { \
@@ -341,6 +341,43 @@
return logger_list;
}
+/* Validate log_msg packet, read function has already been null checked */
+static int android_transport_read(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ struct log_msg *log_msg)
+{
+ int ret = (*transp->transport->read)(logger_list, transp, log_msg);
+
+ if (ret > (int)sizeof(*log_msg)) {
+ ret = sizeof(*log_msg);
+ }
+
+ transp->ret = ret;
+
+ /* propagate errors, or make sure len & hdr_size members visible */
+ if (ret < (int)(sizeof(log_msg->entry.len) +
+ sizeof(log_msg->entry.hdr_size))) {
+ if (ret >= (int)sizeof(log_msg->entry.len)) {
+ log_msg->entry.len = 0;
+ }
+ return ret;
+ }
+
+ /* hdr_size correction (logger_entry -> logger_entry_v2+ conversion) */
+ if (log_msg->entry_v2.hdr_size == 0) {
+ log_msg->entry_v2.hdr_size = sizeof(struct logger_entry);
+ }
+
+ /* len validation */
+ if (ret <= log_msg->entry_v2.hdr_size) {
+ log_msg->entry.len = 0;
+ } else {
+ log_msg->entry.len = ret - log_msg->entry_v2.hdr_size;
+ }
+
+ return ret;
+}
+
/* Read from the selected logs */
LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
struct log_msg *log_msg)
@@ -378,7 +415,7 @@
} else if ((logger_list_internal->mode &
ANDROID_LOG_NONBLOCK) ||
!transp->transport->poll) {
- retval = transp->ret = (*transp->transport->read)(
+ retval = android_transport_read(
logger_list_internal,
transp,
&transp->logMsg);
@@ -397,7 +434,7 @@
}
retval = transp->ret = pollval;
} else if (pollval > 0) {
- retval = transp->ret = (*transp->transport->read)(
+ retval = android_transport_read(
logger_list_internal,
transp,
&transp->logMsg);
@@ -434,16 +471,22 @@
if (!oldest) {
return ret;
}
- memcpy(log_msg, &oldest->logMsg, oldest->logMsg.entry.len +
- (oldest->logMsg.entry.hdr_size ?
- oldest->logMsg.entry.hdr_size :
- sizeof(struct logger_entry)));
+ // ret is a positive value less than sizeof(struct log_msg)
+ ret = oldest->ret;
+ if (ret < oldest->logMsg.entry.hdr_size) {
+ // zero truncated header fields.
+ memset(log_msg, 0,
+ (oldest->logMsg.entry.hdr_size > sizeof(oldest->logMsg) ?
+ sizeof(oldest->logMsg) :
+ oldest->logMsg.entry.hdr_size));
+ }
+ memcpy(log_msg, &oldest->logMsg, ret);
oldest->logMsg.entry.len = 0; /* Mark it as copied */
- return oldest->ret;
+ return ret;
}
/* if only one, no need to copy into transport_context and merge-sort */
- return (transp->transport->read)(logger_list_internal, transp, log_msg);
+ return android_transport_read(logger_list_internal, transp, log_msg);
}
/* Close all the logs */
diff --git a/liblog/tests/benchmark.h b/liblog/tests/benchmark.h
index 7f96e6d..57b3748 100644
--- a/liblog/tests/benchmark.h
+++ b/liblog/tests/benchmark.h
@@ -141,7 +141,7 @@
void StopBenchmarkTiming(uint64_t);
#define BENCHMARK(f) \
- static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = \
- (::testing::Benchmark*)::testing::BenchmarkFactory(#f, f)
+ static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = /* NOLINT */ \
+ (::testing::Benchmark*)::testing::BenchmarkFactory(#f, f) /* NOLINT */
#endif // BIONIC_BENCHMARK_H_
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 1a7d4aa..df2c766 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1368,6 +1368,7 @@
snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
i, j, key, buf);
+ usleep(20000);
property_set(key, buf);
bool android_log_is_loggable = __android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG);
@@ -1393,6 +1394,7 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key, "");
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1422,6 +1424,7 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key + base_offset, "");
strcpy(key, log_namespace);
@@ -1453,6 +1456,7 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key, "");
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1482,6 +1486,7 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key + base_offset, "");
}
}
@@ -1489,6 +1494,7 @@
// All combinations of level and tag properties, but with global set to INFO
strcpy(key, log_namespace);
key[sizeof(log_namespace) - 2] = '\0';
+ usleep(20000);
property_set(key, "I");
snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
@@ -1502,6 +1508,7 @@
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
i, j, key, buf);
+ usleep(20000);
property_set(key, buf);
bool android_log_is_loggable = __android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG);
@@ -1527,6 +1534,7 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key, "");
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1556,12 +1564,14 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key + base_offset, "");
}
}
// reset parms
snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ usleep(20000);
property_set(key, hold[0]);
property_set(key + base_offset, hold[1]);
strcpy(key, log_namespace);
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
index 21d9ebd..b528214 100644
--- a/libmemtrack/memtrack.c
+++ b/libmemtrack/memtrack.c
@@ -26,7 +26,7 @@
#include <hardware/memtrack.h>
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
static const memtrack_module_t *module;
diff --git a/libmemunreachable/tests/LeakFolding_test.cpp b/libmemunreachable/tests/LeakFolding_test.cpp
index 879a3a0..e85df5f 100644
--- a/libmemunreachable/tests/LeakFolding_test.cpp
+++ b/libmemunreachable/tests/LeakFolding_test.cpp
@@ -37,10 +37,10 @@
Heap heap_;
};
-#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(&buffer[0])
-#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(&buffer[0]) + sizeof(buffer))
+#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(&(buffer)[0])
+#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(&(buffer)[0]) + sizeof(buffer))
#define ALLOCATION(heap_walker, buffer) \
- ASSERT_EQ(true, heap_walker.Allocation(buffer_begin(buffer), buffer_end(buffer)))
+ ASSERT_EQ(true, (heap_walker).Allocation(buffer_begin(buffer), buffer_end(buffer)))
TEST_F(LeakFoldingTest, one) {
void* buffer1[1] = {nullptr};
diff --git a/libnativeloader/dlext_namespaces.h b/libnativeloader/dlext_namespaces.h
new file mode 100644
index 0000000..13a44e2
--- /dev/null
+++ b/libnativeloader/dlext_namespaces.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef __ANDROID_DLEXT_NAMESPACES_H__
+#define __ANDROID_DLEXT_NAMESPACES_H__
+
+#include <android/dlext.h>
+
+__BEGIN_DECLS
+
+/*
+ * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
+ * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
+ * The libraries in this list should be loaded prior to this call.
+ *
+ * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
+ * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
+ */
+extern bool android_init_namespaces(const char* public_ns_sonames,
+ const char* anon_ns_library_path);
+
+
+enum {
+ /* A regular namespace is the namespace with a custom search path that does
+ * not impose any restrictions on the location of native libraries.
+ */
+ ANDROID_NAMESPACE_TYPE_REGULAR = 0,
+
+ /* An isolated namespace requires all the libraries to be on the search path
+ * or under permitted_when_isolated_path. The search path is the union of
+ * ld_library_path and default_library_path.
+ */
+ ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+
+ /* The shared namespace clones the list of libraries of the caller namespace upon creation
+ * which means that they are shared between namespaces - the caller namespace and the new one
+ * will use the same copy of a library if it was loaded prior to android_create_namespace call.
+ *
+ * Note that libraries loaded after the namespace is created will not be shared.
+ *
+ * Shared namespaces can be isolated or regular. Note that they do not inherit the search path nor
+ * permitted_path from the caller's namespace.
+ */
+ ANDROID_NAMESPACE_TYPE_SHARED = 2,
+ ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+};
+
+/*
+ * Creates new linker namespace.
+ * ld_library_path and default_library_path represent the search path
+ * for the libraries in the namespace.
+ *
+ * The libraries in the namespace are searched by folowing order:
+ * 1. ld_library_path (Think of this as namespace-local LD_LIBRARY_PATH)
+ * 2. In directories specified by DT_RUNPATH of the "needed by" binary.
+ * 3. deault_library_path (This of this as namespace-local default library path)
+ *
+ * When type is ANDROID_NAMESPACE_TYPE_ISOLATED the resulting namespace requires all of
+ * the libraries to be on the search path or under the permitted_when_isolated_path;
+ * the search_path is ld_library_path:default_library_path. Note that the
+ * permitted_when_isolated_path path is not part of the search_path and
+ * does not affect the search order. It is a way to allow loading libraries from specific
+ * locations when using absolute path.
+ * If a library or any of its dependencies are outside of the permitted_when_isolated_path
+ * and search_path, and it is not part of the public namespace dlopen will fail.
+ */
+extern struct android_namespace_t* android_create_namespace(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ android_namespace_t* parent);
+
+__END_DECLS
+
+#endif /* __ANDROID_DLEXT_NAMESPACES_H__ */
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 33d5b62..713a59d 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -19,7 +19,7 @@
#include <dlfcn.h>
#ifdef __ANDROID__
-#include <android/dlext.h>
+#include "dlext_namespaces.h"
#include "cutils/properties.h"
#include "log/log.h"
#endif
@@ -39,6 +39,11 @@
static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
+// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
+// System.load() with an absolute path which is outside of the classloader library search path.
+// This list includes all directories app is allowed to access this way.
+static constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
+
static bool is_debuggable() {
char debuggable[PROP_VALUE_MAX];
property_get("ro.debuggable", debuggable, "0");
@@ -61,10 +66,19 @@
library_path = library_path_utf_chars.c_str();
}
- std::string permitted_path;
+ // (http://b/27588281) This is a workaround for apps using custom
+ // classloaders and calling System.load() with an absolute path which
+ // is outside of the classloader library search path.
+ //
+ // This part effectively allows such a classloader to access anything
+ // under /data and /mnt/expand
+ std::string permitted_path = kWhitelistedDirectories;
+
if (java_permitted_path != nullptr) {
ScopedUtfChars path(env, java_permitted_path);
- permitted_path = path.c_str();
+ if (path.c_str() != nullptr && path.size() > 0) {
+ permitted_path = permitted_path + ":" + path.c_str();
+ }
}
if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
@@ -81,13 +95,14 @@
namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
}
+ android_namespace_t* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
+
ns = android_create_namespace("classloader-namespace",
nullptr,
library_path.c_str(),
namespace_type,
- java_permitted_path != nullptr ?
- permitted_path.c_str() :
- nullptr);
+ permitted_path.c_str(),
+ parent_ns);
if (ns != nullptr) {
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
@@ -105,6 +120,13 @@
}
void Initialize() {
+ // Once public namespace is initialized there is no
+ // point in running this code - it will have no effect
+ // on the current list of public libraries.
+ if (initialized_) {
+ return;
+ }
+
std::vector<std::string> sonames;
const char* android_root_env = getenv("ANDROID_ROOT");
std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
@@ -181,6 +203,29 @@
return initialized_;
}
+ jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
+ jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
+ jmethodID get_parent = env->GetMethodID(class_loader_class,
+ "getParent",
+ "()Ljava/lang/ClassLoader;");
+
+ return env->CallObjectMethod(class_loader, get_parent);
+ }
+
+ android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ jobject parent_class_loader = GetParentClassLoader(env, class_loader);
+
+ while (parent_class_loader != nullptr) {
+ android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader);
+ if (ns != nullptr) {
+ return ns;
+ }
+
+ parent_class_loader = GetParentClassLoader(env, parent_class_loader);
+ }
+ return nullptr;
+ }
+
bool initialized_;
std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
std::string public_libraries_;
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index c6b9fe4..56e1d59 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -243,12 +243,8 @@
property_set(result_prop_name, "");
/* Start the daemon and wait until it's ready */
- if (property_get(HOSTNAME_PROP_NAME, prop_value, NULL) && (prop_value[0] != '\0'))
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s -h %s %s", DAEMON_NAME,
- p2p_interface, DHCP_CONFIG_PATH, prop_value, interface);
- else
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s %s", DAEMON_NAME,
- p2p_interface, DHCP_CONFIG_PATH, interface);
+ snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME,
+ p2p_interface);
memset(prop_value, '\0', PROPERTY_VALUE_MAX);
property_set(ctrl_prop, daemon_cmd);
if (wait_for_property(daemon_prop_name, desired_status, 10) < 0) {
@@ -288,7 +284,8 @@
DAEMON_PROP_NAME,
p2p_interface);
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, p2p_interface);
+ snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME,
+ p2p_interface);
/* Stop the daemon and wait until it's reported to be stopped */
property_set(ctrl_prop, daemon_cmd);
@@ -317,7 +314,8 @@
DAEMON_PROP_NAME,
p2p_interface);
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, p2p_interface);
+ snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME,
+ p2p_interface);
/* Stop the daemon and wait until it's reported to be stopped */
property_set(ctrl_prop, daemon_cmd);
@@ -357,8 +355,8 @@
property_set(result_prop_name, "");
/* Start the renew daemon and wait until it's ready */
- snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME_RENEW,
- p2p_interface, interface);
+ snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME_RENEW,
+ p2p_interface);
memset(prop_value, '\0', PROPERTY_VALUE_MAX);
property_set(ctrl_prop, daemon_cmd);
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index f48e1d0..aa18360 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -26,10 +26,6 @@
#include <cutils/memory.h>
#include <cutils/log.h>
-#ifdef __arm__
-#include <machine/cpu-features.h>
-#endif
-
#include "buffer.h"
#include "scanline.h"
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index cd30800..d284736 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -57,7 +57,7 @@
#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
#define container_of(inner, outer_t, elem) \
- ((outer_t *)((char *)inner - offsetof(outer_t, elem)))
+ ((outer_t *)((char *)(inner) - offsetof(outer_t, elem)))
struct output_file_ops {
int (*open)(struct output_file *, int fd);
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index c5ae327..965e32c 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -19,18 +19,13 @@
* System clock functions.
*/
-#if defined(__ANDROID__)
-#include <linux/ioctl.h>
-#include <linux/rtc.h>
-#include <utils/Atomic.h>
-#include <linux/android_alarm.h>
-#endif
-
#include <sys/time.h>
#include <limits.h>
#include <fcntl.h>
#include <string.h>
+#include <errno.h>
+#include <cutils/compiler.h>
#include <utils/SystemClock.h>
#include <utils/Timers.h>
@@ -61,30 +56,16 @@
*/
int64_t elapsedRealtimeNano()
{
-#if defined(__ANDROID__)
- static int s_fd = -1;
-
- if (s_fd == -1) {
- int fd = open("/dev/alarm", O_RDONLY);
- if (android_atomic_cmpxchg(-1, fd, &s_fd)) {
- close(fd);
- }
- }
-
+#if defined(__linux__)
struct timespec ts;
- if (ioctl(s_fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts) == 0) {
- return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+ int err = clock_gettime(CLOCK_BOOTTIME, &ts);
+ if (CC_UNLIKELY(err)) {
+ // This should never happen, but just in case ...
+ ALOGE("clock_gettime(CLOCK_BOOTTIME) failed: %s", strerror(errno));
+ return 0;
}
- // /dev/alarm doesn't exist, fallback to CLOCK_BOOTTIME
- if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0) {
- return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
- }
-
- // XXX: there was an error, probably because the driver didn't
- // exist ... this should return
- // a real error, like an exception!
- return systemTime(SYSTEM_TIME_MONOTONIC);
+ return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
#else
return systemTime(SYSTEM_TIME_MONOTONIC);
#endif
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
index 8f07f1a..21fe19c 100644
--- a/libutils/tests/Android.mk
+++ b/libutils/tests/Android.mk
@@ -28,6 +28,7 @@
LruCache_test.cpp \
String8_test.cpp \
StrongPointer_test.cpp \
+ SystemClock_test.cpp \
Unicode_test.cpp \
Vector_test.cpp \
diff --git a/libutils/tests/SystemClock_test.cpp b/libutils/tests/SystemClock_test.cpp
new file mode 100644
index 0000000..5ad060b
--- /dev/null
+++ b/libutils/tests/SystemClock_test.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 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 <unistd.h>
+#include <utils/SystemClock.h>
+
+#include <gtest/gtest.h>
+
+static const auto MS_IN_NS = 1000000;
+
+static const int64_t SLEEP_MS = 500;
+static const int64_t SLEEP_NS = SLEEP_MS * MS_IN_NS;
+// Conservatively assume that we might be descheduled for up to 50 ms
+static const int64_t SLACK_MS = 50;
+static const int64_t SLACK_NS = SLACK_MS * MS_IN_NS;
+
+TEST(SystemClock, SystemClock) {
+ auto startUptimeMs = android::uptimeMillis();
+ auto startRealtimeMs = android::elapsedRealtime();
+ auto startRealtimeNs = android::elapsedRealtimeNano();
+
+ ASSERT_GT(startUptimeMs, 0)
+ << "uptimeMillis() reported an impossible uptime";
+ ASSERT_GE(startRealtimeMs, startUptimeMs)
+ << "elapsedRealtime() thinks we've suspended for negative time";
+ ASSERT_GE(startRealtimeNs, startUptimeMs * MS_IN_NS)
+ << "elapsedRealtimeNano() thinks we've suspended for negative time";
+
+ ASSERT_GE(startRealtimeNs, startRealtimeMs * MS_IN_NS)
+ << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
+ ASSERT_LT(startRealtimeNs, (startRealtimeMs + SLACK_MS) * MS_IN_NS)
+ << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
+
+ timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = SLEEP_MS * MS_IN_NS;
+ auto nanosleepErr = TEMP_FAILURE_RETRY(nanosleep(&ts, nullptr));
+ ASSERT_EQ(nanosleepErr, 0) << "nanosleep() failed: " << strerror(errno);
+
+ auto endUptimeMs = android::uptimeMillis();
+ auto endRealtimeMs = android::elapsedRealtime();
+ auto endRealtimeNs = android::elapsedRealtimeNano();
+
+ EXPECT_GE(endUptimeMs - startUptimeMs, SLEEP_MS)
+ << "uptimeMillis() advanced too little after nanosleep()";
+ EXPECT_LT(endUptimeMs - startUptimeMs, SLEEP_MS + SLACK_MS)
+ << "uptimeMillis() advanced too much after nanosleep()";
+ EXPECT_GE(endRealtimeMs - startRealtimeMs, SLEEP_MS)
+ << "elapsedRealtime() advanced too little after nanosleep()";
+ EXPECT_LT(endRealtimeMs - startRealtimeMs, SLEEP_MS + SLACK_MS)
+ << "elapsedRealtime() advanced too much after nanosleep()";
+ EXPECT_GE(endRealtimeNs - startRealtimeNs, SLEEP_NS)
+ << "elapsedRealtimeNano() advanced too little after nanosleep()";
+ EXPECT_LT(endRealtimeNs - startRealtimeNs, SLEEP_NS + SLACK_NS)
+ << "elapsedRealtimeNano() advanced too much after nanosleep()";
+
+ EXPECT_GE(endRealtimeNs, endRealtimeMs * MS_IN_NS)
+ << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
+ EXPECT_LT(endRealtimeNs, (endRealtimeMs + SLACK_MS) * MS_IN_NS)
+ << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
+}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 6f7d264..b32c27d 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -33,7 +33,7 @@
#include "LogUtils.h"
#define log_id_for_each(i) \
- for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
+ for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t) ((i) + 1))
class LogStatistics;
diff --git a/rootdir/init.rc b/rootdir/init.rc
index aa32343..ef70bf2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -140,7 +140,6 @@
chown system system /dev/cpuctl
chown system system /dev/cpuctl/tasks
chmod 0666 /dev/cpuctl/tasks
- write /dev/cpuctl/cpu.shares 1024
write /dev/cpuctl/cpu.rt_runtime_us 800000
write /dev/cpuctl/cpu.rt_period_us 1000000
diff --git a/rootdir/init.usb.configfs.rc b/rootdir/init.usb.configfs.rc
index 186384b..e19b058 100644
--- a/rootdir/init.usb.configfs.rc
+++ b/rootdir/init.usb.configfs.rc
@@ -1,6 +1,7 @@
on property:sys.usb.config=none && property:sys.usb.configfs=1
write /config/usb_gadget/g1/UDC "none"
stop adbd
+ setprop sys.usb.ffs.ready 0
write /config/usb_gadget/g1/bDeviceClass 0
write /config/usb_gadget/g1/bDeviceSubClass 0
write /config/usb_gadget/g1/bDeviceProtocol 0