Merge "Add libkeyutils."
diff --git a/adb/Android.mk b/adb/Android.mk
index efdff5d..382c8cb 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -5,6 +5,8 @@
LOCAL_PATH:= $(call my-dir)
+include $(LOCAL_PATH)/../platform_tools_tool_version.mk
+
adb_host_sanitize :=
adb_target_sanitize :=
@@ -13,11 +15,11 @@
-Wno-unused-parameter \
-Wno-missing-field-initializers \
-Wvla \
- -DADB_REVISION=\"$(BUILD_NUMBER_FROM_FILE)\" \
+ -DADB_VERSION="\"$(tool_version)\"" \
ADB_COMMON_posix_CFLAGS := \
-Wexit-time-destructors \
- -Wthread-safety
+ -Wthread-safety \
ADB_COMMON_linux_CFLAGS := \
$(ADB_COMMON_posix_CFLAGS) \
@@ -230,7 +232,7 @@
libcutils \
libdiagnose_usb \
libmdnssd \
- libgmock_host
+ libgmock_host \
LOCAL_STATIC_LIBRARIES_linux := libusb
LOCAL_STATIC_LIBRARIES_darwin := libusb
@@ -298,7 +300,7 @@
libcrypto \
libdiagnose_usb \
liblog \
- libmdnssd
+ libmdnssd \
# Don't use libcutils on Windows.
LOCAL_STATIC_LIBRARIES_darwin := libcutils
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 0181daa..23f6580 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -64,9 +64,9 @@
// Don't change the format of this --- it's parsed by ddmlib.
return android::base::StringPrintf(
"Android Debug Bridge version %d.%d.%d\n"
- "Revision %s\n"
+ "Version %s\n"
"Installed as %s\n",
- ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_REVISION,
+ ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_VERSION,
android::base::GetExecutablePath().c_str());
}
@@ -1054,15 +1054,12 @@
if (strcmp(service, "kill") == 0) {
fprintf(stderr, "adb server killed by remote request\n");
fflush(stdout);
+
+ // Send a reply even though we don't read it anymore, so that old versions
+ // of adb that do read it don't spew error messages.
SendOkay(reply_fd);
- // On Windows, if the process exits with open sockets that
- // shutdown(SD_SEND) has not been called on, TCP RST segments will be
- // sent to the peers which will cause their next recv() to error-out
- // with WSAECONNRESET. In the case of this code, that means the client
- // may not read the OKAY sent above.
- adb_shutdown(reply_fd);
-
+ // Rely on process exit to close the socket for us.
android::base::quick_exit(0);
}
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 4f3ff25..f5d0f02 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -123,7 +123,7 @@
return false;
}
-int _adb_connect(const std::string& service, std::string* error) {
+static int _adb_connect(const std::string& service, std::string* error) {
D("_adb_connect: %s", service.c_str());
if (service.empty() || service.size() > MAX_PAYLOAD_V1) {
*error = android::base::StringPrintf("bad service name length (%zd)",
@@ -158,6 +158,25 @@
return fd;
}
+bool adb_kill_server() {
+ D("adb_kill_server");
+ std::string reason;
+ int fd = socket_spec_connect(__adb_server_socket_spec, &reason);
+ if (fd < 0) {
+ fprintf(stderr, "cannot connect to daemon at %s: %s\n", __adb_server_socket_spec,
+ reason.c_str());
+ return true;
+ }
+
+ if (!SendProtocolString(fd, "host:kill")) {
+ fprintf(stderr, "error: write failure during connection: %s\n", strerror(errno));
+ return false;
+ }
+
+ ReadOrderlyShutdown(fd);
+ return true;
+}
+
int adb_connect(const std::string& service, std::string* error) {
// first query the adb server's version
int fd = _adb_connect("host:version", error);
@@ -214,18 +233,7 @@
if (version != ADB_SERVER_VERSION) {
fprintf(stderr, "adb server version (%d) doesn't match this client (%d); killing...\n",
version, ADB_SERVER_VERSION);
- fd = _adb_connect("host:kill", error);
- if (fd >= 0) {
- ReadOrderlyShutdown(fd);
- adb_close(fd);
- } else {
- // If we couldn't connect to the server or had some other error,
- // report it, but still try to start the server.
- fprintf(stderr, "error: %s\n", error->c_str());
- }
-
- /* XXX can we better detect its death? */
- std::this_thread::sleep_for(2s);
+ adb_kill_server();
goto start_server;
}
}
diff --git a/adb/adb_client.h b/adb/adb_client.h
index d07c1e9..fabec00 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -26,7 +26,9 @@
// Connect to adb, connect to the named service, and return a valid fd for
// interacting with that service upon success or a negative number on failure.
int adb_connect(const std::string& service, std::string* _Nonnull error);
-int _adb_connect(const std::string& service, std::string* _Nonnull error);
+
+// Kill the currently running adb server, if it exists.
+bool adb_kill_server();
// Connect to adb, connect to the named service, returns true if the connection
// succeeded AND the service returned OKAY. Outputs any returned error otherwise.
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 18b1492..30cb29b 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -19,8 +19,12 @@
#include <stdio.h>
#include <stdlib.h>
+#include <algorithm>
+#include <list>
+
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/thread_annotations.h>
#include <cutils/sockets.h>
#include "socket_spec.h"
@@ -64,8 +68,9 @@
// listener_list retains ownership of all created alistener objects. Removing an alistener from
// this list will cause it to be deleted.
+static auto& listener_list_mutex = *new std::mutex();
typedef std::list<std::unique_ptr<alistener>> ListenerList;
-static ListenerList& listener_list = *new ListenerList();
+static ListenerList& listener_list GUARDED_BY(listener_list_mutex) = *new ListenerList();
static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
if (ev & FDE_READ) {
@@ -108,7 +113,8 @@
}
// Called as a transport disconnect function. |arg| is the raw alistener*.
-static void listener_disconnect(void* arg, atransport*) {
+static void listener_disconnect(void* arg, atransport*) EXCLUDES(listener_list_mutex) {
+ std::lock_guard<std::mutex> lock(listener_list_mutex);
for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
if (iter->get() == arg) {
(*iter)->transport = nullptr;
@@ -119,7 +125,8 @@
}
// Write the list of current listeners (network redirections) into a string.
-std::string format_listeners() {
+std::string format_listeners() EXCLUDES(listener_list_mutex) {
+ std::lock_guard<std::mutex> lock(listener_list_mutex);
std::string result;
for (auto& l : listener_list) {
// Ignore special listeners like those for *smartsocket*
@@ -135,7 +142,9 @@
return result;
}
-InstallStatus remove_listener(const char* local_name, atransport* transport) {
+InstallStatus remove_listener(const char* local_name, atransport* transport)
+ EXCLUDES(listener_list_mutex) {
+ std::lock_guard<std::mutex> lock(listener_list_mutex);
for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
if (local_name == (*iter)->local_name) {
listener_list.erase(iter);
@@ -145,7 +154,8 @@
return INSTALL_STATUS_LISTENER_NOT_FOUND;
}
-void remove_all_listeners() {
+void remove_all_listeners() EXCLUDES(listener_list_mutex) {
+ std::lock_guard<std::mutex> lock(listener_list_mutex);
auto iter = listener_list.begin();
while (iter != listener_list.end()) {
// Never remove smart sockets.
@@ -157,9 +167,18 @@
}
}
+void close_smartsockets() EXCLUDES(listener_list_mutex) {
+ std::lock_guard<std::mutex> lock(listener_list_mutex);
+ auto pred = [](const std::unique_ptr<alistener>& listener) {
+ return listener->local_name == "*smartsocket*";
+ };
+ listener_list.erase(std::remove_if(listener_list.begin(), listener_list.end(), pred));
+}
+
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* error) EXCLUDES(listener_list_mutex) {
+ std::lock_guard<std::mutex> lock(listener_list_mutex);
for (auto& l : listener_list) {
if (local_name == l->local_name) {
// Can't repurpose a smartsocket.
@@ -212,7 +231,7 @@
if (transport) {
listener->disconnect.opaque = listener.get();
- listener->disconnect.func = listener_disconnect;
+ listener->disconnect.func = listener_disconnect;
transport->AddDisconnect(&listener->disconnect);
}
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 8eba00a..70a2ee1 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -41,4 +41,6 @@
InstallStatus remove_listener(const char* local_name, atransport* transport);
void remove_all_listeners(void);
+void close_smartsockets();
+
#endif /* __ADB_LISTENERS_H */
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index fe5099c..bd9ad01 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -92,6 +92,16 @@
}
#endif
+void adb_server_cleanup() {
+ // Upon exit, we want to clean up in the following order:
+ // 1. close_smartsockets, so that we don't get any new clients
+ // 2. kick_all_transports, to avoid writing only part of a packet to a transport.
+ // 3. usb_cleanup, to tear down the USB stack.
+ close_smartsockets();
+ kick_all_transports();
+ usb_cleanup();
+}
+
int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd) {
#if defined(_WIN32)
// adb start-server starts us up with stdout and stderr hooked up to
@@ -111,12 +121,13 @@
SetConsoleCtrlHandler(ctrlc_handler, TRUE);
#else
signal(SIGINT, [](int) {
- android::base::quick_exit(0);
+ fdevent_run_on_main_thread([]() { android::base::quick_exit(0); });
});
#endif
- init_transport_registration();
+ android::base::at_quick_exit(adb_server_cleanup);
+ init_transport_registration();
init_mdns_transport_discovery();
usb_init();
diff --git a/adb/client/usb_dispatch.cpp b/adb/client/usb_dispatch.cpp
index 710a3ce..ce57731 100644
--- a/adb/client/usb_dispatch.cpp
+++ b/adb/client/usb_dispatch.cpp
@@ -27,6 +27,14 @@
}
}
+void usb_cleanup() {
+ if (should_use_libusb()) {
+ libusb::usb_cleanup();
+ } else {
+ native::usb_cleanup();
+ }
+}
+
int usb_write(usb_handle* h, const void* data, int len) {
return should_use_libusb()
? libusb::usb_write(reinterpret_cast<libusb::usb_handle*>(h), data, len)
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 15d4b7a..18a8ff2 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -152,7 +152,9 @@
static auto& usb_handles_mutex = *new std::mutex();
static std::thread* device_poll_thread = nullptr;
-static std::atomic<bool> terminate_device_poll_thread(false);
+static bool terminate_device_poll_thread = false;
+static auto& device_poll_mutex = *new std::mutex();
+static auto& device_poll_cv = *new std::condition_variable();
static std::string get_device_address(libusb_device* device) {
return StringPrintf("usb:%d:%d", libusb_get_bus_number(device),
@@ -376,7 +378,7 @@
static void poll_for_devices() {
libusb_device** list;
adb_thread_setname("device poll");
- while (!terminate_device_poll_thread) {
+ while (true) {
const ssize_t device_count = libusb_get_device_list(nullptr, &list);
LOG(VERBOSE) << "found " << device_count << " attached devices";
@@ -389,7 +391,10 @@
adb_notify_device_scan_complete();
- std::this_thread::sleep_for(500ms);
+ std::unique_lock<std::mutex> lock(device_poll_mutex);
+ if (device_poll_cv.wait_for(lock, 500ms, []() { return terminate_device_poll_thread; })) {
+ return;
+ }
}
}
@@ -410,11 +415,21 @@
// Spawn a thread to do device enumeration.
// TODO: Use libusb_hotplug_* instead?
+ std::unique_lock<std::mutex> lock(device_poll_mutex);
device_poll_thread = new std::thread(poll_for_devices);
- android::base::at_quick_exit([]() {
+}
+
+void usb_cleanup() {
+ {
+ std::unique_lock<std::mutex> lock(device_poll_mutex);
terminate_device_poll_thread = true;
- device_poll_thread->join();
- });
+
+ if (!device_poll_thread) {
+ return;
+ }
+ }
+ device_poll_cv.notify_all();
+ device_poll_thread->join();
}
// Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result.
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index f9ba7cb..a7df0ed 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -598,4 +598,7 @@
std::thread(device_poll_thread).detach();
}
+
+void usb_cleanup() {}
+
} // namespace native
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index e366754..4e1480f 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -430,7 +430,7 @@
VLOG(USB) << "RunLoopThread done";
}
-static void usb_cleanup() NO_THREAD_SAFETY_ANALYSIS {
+void usb_cleanup() NO_THREAD_SAFETY_ANALYSIS {
VLOG(USB) << "usb_cleanup";
// Wait until usb operations in RunLoopThread finish, and prevent further operations.
operate_device_lock.lock();
@@ -440,8 +440,6 @@
void usb_init() {
static bool initialized = false;
if (!initialized) {
- atexit(usb_cleanup);
-
usb_inited_flag = false;
std::thread(RunLoopThread).detach();
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index ec55b0e..1620e6e 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -265,6 +265,8 @@
std::thread(_power_notification_thread).detach();
}
+void usb_cleanup() {}
+
usb_handle* do_usb_open(const wchar_t* interface_name) {
unsigned long name_len = 0;
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index a9b1540..f49c69d 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1546,25 +1546,7 @@
return 0;
}
else if (!strcmp(argv[0], "kill-server")) {
- std::string error;
- int fd = _adb_connect("host:kill", &error);
- if (fd == -2) {
- // Failed to make network connection to server. Don't output the
- // network error since that is expected.
- fprintf(stderr,"* server not running *\n");
- // Successful exit code because the server is already "killed".
- return 0;
- } else if (fd == -1) {
- // Some other error.
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
- } else {
- // Successfully connected, kill command sent, okay status came back.
- // Server should exit() in a moment, if not already.
- ReadOrderlyShutdown(fd);
- adb_close(fd);
- return 0;
- }
+ return adb_kill_server() ? 0 : 1;
}
else if (!strcmp(argv[0], "sideload")) {
if (argc != 2) return syntax_error("sideload requires an argument");
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 7a87df4..1c94298 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -107,10 +107,10 @@
// AID_SDCARD_RW to allow writing to the SD card
// AID_NET_BW_STATS to read out qtaguid statistics
// AID_READPROC for reading /proc entries across UID boundaries
- gid_t groups[] = {AID_ADB, AID_LOG, AID_INPUT,
- AID_INET, AID_NET_BT, AID_NET_BT_ADMIN,
- AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
- AID_READPROC};
+ // AID_UHID for using 'hid' command to read/write to /dev/uhid
+ gid_t groups[] = {AID_ADB, AID_LOG, AID_INPUT, AID_INET,
+ AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
+ AID_NET_BW_STATS, AID_READPROC, AID_UHID};
minijail_set_supplementary_gids(jail.get(), arraysize(groups), groups);
// Don't listen on a port (default 5037) if running in secure mode.
@@ -233,9 +233,8 @@
adb_device_banner = optarg;
break;
case 'v':
- printf("Android Debug Bridge Daemon version %d.%d.%d %s\n",
- ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION,
- ADB_REVISION);
+ printf("Android Debug Bridge Daemon version %d.%d.%d (%s)\n", ADB_VERSION_MAJOR,
+ ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_VERSION);
return 0;
default:
// getopt already prints "adbd: invalid option -- %c" for us.
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 20de642..13cfaa1 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -568,15 +568,14 @@
transport_registration_func, 0);
fdevent_set(&transport_registration_fde, FDE_READ);
-#if ADB_HOST
- android::base::at_quick_exit([]() {
- // To avoid only writing part of a packet to a transport after exit, kick all transports.
- std::lock_guard<std::mutex> lock(transport_lock);
- for (auto t : transport_list) {
- t->Kick();
- }
- });
-#endif
+}
+
+void kick_all_transports() {
+ // To avoid only writing part of a packet to a transport after exit, kick all transports.
+ std::lock_guard<std::mutex> lock(transport_lock);
+ for (auto t : transport_list) {
+ t->Kick();
+ }
}
/* the fdevent select pump is single threaded */
diff --git a/adb/transport.h b/adb/transport.h
index e129355..006aaf4 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -207,6 +207,7 @@
std::string list_transports(bool long_listing);
atransport* find_transport(const char* serial);
void kick_all_tcp_devices();
+void kick_all_transports();
void register_usb_transport(usb_handle* h, const char* serial,
const char* devpath, unsigned writeable);
diff --git a/adb/usb.h b/adb/usb.h
index e867ec8..f428ede 100644
--- a/adb/usb.h
+++ b/adb/usb.h
@@ -22,6 +22,7 @@
#define ADB_USB_INTERFACE(handle_ref_type) \
void usb_init(); \
+ void usb_cleanup(); \
int usb_write(handle_ref_type h, const void* data, int len); \
int usb_read(handle_ref_type h, void* data, int len); \
int usb_close(handle_ref_type h); \
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index e78edbb..fa0d922 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -164,6 +164,24 @@
using ::android::base::FATAL; \
return (severity); }())
+#ifdef __clang_analyzer__
+// Clang's static analyzer does not see the conditional statement inside
+// LogMessage's destructor that will abort on FATAL severity.
+#define ABORT_AFTER_LOG_FATAL for (;; abort())
+
+struct LogAbortAfterFullExpr {
+ ~LogAbortAfterFullExpr() __attribute__((noreturn)) { abort(); }
+ explicit operator bool() const { return false; }
+};
+// Provides an expression that evaluates to the truthiness of `x`, automatically
+// aborting if `c` is true.
+#define ABORT_AFTER_LOG_EXPR_IF(c, x) (((c) && ::android::base::LogAbortAfterFullExpr()) || (x))
+#else
+#define ABORT_AFTER_LOG_FATAL
+#define ABORT_AFTER_LOG_EXPR_IF(c, x) (x)
+#endif
+#define ABORT_AFTER_LOG_FATAL_EXPR(x) ABORT_AFTER_LOG_EXPR_IF(true, x)
+
// Defines whether the given severity will be logged or silently swallowed.
#define WOULD_LOG(severity) \
UNLIKELY((SEVERITY_LAMBDA(severity)) >= ::android::base::GetMinimumLogSeverity())
@@ -190,54 +208,47 @@
// LOG(FATAL) << "We didn't expect to reach here";
#define LOG(severity) LOG_TO(DEFAULT, severity)
+// Checks if we want to log something, and sets up appropriate RAII objects if
+// so.
+// Note: DO NOT USE DIRECTLY. This is an implementation detail.
+#define LOGGING_PREAMBLE(severity) \
+ (WOULD_LOG(severity) && \
+ ABORT_AFTER_LOG_EXPR_IF((SEVERITY_LAMBDA(severity)) == ::android::base::FATAL, true) && \
+ ::android::base::ErrnoRestorer())
+
// Logs a message to logcat with the specified log ID on Android otherwise to
// stderr. If the severity is FATAL it also causes an abort.
-// Use an if-else statement instead of just an if statement here. So if there is a
-// else statement after LOG() macro, it won't bind to the if statement in the macro.
-// do-while(0) statement doesn't work here. Because we need to support << operator
-// following the macro, like "LOG(DEBUG) << xxx;".
-
-#define LOG_TO(dest, severity) \
- WOULD_LOG(severity) && \
- ::android::base::ErrnoRestorer() && \
- LOG_STREAM_TO(dest, severity)
+// Use an expression here so we can support the << operator following the macro,
+// like "LOG(DEBUG) << xxx;".
+#define LOG_TO(dest, severity) LOGGING_PREAMBLE(severity) && LOG_STREAM_TO(dest, severity)
// A variant of LOG that also logs the current errno value. To be used when
// library calls fail.
#define PLOG(severity) PLOG_TO(DEFAULT, severity)
// Behaves like PLOG, but logs to the specified log ID.
-#define PLOG_TO(dest, severity) \
- WOULD_LOG(SEVERITY_LAMBDA(severity)) && \
- ::android::base::ErrnoRestorer() && \
- ::android::base::LogMessage(__FILE__, __LINE__, \
- ::android::base::dest, \
- SEVERITY_LAMBDA(severity), errno).stream()
+#define PLOG_TO(dest, severity) \
+ LOGGING_PREAMBLE(severity) && \
+ ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \
+ SEVERITY_LAMBDA(severity), errno) \
+ .stream()
// Marker that code is yet to be implemented.
#define UNIMPLEMENTED(level) \
LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
-#ifdef __clang_analyzer__
-// ClangL static analyzer does not see the conditional statement inside
-// LogMessage's destructor that will abort on FATAL severity.
-#define ABORT_AFTER_LOG_FATAL for (;;abort())
-#else
-#define ABORT_AFTER_LOG_FATAL
-#endif
-
// Check whether condition x holds and LOG(FATAL) if not. The value of the
// expression x is only evaluated once. Extra logging can be appended using <<
// after. For example:
//
// CHECK(false == true) results in a log message of
// "Check failed: false == true".
-#define CHECK(x) \
- LIKELY((x)) || \
- ABORT_AFTER_LOG_FATAL \
- ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
- ::android::base::FATAL, -1).stream() \
- << "Check failed: " #x << " "
+#define CHECK(x) \
+ LIKELY((x)) || ABORT_AFTER_LOG_FATAL_EXPR(false) || \
+ ::android::base::LogMessage( \
+ __FILE__, __LINE__, ::android::base::DEFAULT, ::android::base::FATAL, \
+ -1).stream() \
+ << "Check failed: " #x << " "
// Helper for CHECK_xx(x,y) macros.
#define CHECK_OP(LHS, RHS, OP) \
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index eb5578f..37d54d7 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -221,7 +221,6 @@
"libbase",
"liblog",
"libprocinfo",
- "libselinux",
],
}
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 88f390b..d2a4239 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -42,7 +42,6 @@
#include <cutils/sockets.h>
#include <log/log.h>
#include <procinfo/process.h>
-#include <selinux/selinux.h>
#include "backtrace.h"
#include "tombstone.h"
diff --git a/debuggerd/libdebuggerd/arm/machine.cpp b/debuggerd/libdebuggerd/arm/machine.cpp
index 78c2306..ac833ae 100644
--- a/debuggerd/libdebuggerd/arm/machine.cpp
+++ b/debuggerd/libdebuggerd/arm/machine.cpp
@@ -48,6 +48,21 @@
}
}
+#define DUMP_GP_REGISTERS(log, reg_prefix) \
+ _LOG(log, logtype::REGISTERS, " r0 %08x r1 %08x r2 %08x r3 %08x\n", \
+ static_cast<uint32_t>(reg_prefix##r0), static_cast<uint32_t>(reg_prefix##r1), \
+ static_cast<uint32_t>(reg_prefix##r2), static_cast<uint32_t>(reg_prefix##r3)); \
+ _LOG(log, logtype::REGISTERS, " r4 %08x r5 %08x r6 %08x r7 %08x\n", \
+ static_cast<uint32_t>(reg_prefix##r4), static_cast<uint32_t>(reg_prefix##r5), \
+ static_cast<uint32_t>(reg_prefix##r6), static_cast<uint32_t>(reg_prefix##r7)); \
+ _LOG(log, logtype::REGISTERS, " r8 %08x r9 %08x sl %08x fp %08x\n", \
+ static_cast<uint32_t>(reg_prefix##r8), static_cast<uint32_t>(reg_prefix##r9), \
+ static_cast<uint32_t>(reg_prefix##r10), static_cast<uint32_t>(reg_prefix##fp)); \
+ _LOG(log, logtype::REGISTERS, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", \
+ static_cast<uint32_t>(reg_prefix##ip), static_cast<uint32_t>(reg_prefix##sp), \
+ static_cast<uint32_t>(reg_prefix##lr), static_cast<uint32_t>(reg_prefix##pc), \
+ static_cast<uint32_t>(reg_prefix##cpsr))
+
void dump_registers(log_t* log, pid_t tid) {
pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
@@ -55,19 +70,7 @@
return;
}
- _LOG(log, logtype::REGISTERS, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
- static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1),
- static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3));
- _LOG(log, logtype::REGISTERS, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
- static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5),
- static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7));
- _LOG(log, logtype::REGISTERS, " r8 %08x r9 %08x sl %08x fp %08x\n",
- static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9),
- static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp));
- _LOG(log, logtype::REGISTERS, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
- static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp),
- static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc),
- static_cast<uint32_t>(r.ARM_cpsr));
+ DUMP_GP_REGISTERS(log, r.ARM_);
user_vfp vfp_regs;
if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
@@ -81,3 +84,7 @@
}
_LOG(log, logtype::FP_REGISTERS, " scr %08lx\n", vfp_regs.fpscr);
}
+
+void dump_registers(log_t* log, const ucontext_t* uc) {
+ DUMP_GP_REGISTERS(log, uc->uc_mcontext.arm_);
+}
diff --git a/debuggerd/libdebuggerd/arm64/machine.cpp b/debuggerd/libdebuggerd/arm64/machine.cpp
index e7bf79a..fa73c99a 100644
--- a/debuggerd/libdebuggerd/arm64/machine.cpp
+++ b/debuggerd/libdebuggerd/arm64/machine.cpp
@@ -52,6 +52,17 @@
}
}
+#define DUMP_GP_REGISTERS(log) \
+ for (int i = 0; i < 28; i += 4) { \
+ const char* fmt = " x%-2d %016llx x%-2d %016llx x%-2d %016llx x%-2d %016llx\n"; \
+ _LOG(log, logtype::REGISTERS, fmt, i, r.regs[i], i + 1, r.regs[i + 1], i + 2, r.regs[i + 2], \
+ i + 3, r.regs[i + 3]); \
+ } \
+ _LOG(log, logtype::REGISTERS, " x28 %016llx x29 %016llx x30 %016llx\n", r.regs[28], \
+ r.regs[29], r.regs[30]); \
+ _LOG(log, logtype::REGISTERS, " sp %016llx pc %016llx pstate %016llx\n", r.sp, r.pc, \
+ r.pstate)
+
void dump_registers(log_t* log, pid_t tid) {
struct user_pt_regs r;
struct iovec io;
@@ -63,20 +74,7 @@
return;
}
- for (int i = 0; i < 28; i += 4) {
- _LOG(log, logtype::REGISTERS,
- " x%-2d %016llx x%-2d %016llx x%-2d %016llx x%-2d %016llx\n",
- i, r.regs[i],
- i+1, r.regs[i+1],
- i+2, r.regs[i+2],
- i+3, r.regs[i+3]);
- }
-
- _LOG(log, logtype::REGISTERS, " x28 %016llx x29 %016llx x30 %016llx\n",
- r.regs[28], r.regs[29], r.regs[30]);
-
- _LOG(log, logtype::REGISTERS, " sp %016llx pc %016llx pstate %016llx\n",
- r.sp, r.pc, r.pstate);
+ DUMP_GP_REGISTERS(log);
struct user_fpsimd_state f;
io.iov_base = &f;
@@ -99,3 +97,8 @@
}
_LOG(log, logtype::FP_REGISTERS, " fpsr %08x fpcr %08x\n", f.fpsr, f.fpcr);
}
+
+void dump_registers(log_t* log, const ucontext_t* ucontext) {
+ const mcontext_t& r = ucontext->uc_mcontext;
+ DUMP_GP_REGISTERS(log);
+}
diff --git a/debuggerd/libdebuggerd/include/machine.h b/debuggerd/libdebuggerd/include/machine.h
index e65b147..5e56682 100644
--- a/debuggerd/libdebuggerd/include/machine.h
+++ b/debuggerd/libdebuggerd/include/machine.h
@@ -25,5 +25,6 @@
void dump_memory_and_code(log_t* log, Backtrace* backtrace);
void dump_registers(log_t* log, pid_t tid);
+void dump_registers(log_t* log, const ucontext_t* uc);
#endif // _DEBUGGERD_MACHINE_H
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 0c38449..edc7be5 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -470,6 +470,11 @@
}
}
+// Weak noop implementation, real implementations are in <arch>/machine.cpp.
+__attribute__((weak)) void dump_registers(log_t* log, const ucontext_t*) {
+ _LOG(log, logtype::REGISTERS, " register dumping unimplemented on this architecture");
+}
+
static void dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name,
const std::string& thread_name, BacktraceMap* map,
uintptr_t abort_msg_address, bool primary_thread) {
@@ -749,11 +754,15 @@
read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
+ _LOG(&log, logtype::HEADER, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
+ dump_header_info(&log);
dump_thread_info(&log, pid, tid, thread_name, process_name);
dump_signal_info(&log, siginfo);
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid));
dump_abort_message(backtrace.get(), &log, abort_msg_address);
+ dump_registers(&log, ucontext);
+
// TODO: Dump registers from the ucontext.
if (backtrace->Unwind(0, ucontext)) {
dump_backtrace_and_stack(backtrace.get(), &log);
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index e675d7d..80def73 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -14,8 +14,12 @@
LOCAL_PATH:= $(call my-dir)
+include $(LOCAL_PATH)/../platform_tools_tool_version.mk
+
include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DFASTBOOT_VERSION="\"$(tool_version)\""
+
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../adb \
$(LOCAL_PATH)/../mkbootimg \
@@ -37,8 +41,6 @@
LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_CFLAGS += -DFASTBOOT_REVISION=\"$(BUILD_NUMBER_FROM_FILE)\"
-
LOCAL_SRC_FILES_linux := usb_linux.cpp
LOCAL_STATIC_LIBRARIES_linux := libselinux
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 56ee816..7e10cc9 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -258,6 +258,12 @@
return cb_check(a, status, resp, 1);
}
+static char* xstrdup(const char* s) {
+ char* result = strdup(s);
+ if (!result) die("out of memory");
+ return result;
+}
+
void fb_queue_require(const char *prod, const char *var,
bool invert, size_t nvalues, const char **value)
{
@@ -276,16 +282,14 @@
fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
return status;
}
- fprintf(stderr, "%s: %s\n", (char*) a->data, resp);
+ fprintf(stderr, "%s: %s\n", static_cast<const char*>(a->data), resp);
+ free(static_cast<char*>(a->data));
return 0;
}
-void fb_queue_display(const char *var, const char *prettyname)
-{
- Action *a;
- a = queue_action(OP_QUERY, "getvar:%s", var);
- a->data = strdup(prettyname);
- if (a->data == nullptr) die("out of memory");
+void fb_queue_display(const char* var, const char* prettyname) {
+ Action* a = queue_action(OP_QUERY, "getvar:%s", var);
+ a->data = xstrdup(prettyname);
a->func = cb_display;
}
@@ -298,11 +302,9 @@
return 0;
}
-void fb_queue_query_save(const char *var, char *dest, uint32_t dest_size)
-{
- Action *a;
- a = queue_action(OP_QUERY, "getvar:%s", var);
- a->data = (void *)dest;
+void fb_queue_query_save(const char* var, char* dest, uint32_t dest_size) {
+ Action* a = queue_action(OP_QUERY, "getvar:%s", var);
+ a->data = dest;
a->size = dest_size;
a->func = cb_save;
}
@@ -342,15 +344,13 @@
a->msg = mkmsg("sending '%s' (%d KB)", name, sz / 1024);
}
-void fb_queue_upload(char *outfile)
-{
- Action *a = queue_action(OP_UPLOAD, "");
- a->data = outfile;
+void fb_queue_upload(const char* outfile) {
+ Action* a = queue_action(OP_UPLOAD, "");
+ a->data = xstrdup(outfile);
a->msg = mkmsg("uploading '%s'", outfile);
}
-void fb_queue_notice(const char *notice)
-{
+void fb_queue_notice(const char* notice) {
Action *a = queue_action(OP_NOTICE, "");
a->data = (void*) notice;
}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 5d5ac9b..8a6877a 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -135,17 +135,17 @@
return android::base::StringPrintf("%s/%s", dir, img_name);
}
-std::string find_item(const char* item) {
+static std::string find_item(const std::string& item) {
for (size_t i = 0; i < arraysize(images); ++i) {
- if (images[i].nickname && !strcmp(images[i].nickname, item)) {
+ if (images[i].nickname && item == images[i].nickname) {
return find_item_given_name(images[i].img_name);
}
}
- if (!strcmp(item, "userdata")) return find_item_given_name("userdata.img");
- if (!strcmp(item, "cache")) return find_item_given_name("cache.img");
+ if (item == "userdata") return find_item_given_name("userdata.img");
+ if (item == "cache") return find_item_given_name("cache.img");
- fprintf(stderr, "unknown partition '%s'\n", item);
+ fprintf(stderr, "unknown partition '%s'\n", item.c_str());
return "";
}
@@ -305,8 +305,21 @@
usb_open(list_devices_callback);
}
-static void usage() {
- fprintf(stderr,
+static void syntax_error(const char* fmt, ...) {
+ fprintf(stderr, "fastboot: usage: ");
+
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+static int show_help() {
+ // clang-format off
+ fprintf(stdout,
/* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */
"usage: fastboot [ <option> ] <command>\n"
"\n"
@@ -344,7 +357,7 @@
" set_active <slot> Sets the active slot. If slots are\n"
" not supported, this does nothing.\n"
" boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
- " flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
+ " flash:raw <bootable-partition> <kernel> [ <ramdisk> [ <second> ] ]\n"
" Create bootimage and flash it.\n"
" devices [-l] List all connected devices [with\n"
" device paths].\n"
@@ -413,31 +426,22 @@
" --version Display version.\n"
" -h, --help show this message.\n"
);
+ // clang-format off
+ return 0;
}
-static void* load_bootable_image(const char* kernel, const char* ramdisk,
- const char* secondstage, int64_t* sz,
+static void* load_bootable_image(const std::string& kernel, const std::string& ramdisk,
+ const std::string& second_stage, int64_t* sz,
const char* cmdline) {
- if (kernel == nullptr) {
- fprintf(stderr, "no image specified\n");
- return 0;
- }
-
int64_t ksize;
- void* kdata = load_file(kernel, &ksize);
- if (kdata == nullptr) {
- fprintf(stderr, "cannot load '%s': %s\n", kernel, strerror(errno));
- return 0;
- }
+ void* kdata = load_file(kernel.c_str(), &ksize);
+ if (kdata == nullptr) die("cannot load '%s': %s\n", kernel.c_str(), strerror(errno));
// Is this actually a boot image?
- if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+ if (!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
if (cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
- if (ramdisk) {
- fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
- return 0;
- }
+ if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk\n");
*sz = ksize;
return kdata;
@@ -445,22 +449,16 @@
void* rdata = nullptr;
int64_t rsize = 0;
- if (ramdisk) {
- rdata = load_file(ramdisk, &rsize);
- if (rdata == nullptr) {
- fprintf(stderr,"cannot load '%s': %s\n", ramdisk, strerror(errno));
- return 0;
- }
+ if (!ramdisk.empty()) {
+ rdata = load_file(ramdisk.c_str(), &rsize);
+ if (rdata == nullptr) die("cannot load '%s': %s\n", ramdisk.c_str(), strerror(errno));
}
void* sdata = nullptr;
int64_t ssize = 0;
- if (secondstage) {
- sdata = load_file(secondstage, &ssize);
- if (sdata == nullptr) {
- fprintf(stderr,"cannot load '%s': %s\n", secondstage, strerror(errno));
- return 0;
- }
+ if (!second_stage.empty()) {
+ sdata = load_file(second_stage.c_str(), &ssize);
+ if (sdata == nullptr) die("cannot load '%s': %s\n", second_stage.c_str(), strerror(errno));
}
fprintf(stderr,"creating boot image...\n");
@@ -469,10 +467,8 @@
rdata, rsize, ramdisk_offset,
sdata, ssize, second_offset,
page_size, base_addr, tags_offset, &bsize);
- if (bdata == nullptr) {
- fprintf(stderr,"failed to create boot.img\n");
- return 0;
- }
+ if (bdata == nullptr) die("failed to create boot.img\n");
+
if (cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", bsize);
*sz = bsize;
@@ -1244,41 +1240,33 @@
}
}
-#define skip(n) do { argc -= (n); argv += (n); } while (0)
-#define require(n) do { if (argc < (n)) {usage(); exit(1);}} while (0)
-
-static int do_bypass_unlock_command(int argc, char **argv)
-{
- if (argc <= 2) return 0;
- skip(2);
-
- /*
- * Process unlock_bootloader, we have to load the message file
- * and send that to the remote device.
- */
- require(1);
-
- int64_t sz;
- void* data = load_file(*argv, &sz);
- if (data == nullptr) die("could not load '%s': %s", *argv, strerror(errno));
- fb_queue_download("unlock_message", data, sz);
- fb_queue_command("flashing unlock_bootloader", "unlocking bootloader");
- skip(1);
- return 0;
+static std::string next_arg(std::vector<std::string>* args) {
+ if (args->empty()) syntax_error("expected argument");
+ std::string result = args->front();
+ args->erase(args->begin());
+ return result;
}
-static int do_oem_command(int argc, char** argv) {
- if (argc <= 1) return 0;
+static void do_bypass_unlock_command(std::vector<std::string>* args) {
+ if (args->empty()) syntax_error("missing unlock_bootloader request");
- std::string command;
- while (argc > 0) {
- command += *argv;
- skip(1);
- if (argc != 0) command += " ";
+ std::string filename = next_arg(args);
+
+ int64_t sz;
+ void* data = load_file(filename.c_str(), &sz);
+ if (data == nullptr) die("could not load '%s': %s", filename.c_str(), strerror(errno));
+ fb_queue_download("unlock_message", data, sz);
+ fb_queue_command("flashing unlock_bootloader", "unlocking bootloader");
+}
+
+static void do_oem_command(std::vector<std::string>* args) {
+ if (args->empty()) syntax_error("empty oem command");
+
+ std::string command("oem");
+ while (!args->empty()) {
+ command += " " + next_arg(args);
}
-
fb_queue_command(command.c_str(), "");
- return 0;
}
static int64_t parse_num(const char *arg)
@@ -1354,7 +1342,7 @@
static void fb_perform_format(Transport* transport,
const char* partition, int skip_if_not_supported,
- const char* type_override, const char* size_override,
+ const std::string& type_override, const std::string& size_override,
const std::string& initial_dir) {
std::string partition_type, partition_size;
@@ -1375,10 +1363,10 @@
errMsg = "Can't determine partition type.\n";
goto failed;
}
- if (type_override) {
+ if (!type_override.empty()) {
if (partition_type != type_override) {
fprintf(stderr, "Warning: %s type is %s, but %s was requested for formatting.\n",
- partition, partition_type.c_str(), type_override);
+ partition, partition_type.c_str(), type_override.c_str());
}
partition_type = type_override;
}
@@ -1387,10 +1375,10 @@
errMsg = "Unable to get partition size\n";
goto failed;
}
- if (size_override) {
+ if (!size_override.empty()) {
if (partition_size != size_override) {
fprintf(stderr, "Warning: %s size is %s, but %s was requested for formatting.\n",
- partition, partition_size.c_str(), size_override);
+ partition, partition_size.c_str(), size_override.c_str());
}
partition_size = size_override;
}
@@ -1505,8 +1493,7 @@
cmdline = optarg;
break;
case 'h':
- usage();
- return 1;
+ return show_help();
case 'i': {
char *endptr = nullptr;
unsigned long val;
@@ -1555,7 +1542,7 @@
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
} else if (strcmp("version", longopts[longindex].name) == 0) {
- fprintf(stdout, "fastboot version %s\n", FASTBOOT_REVISION);
+ fprintf(stdout, "fastboot version %s\n", FASTBOOT_VERSION);
fprintf(stdout, "Installed as %s\n", android::base::GetExecutablePath().c_str());
return 0;
} else if (strcmp("slot", longopts[longindex].name) == 0) {
@@ -1583,20 +1570,15 @@
argc -= optind;
argv += optind;
- if (argc == 0 && !wants_wipe && !wants_set_active) {
- usage();
- return 1;
- }
+ if (argc == 0 && !wants_wipe && !wants_set_active) syntax_error("no command");
if (argc > 0 && !strcmp(*argv, "devices")) {
- skip(1);
list_devices();
return 0;
}
if (argc > 0 && !strcmp(*argv, "help")) {
- usage();
- return 0;
+ return show_help();
}
Transport* transport = open_device();
@@ -1625,17 +1607,19 @@
}
}
- while (argc > 0) {
- if (!strcmp(*argv, "getvar")) {
- require(2);
- fb_queue_display(argv[1], argv[1]);
- skip(2);
- } else if(!strcmp(*argv, "erase")) {
- require(2);
+ std::vector<std::string> args(argv, argv + argc);
+ while (!args.empty()) {
+ std::string command = next_arg(&args);
- auto erase = [&](const std::string &partition) {
+ if (command == "getvar") {
+ std::string variable = next_arg(&args);
+ fb_queue_display(variable.c_str(), variable.c_str());
+ } else if (command == "erase") {
+ std::string partition = next_arg(&args);
+ auto erase = [&](const std::string& partition) {
std::string partition_type;
- if (fb_getvar(transport, std::string("partition-type:") + argv[1], &partition_type) &&
+ if (fb_getvar(transport, std::string("partition-type:") + partition,
+ &partition_type) &&
fs_get_generator(partition_type) != nullptr) {
fprintf(stderr, "******** Did you mean to fastboot format this %s partition?\n",
partition_type.c_str());
@@ -1643,106 +1627,79 @@
fb_queue_erase(partition.c_str());
};
- do_for_partitions(transport, argv[1], slot_override, erase, true);
- skip(2);
- } else if(!strncmp(*argv, "format", strlen("format"))) {
- char *overrides;
- char *type_override = nullptr;
- char *size_override = nullptr;
- require(2);
- /*
- * Parsing for: "format[:[type][:[size]]]"
- * Some valid things:
- * - select ontly the size, and leave default fs type:
- * format::0x4000000 userdata
- * - default fs type and size:
- * format userdata
- * format:: userdata
- */
- overrides = strchr(*argv, ':');
- if (overrides) {
- overrides++;
- size_override = strchr(overrides, ':');
- if (size_override) {
- size_override[0] = '\0';
- size_override++;
- }
- type_override = overrides;
- }
- if (type_override && !type_override[0]) type_override = nullptr;
- if (size_override && !size_override[0]) size_override = nullptr;
+ do_for_partitions(transport, partition, slot_override, erase, true);
+ } else if (android::base::StartsWith(command, "format")) {
+ // Parsing for: "format[:[type][:[size]]]"
+ // Some valid things:
+ // - select only the size, and leave default fs type:
+ // format::0x4000000 userdata
+ // - default fs type and size:
+ // format userdata
+ // format:: userdata
+ std::vector<std::string> pieces = android::base::Split(command, ":");
+ std::string type_override;
+ if (pieces.size() > 1) type_override = pieces[1].c_str();
+ std::string size_override;
+ if (pieces.size() > 2) size_override = pieces[2].c_str();
- auto format = [&](const std::string &partition) {
+ std::string partition = next_arg(&args);
+
+ auto format = [&](const std::string& partition) {
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
}
- fb_perform_format(transport, partition.c_str(), 0,
- type_override, size_override, "");
+ fb_perform_format(transport, partition.c_str(), 0, type_override, size_override,
+ "");
};
- do_for_partitions(transport, argv[1], slot_override, format, true);
- skip(2);
- } else if(!strcmp(*argv, "signature")) {
- require(2);
- data = load_file(argv[1], &sz);
- if (data == nullptr) die("could not load '%s': %s", argv[1], strerror(errno));
+ do_for_partitions(transport, partition.c_str(), slot_override, format, true);
+ } else if (command == "signature") {
+ std::string filename = next_arg(&args);
+ data = load_file(filename.c_str(), &sz);
+ if (data == nullptr) die("could not load '%s': %s", filename.c_str(), strerror(errno));
if (sz != 256) die("signature must be 256 bytes");
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
- skip(2);
- } else if(!strcmp(*argv, "reboot")) {
+ } else if (command == "reboot") {
wants_reboot = true;
- skip(1);
- if (argc > 0) {
- if (!strcmp(*argv, "bootloader")) {
+
+ if (args.size() == 1) {
+ std::string what = next_arg(&args);
+ if (what == "bootloader") {
wants_reboot = false;
wants_reboot_bootloader = true;
- skip(1);
- } else if (!strcmp(*argv, "emergency")) {
+ } else if (what == "emergency") {
wants_reboot = false;
wants_reboot_emergency = true;
- skip(1);
+ } else {
+ syntax_error("unknown reboot target %s", what.c_str());
}
+
}
- require(0);
- } else if(!strcmp(*argv, "reboot-bootloader")) {
+ if (!args.empty()) syntax_error("junk after reboot command");
+ } else if (command == "reboot-bootloader") {
wants_reboot_bootloader = true;
- skip(1);
- } else if (!strcmp(*argv, "continue")) {
+ } else if (command == "continue") {
fb_queue_command("continue", "resuming boot");
- skip(1);
- } else if(!strcmp(*argv, "boot")) {
- char *kname = 0;
- char *rname = 0;
- char *sname = 0;
- skip(1);
- if (argc > 0) {
- kname = argv[0];
- skip(1);
- }
- if (argc > 0) {
- rname = argv[0];
- skip(1);
- }
- if (argc > 0) {
- sname = argv[0];
- skip(1);
- }
- data = load_bootable_image(kname, rname, sname, &sz, cmdline);
- if (data == 0) return 1;
+ } else if (command == "boot") {
+ std::string kernel = next_arg(&args);
+ std::string ramdisk;
+ if (!args.empty()) ramdisk = next_arg(&args);
+ std::string second_stage;
+ if (!args.empty()) second_stage = next_arg(&args);
+
+ data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline);
fb_queue_download("boot.img", data, sz);
fb_queue_command("boot", "booting");
- } else if(!strcmp(*argv, "flash")) {
- char* pname = argv[1];
+ } else if (command == "flash") {
+ std::string pname = next_arg(&args);
+
std::string fname;
- require(2);
- if (argc > 2) {
- fname = argv[2];
- skip(3);
+ if (!args.empty()) {
+ fname = next_arg(&args);
} else {
fname = find_item(pname);
- skip(2);
}
- if (fname.empty()) die("cannot determine image filename for '%s'", pname);
+ if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str());
auto flash = [&](const std::string &partition) {
if (erase_first && needs_erase(transport, partition.c_str())) {
@@ -1750,29 +1707,21 @@
}
do_flash(transport, partition.c_str(), fname.c_str());
};
- do_for_partitions(transport, pname, slot_override, flash, true);
- } else if(!strcmp(*argv, "flash:raw")) {
- char *kname = argv[2];
- char *rname = 0;
- char *sname = 0;
- require(3);
- skip(3);
- if (argc > 0) {
- rname = argv[0];
- skip(1);
- }
- if (argc > 0) {
- sname = argv[0];
- skip(1);
- }
- data = load_bootable_image(kname, rname, sname, &sz, cmdline);
- if (data == 0) die("cannot load bootable image");
- auto flashraw = [&](const std::string &partition) {
+ do_for_partitions(transport, pname.c_str(), slot_override, flash, true);
+ } else if (command == "flash:raw") {
+ std::string partition = next_arg(&args);
+ std::string kernel = next_arg(&args);
+ std::string ramdisk;
+ if (!args.empty()) ramdisk = next_arg(&args);
+ std::string second_stage;
+ if (!args.empty()) second_stage = next_arg(&args);
+
+ data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline);
+ auto flashraw = [&](const std::string& partition) {
fb_queue_flash(partition.c_str(), data, sz);
};
- do_for_partitions(transport, argv[1], slot_override, flashraw, true);
- } else if(!strcmp(*argv, "flashall")) {
- skip(1);
+ do_for_partitions(transport, partition, slot_override, flashraw, true);
+ } else if (command == "flashall") {
if (slot_override == "all") {
fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
do_flashall(transport, slot_override, erase_first, true);
@@ -1780,22 +1729,21 @@
do_flashall(transport, slot_override, erase_first, skip_secondary);
}
wants_reboot = true;
- } else if(!strcmp(*argv, "update")) {
+ } else if (command == "update") {
bool slot_all = (slot_override == "all");
if (slot_all) {
fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
}
- if (argc > 1) {
- do_update(transport, argv[1], slot_override, erase_first, skip_secondary || slot_all);
- skip(2);
- } else {
- do_update(transport, "update.zip", slot_override, erase_first, skip_secondary || slot_all);
- skip(1);
+ std::string filename = "update.zip";
+ if (!args.empty()) {
+ filename = next_arg(&args);
}
+ do_update(transport, filename.c_str(), slot_override, erase_first,
+ skip_secondary || slot_all);
wants_reboot = true;
- } else if(!strcmp(*argv, "set_active")) {
- require(2);
- std::string slot = verify_slot(transport, std::string(argv[1]), false);
+ } else if (command == "set_active") {
+ std::string slot = verify_slot(transport, next_arg(&args), false);
+
// Legacy support: verify_slot() removes leading underscores, we need to put them back
// in for old bootloaders. Legacy bootloaders do not have the slot-count variable but
// do have slot-suffixes.
@@ -1805,42 +1753,36 @@
slot = "_" + slot;
}
fb_set_active(slot.c_str());
- skip(2);
- } else if(!strcmp(*argv, "stage")) {
- require(2);
- std::string infile(argv[1]);
- skip(2);
+ } else if (command == "stage") {
+ std::string filename = next_arg(&args);
+
struct fastboot_buffer buf;
- if (!load_buf(transport, infile.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
- die("cannot load '%s'", infile.c_str());
+ if (!load_buf(transport, filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
+ die("cannot load '%s'", filename.c_str());
}
- fb_queue_download_fd(infile.c_str(), buf.fd, buf.sz);
- } else if(!strcmp(*argv, "get_staged")) {
- require(2);
- char *outfile = argv[1];
- skip(2);
- fb_queue_upload(outfile);
- } else if(!strcmp(*argv, "oem")) {
- argc = do_oem_command(argc, argv);
- } else if(!strcmp(*argv, "flashing")) {
- if (argc == 2 && (!strcmp(*(argv+1), "unlock") ||
- !strcmp(*(argv+1), "lock") ||
- !strcmp(*(argv+1), "unlock_critical") ||
- !strcmp(*(argv+1), "lock_critical") ||
- !strcmp(*(argv+1), "get_unlock_ability") ||
- !strcmp(*(argv+1), "get_unlock_bootloader_nonce") ||
- !strcmp(*(argv+1), "lock_bootloader"))) {
- argc = do_oem_command(argc, argv);
- } else
- if (argc == 3 && !strcmp(*(argv+1), "unlock_bootloader")) {
- argc = do_bypass_unlock_command(argc, argv);
+ fb_queue_download_fd(filename.c_str(), buf.fd, buf.sz);
+ } else if (command == "get_staged") {
+ std::string filename = next_arg(&args);
+ fb_queue_upload(filename.c_str());
+ } else if (command == "oem") {
+ do_oem_command(&args);
+ } else if (command == "flashing") {
+ if (args.empty()) {
+ syntax_error("missing 'flashing' command");
+ } else if (args.size() == 1 && (args[0] == "unlock" || args[0] == "lock" ||
+ args[0] == "unlock_critical" ||
+ args[0] == "lock_critical" ||
+ args[0] == "get_unlock_ability" ||
+ args[0] == "get_unlock_bootloader_nonce" ||
+ args[0] == "lock_bootloader")) {
+ do_oem_command(&args);
+ } else if (args.size() == 2 && args[0] == "unlock_bootloader") {
+ do_bypass_unlock_command(&args);
} else {
- usage();
- return 1;
+ syntax_error("unknown 'flashing' command %s", args[0].c_str());
}
} else {
- usage();
- return 1;
+ syntax_error("unknown command %s", command.c_str());
}
}
@@ -1853,17 +1795,17 @@
if (initial_userdata_dir.empty()) {
return 1;
}
- fb_perform_format(transport, "userdata", 1, nullptr, nullptr, initial_userdata_dir);
+ fb_perform_format(transport, "userdata", 1, "", "", initial_userdata_dir);
delete_fbemarker_tmpdir(initial_userdata_dir);
} else {
- fb_perform_format(transport, "userdata", 1, nullptr, nullptr, "");
+ fb_perform_format(transport, "userdata", 1, "", "", "");
}
std::string cache_type;
if (fb_getvar(transport, "partition-type:cache", &cache_type) && !cache_type.empty()) {
fprintf(stderr, "wiping cache...\n");
fb_queue_erase("cache");
- fb_perform_format(transport, "cache", 1, nullptr, nullptr, "");
+ fb_perform_format(transport, "cache", 1, "", "", "");
}
}
if (wants_set_active) {
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index e30c6de..e3c60ae 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -66,7 +66,7 @@
void fb_queue_command(const char *cmd, const char *msg);
void fb_queue_download(const char *name, void *data, uint32_t size);
void fb_queue_download_fd(const char *name, int fd, uint32_t sz);
-void fb_queue_upload(char *outfile);
+void fb_queue_upload(const char* outfile);
void fb_queue_notice(const char *notice);
void fb_queue_wait_for_disconnect(void);
int64_t fb_execute_queue(Transport* transport);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 60ce43e..df3c300 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -744,23 +744,6 @@
}
}
-static std::string extract_by_name_prefix(struct fstab* fstab) {
- // We assume that there's an entry for the /misc mount point in the
- // fstab file and use that to get the device file by-name prefix.
- // The device needs not to have an actual /misc partition.
- // e.g.,
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/
- struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
- if (fstab_entry == nullptr) {
- LERROR << "/misc mount point not found in fstab";
- return "";
- }
- std::string full_path(fstab_entry->blk_device);
- size_t end_slash = full_path.find_last_of("/");
- return full_path.substr(0, end_slash + 1);
-}
-
// TODO: add ueventd notifiers if they don't exist.
// This is just doing a wait_for_device for maximum of 1s
int fs_mgr_test_access(const char *device) {
@@ -850,7 +833,7 @@
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
- avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab));
+ avb_handle = FsManagerAvbHandle::Open(*fstab);
if (!avb_handle) {
LERROR << "Failed to open FsManagerAvbHandle";
return FS_MGR_MNTALL_FAIL;
@@ -1060,7 +1043,7 @@
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
- avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab));
+ avb_handle = FsManagerAvbHandle::Open(*fstab);
if (!avb_handle) {
LERROR << "Failed to open FsManagerAvbHandle";
return FS_MGR_DOMNT_FAILED;
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 31babfe..2b32201 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "fs_mgr_avb.h"
+
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -38,9 +40,8 @@
#include <utils/Compat.h>
#include "fs_mgr.h"
-#include "fs_mgr_avb.h"
-#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_avb_ops.h"
#include "fs_mgr_priv_dm_ioctl.h"
#include "fs_mgr_priv_sha.h"
@@ -457,12 +458,21 @@
return true;
}
-FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const std::string& device_file_by_name_prefix) {
- if (device_file_by_name_prefix.empty()) {
- LERROR << "Missing device file by-name prefix";
+FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const fstab& fstab) {
+ FsManagerAvbOps avb_ops(fstab);
+ return DoOpen(&avb_ops);
+}
+
+FsManagerAvbUniquePtr FsManagerAvbHandle::Open(ByNameSymlinkMap&& by_name_symlink_map) {
+ if (by_name_symlink_map.empty()) {
+ LERROR << "Empty by_name_symlink_map when opening FsManagerAvbHandle";
return nullptr;
}
+ FsManagerAvbOps avb_ops(std::move(by_name_symlink_map));
+ return DoOpen(&avb_ops);
+}
+FsManagerAvbUniquePtr FsManagerAvbHandle::DoOpen(FsManagerAvbOps* avb_ops) {
// Gets the expected hash value of vbmeta images from kernel cmdline.
std::unique_ptr<FsManagerAvbVerifier> avb_verifier = FsManagerAvbVerifier::Create();
if (!avb_verifier) {
@@ -476,9 +486,11 @@
return nullptr;
}
- FsManagerAvbOps avb_ops(device_file_by_name_prefix);
- AvbSlotVerifyResult verify_result = avb_ops.AvbSlotVerify(
- fs_mgr_get_slot_suffix(), avb_verifier->IsDeviceUnlocked(), &avb_handle->avb_slot_data_);
+ AvbSlotVerifyFlags flags = avb_verifier->IsDeviceUnlocked()
+ ? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
+ : AVB_SLOT_VERIFY_FLAGS_NONE;
+ AvbSlotVerifyResult verify_result =
+ avb_ops->AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &avb_handle->avb_slot_data_);
// Only allow two verify results:
// - AVB_SLOT_VERIFY_RESULT_OK.
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index caee4ec..512839b 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -22,6 +22,8 @@
* SOFTWARE.
*/
+#include "fs_mgr_priv_avb_ops.h"
+
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -36,7 +38,6 @@
#include <utils/Compat.h>
#include "fs_mgr.h"
-#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
@@ -88,11 +89,7 @@
return AVB_IO_RESULT_OK;
}
-FsManagerAvbOps::FsManagerAvbOps(const std::string& device_file_by_name_prefix)
- : device_file_by_name_prefix_(device_file_by_name_prefix) {
- if (device_file_by_name_prefix_.back() != '/') {
- device_file_by_name_prefix_ += '/';
- }
+void FsManagerAvbOps::InitializeAvbOps() {
// We only need to provide the implementation of read_from_partition()
// operation since that's all what is being used by the avb_slot_verify().
// Other I/O operations are only required in bootloader but not in
@@ -109,13 +106,31 @@
avb_ops_.user_data = this;
}
+FsManagerAvbOps::FsManagerAvbOps(std::map<std::string, std::string>&& by_name_symlink_map)
+ : by_name_symlink_map_(std::move(by_name_symlink_map)) {
+ InitializeAvbOps();
+}
+
+FsManagerAvbOps::FsManagerAvbOps(const fstab& fstab) {
+ // Constructs the by-name symlink map for each fstab record.
+ // /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a =>
+ // by_name_symlink_map_["system_a"] = "/dev/block/platform/soc.0/7824900.sdhci/by-name/system_a"
+ for (int i = 0; i < fstab.num_entries; i++) {
+ std::string partition_name = basename(fstab.recs[i].blk_device);
+ by_name_symlink_map_[partition_name] = fstab.recs[i].blk_device;
+ }
+ InitializeAvbOps();
+}
+
AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
size_t num_bytes, void* buffer,
size_t* out_num_read) {
- // Appends |partition| to the device_file_by_name_prefix_, e.g.,
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
- std::string path = device_file_by_name_prefix_ + partition;
+ const auto iter = by_name_symlink_map_.find(partition);
+ if (iter == by_name_symlink_map_.end()) {
+ LERROR << "by-name symlink not found for partition: '" << partition << "'";
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+ }
+ std::string path = iter->second;
// Ensures the device path (a symlink created by init) is ready to
// access. fs_mgr_test_access() will test a few iterations if the
@@ -126,7 +141,7 @@
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd < 0) {
- PERROR << "Failed to open " << path.c_str();
+ PERROR << "Failed to open " << path;
return AVB_IO_RESULT_ERROR_IO;
}
@@ -150,8 +165,7 @@
// for EOF).
ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
if (num_read < 0 || (size_t)num_read != num_bytes) {
- PERROR << "Failed to read " << num_bytes << " bytes from " << path.c_str() << " offset "
- << offset;
+ PERROR << "Failed to read " << num_bytes << " bytes from " << path << " offset " << offset;
return AVB_IO_RESULT_ERROR_IO;
}
@@ -163,13 +177,15 @@
}
AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix,
- bool allow_verification_error,
+ AvbSlotVerifyFlags flags,
AvbSlotVerifyData** out_data) {
// Invokes avb_slot_verify() to load and verify all vbmeta images.
// Sets requested_partitions to nullptr as it's to copy the contents
// of HASH partitions into handle>avb_slot_data_, which is not required as
// fs_mgr only deals with HASHTREE partitions.
const char* requested_partitions[] = {nullptr};
- return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(),
- allow_verification_error, out_data);
+ // The |hashtree_error_mode| field doesn't matter as it only
+ // influences the generated kernel cmdline parameters.
+ return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), flags,
+ AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, out_data);
}
diff --git a/fs_mgr/fs_mgr_avb_ops.h b/fs_mgr/fs_mgr_priv_avb_ops.h
similarity index 85%
rename from fs_mgr/fs_mgr_avb_ops.h
rename to fs_mgr/fs_mgr_priv_avb_ops.h
index ec4a8c9..d1ef2e9 100644
--- a/fs_mgr/fs_mgr_avb_ops.h
+++ b/fs_mgr/fs_mgr_priv_avb_ops.h
@@ -22,8 +22,11 @@
* SOFTWARE.
*/
-#ifndef __CORE_FS_MGR_AVB_OPS_H
-#define __CORE_FS_MGR_AVB_OPS_H
+#ifndef __CORE_FS_MGR_PRIV_AVB_OPS_H
+#define __CORE_FS_MGR_PRIV_AVB_OPS_H
+
+#include <map>
+#include <string>
#include <libavb/libavb.h>
@@ -43,7 +46,8 @@
//
class FsManagerAvbOps {
public:
- FsManagerAvbOps(const std::string& device_file_by_name_prefix);
+ FsManagerAvbOps(const fstab& fstab);
+ FsManagerAvbOps(std::map<std::string, std::string>&& by_name_symlink_map);
static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) {
return reinterpret_cast<FsManagerAvbOps*>(ops->user_data);
@@ -52,11 +56,13 @@
AvbIOResult ReadFromPartition(const char* partition, int64_t offset, size_t num_bytes,
void* buffer, size_t* out_num_read);
- AvbSlotVerifyResult AvbSlotVerify(const std::string& ab_suffix, bool allow_verification_error,
+ AvbSlotVerifyResult AvbSlotVerify(const std::string& ab_suffix, AvbSlotVerifyFlags flags,
AvbSlotVerifyData** out_data);
private:
+ void InitializeAvbOps();
+
AvbOps avb_ops_;
- std::string device_file_by_name_prefix_;
+ std::map<std::string, std::string> by_name_symlink_map_;
};
-#endif /* __CORE_FS_MGR_AVB_OPS_H */
+#endif /* __CORE_FS_MGR_PRIV_AVB_OPS_H */
diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/include/fs_mgr_avb.h
index 65ff9941..bbafe1a 100644
--- a/fs_mgr/include/fs_mgr_avb.h
+++ b/fs_mgr/include/fs_mgr_avb.h
@@ -17,6 +17,7 @@
#ifndef __CORE_FS_MGR_AVB_H
#define __CORE_FS_MGR_AVB_H
+#include <map>
#include <memory>
#include <string>
@@ -31,9 +32,13 @@
kFsManagerAvbHandleErrorVerification = 2,
};
+class FsManagerAvbOps;
+
class FsManagerAvbHandle;
using FsManagerAvbUniquePtr = std::unique_ptr<FsManagerAvbHandle>;
+using ByNameSymlinkMap = std::map<std::string, std::string>;
+
// Provides a factory method to return a unique_ptr pointing to itself and the
// SetUpAvb() function to extract dm-verity parameters from AVB metadata to
// load verity table into kernel through ioctl.
@@ -49,6 +54,13 @@
// A typical usage will be:
// - FsManagerAvbUniquePtr handle = FsManagerAvbHandle::Open();
//
+ // There are two overloaded Open() functions with a single parameter.
+ // The argument can be a ByNameSymlinkMap describing the mapping from partition
+ // name to by-name symlink, or a fstab file to which the ByNameSymlinkMap is
+ // constructed from. e.g.,
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a ->
+ // - ByNameSymlinkMap["system_a"] = "/dev/block/platform/soc.0/7824900.sdhci/by-name/system_a"
+ //
// Possible return values:
// - nullptr: any error when reading and verifying the metadata,
// e.g., I/O error, digest value mismatch, size mismatch, etc.
@@ -61,7 +73,8 @@
// - a valid unique_ptr with status kFsMgrAvbHandleSuccess: the metadata
// is verified and can be trusted.
//
- static FsManagerAvbUniquePtr Open(const std::string& device_file_by_name_prefix);
+ static FsManagerAvbUniquePtr Open(const fstab& fstab);
+ static FsManagerAvbUniquePtr Open(ByNameSymlinkMap&& by_name_symlink_map);
// Sets up dm-verity on the given fstab entry.
// The 'wait_for_verity_dev' parameter makes this function wait for the
@@ -88,10 +101,10 @@
}
};
- protected:
- FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleUninitialized) {}
-
private:
+ FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleUninitialized) {}
+ static FsManagerAvbUniquePtr DoOpen(FsManagerAvbOps* avb_ops);
+
AvbSlotVerifyData* avb_slot_data_;
FsManagerAvbHandleStatus status_;
std::string avb_version_;
diff --git a/init/Android.mk b/init/Android.mk
index c7a41e3..0db65cb 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -61,6 +61,8 @@
endif
include $(CLEAR_VARS)
+# b/38002385, work around clang-tidy segmentation fault.
+LOCAL_TIDY_CHECKS := -misc-forwarding-reference-overload
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES:= \
action.cpp \
@@ -82,6 +84,8 @@
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
+# b/38002385, work around clang-tidy segmentation fault.
+LOCAL_TIDY_CHECKS := -misc-forwarding-reference-overload
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES:= \
bootchart.cpp \
@@ -140,6 +144,8 @@
# Unit tests.
# =========================================================
include $(CLEAR_VARS)
+# b/38002385, work around clang-tidy segmentation fault.
+LOCAL_TIDY_CHECKS := -misc-forwarding-reference-overload
LOCAL_MODULE := init_tests
LOCAL_SRC_FILES := \
devices_test.cpp \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 27b72f9..1eacb36 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -762,7 +762,7 @@
}
} else {
in_flags = false;
- if (restorecon(args[i].c_str(), flag) < 0) {
+ if (selinux_android_restorecon(args[i].c_str(), flag) < 0) {
ret = -errno;
}
}
diff --git a/init/devices.cpp b/init/devices.cpp
index 74f099a..d8258cf 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -251,7 +251,7 @@
if (access(path.c_str(), F_OK) == 0) {
LOG(VERBOSE) << "restorecon_recursive: " << path;
- restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
+ selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
}
}
diff --git a/init/init.cpp b/init/init.cpp
index a8f5f97..8b5d15e 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -870,23 +870,23 @@
// value. This must happen before /dev is populated by ueventd.
static void selinux_restore_context() {
LOG(INFO) << "Running restorecon...";
- restorecon("/dev");
- restorecon("/dev/kmsg");
+ selinux_android_restorecon("/dev", 0);
+ selinux_android_restorecon("/dev/kmsg", 0);
if constexpr (WORLD_WRITABLE_KMSG) {
- restorecon("/dev/kmsg_debug");
+ selinux_android_restorecon("/dev/kmsg_debug", 0);
}
- restorecon("/dev/socket");
- restorecon("/dev/random");
- restorecon("/dev/urandom");
- restorecon("/dev/__properties__");
- restorecon("/plat_property_contexts");
- restorecon("/nonplat_property_contexts");
- restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
- restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
- restorecon("/dev/device-mapper");
+ selinux_android_restorecon("/dev/socket", 0);
+ selinux_android_restorecon("/dev/random", 0);
+ selinux_android_restorecon("/dev/urandom", 0);
+ selinux_android_restorecon("/dev/__properties__", 0);
+ selinux_android_restorecon("/plat_property_contexts", 0);
+ selinux_android_restorecon("/nonplat_property_contexts", 0);
+ selinux_android_restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
+ selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
+ selinux_android_restorecon("/dev/device-mapper", 0);
- restorecon("/sbin/mke2fs");
- restorecon("/sbin/e2fsdroid");
+ selinux_android_restorecon("/sbin/mke2fs", 0);
+ selinux_android_restorecon("/sbin/e2fsdroid", 0);
}
// Set the UDC controller for the ConfigFS USB Gadgets.
@@ -995,7 +995,7 @@
// We're in the kernel domain, so re-exec init to transition to the init domain now
// that the SELinux policy has been loaded.
- if (restorecon("/init") == -1) {
+ if (selinux_android_restorecon("/init", 0) == -1) {
PLOG(ERROR) << "restorecon failed";
security_failure();
}
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 2fa790d..9d2a0d1 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -47,18 +47,22 @@
bool InitDevices();
protected:
- void InitRequiredDevices(std::set<std::string>* devices_partition_names);
+ void InitRequiredDevices();
void InitVerityDevice(const std::string& verity_device);
bool MountPartitions();
- virtual bool GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
- bool* out_need_dm_verity) = 0;
+ virtual coldboot_action_t ColdbootCallback(uevent* uevent);
+
+ // Pure virtual functions.
+ virtual bool GetRequiredDevices() = 0;
virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
+ bool need_dm_verity_;
// Device tree fstab entries.
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
// Eligible first stage mount candidates, only allow /system, /vendor and/or /odm.
std::vector<fstab_rec*> mount_fstab_recs_;
+ std::set<std::string> required_devices_partition_names_;
};
class FirstStageMountVBootV1 : public FirstStageMount {
@@ -67,27 +71,26 @@
~FirstStageMountVBootV1() override = default;
protected:
- bool GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
- bool* out_need_dm_verity) override;
+ bool GetRequiredDevices() override;
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
};
class FirstStageMountVBootV2 : public FirstStageMount {
public:
+ friend void SetInitAvbVersionInRecovery();
+
FirstStageMountVBootV2();
~FirstStageMountVBootV2() override = default;
- const std::string& by_name_prefix() const { return device_tree_by_name_prefix_; }
-
protected:
- bool GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
- bool* out_need_dm_verity) override;
+ coldboot_action_t ColdbootCallback(uevent* uevent) override;
+ bool GetRequiredDevices() override;
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
bool InitAvbHandle();
std::string device_tree_vbmeta_parts_;
- std::string device_tree_by_name_prefix_;
FsManagerAvbUniquePtr avb_handle_;
+ ByNameSymlinkMap by_name_symlink_map_;
};
// Static Functions
@@ -102,7 +105,8 @@
// Class Definitions
// -----------------
-FirstStageMount::FirstStageMount() : device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
+FirstStageMount::FirstStageMount()
+ : need_dm_verity_(false), device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
if (!device_tree_fstab_) {
LOG(ERROR) << "Failed to read fstab from device tree";
return;
@@ -136,13 +140,30 @@
}
bool FirstStageMount::InitDevices() {
- bool need_dm_verity;
- std::set<std::string> devices_partition_names;
+ if (!GetRequiredDevices()) return false;
- // The partition name in devices_partition_names MUST have A/B suffix when A/B is used.
- if (!GetRequiredDevices(&devices_partition_names, &need_dm_verity)) return false;
+ InitRequiredDevices();
- if (need_dm_verity) {
+ // InitRequiredDevices() will remove found partitions from required_devices_partition_names_.
+ // So if it isn't empty here, it means some partitions are not found.
+ if (!required_devices_partition_names_.empty()) {
+ LOG(ERROR) << __FUNCTION__ << "(): partition(s) not found: "
+ << android::base::Join(required_devices_partition_names_, ", ");
+ return false;
+ } else {
+ return true;
+ }
+}
+
+// Creates devices with uevent->partition_name matching one in the member variable
+// required_devices_partition_names_. Found partitions will then be removed from it
+// for the subsequent member function to check which devices are NOT created.
+void FirstStageMount::InitRequiredDevices() {
+ if (required_devices_partition_names_.empty()) {
+ return;
+ }
+
+ if (need_dm_verity_) {
const std::string dm_path = "/devices/virtual/misc/device-mapper";
device_init(("/sys" + dm_path).c_str(), [&dm_path](uevent* uevent) -> coldboot_action_t {
if (uevent->path == dm_path) return COLDBOOT_STOP;
@@ -150,58 +171,40 @@
});
}
- bool success = false;
- InitRequiredDevices(&devices_partition_names);
-
- // InitRequiredDevices() will remove found partitions from devices_partition_names.
- // So if it isn't empty here, it means some partitions are not found.
- if (!devices_partition_names.empty()) {
- LOG(ERROR) << __FUNCTION__ << "(): partition(s) not found: "
- << android::base::Join(devices_partition_names, ", ");
- } else {
- success = true;
- }
+ device_init(nullptr,
+ [this](uevent* uevent) -> coldboot_action_t { return ColdbootCallback(uevent); });
device_close();
- return success;
}
-// Creates devices with uevent->partition_name matching one in the in/out
-// devices_partition_names. Found partitions will then be removed from the
-// devices_partition_names for the caller to check which devices are NOT created.
-void FirstStageMount::InitRequiredDevices(std::set<std::string>* devices_partition_names) {
- if (devices_partition_names->empty()) {
- return;
+coldboot_action_t FirstStageMount::ColdbootCallback(uevent* uevent) {
+ // We need platform devices to create symlinks.
+ if (uevent->subsystem == "platform") {
+ return COLDBOOT_CREATE;
}
- device_init(nullptr, [=](uevent* uevent) -> coldboot_action_t {
- // We need platform devices to create symlinks.
- if (uevent->subsystem == "platform") {
- return COLDBOOT_CREATE;
- }
- // Ignores everything that is not a block device.
- if (uevent->subsystem != "block") {
- return COLDBOOT_CONTINUE;
- }
+ // Ignores everything that is not a block device.
+ if (uevent->subsystem != "block") {
+ return COLDBOOT_CONTINUE;
+ }
- if (!uevent->partition_name.empty()) {
- // Matches partition name to create device nodes.
- // Both devices_partition_names and uevent->partition_name have A/B
- // suffix when A/B is used.
- auto iter = devices_partition_names->find(uevent->partition_name);
- if (iter != devices_partition_names->end()) {
- LOG(VERBOSE) << __FUNCTION__ << "(): found partition: " << *iter;
- devices_partition_names->erase(iter);
- if (devices_partition_names->empty()) {
- return COLDBOOT_STOP; // Found all partitions, stop coldboot.
- } else {
- return COLDBOOT_CREATE; // Creates this device and continue to find others.
- }
+ if (!uevent->partition_name.empty()) {
+ // Matches partition name to create device nodes.
+ // Both required_devices_partition_names_ and uevent->partition_name have A/B
+ // suffix when A/B is used.
+ auto iter = required_devices_partition_names_.find(uevent->partition_name);
+ if (iter != required_devices_partition_names_.end()) {
+ LOG(VERBOSE) << __FUNCTION__ << "(): found partition: " << *iter;
+ required_devices_partition_names_.erase(iter);
+ if (required_devices_partition_names_.empty()) {
+ return COLDBOOT_STOP; // Found all partitions, stop coldboot.
+ } else {
+ return COLDBOOT_CREATE; // Creates this device and continue to find others.
}
}
- // Not found a partition or find an unneeded partition, continue to find others.
- return COLDBOOT_CONTINUE;
- });
+ }
+ // Not found a partition or find an unneeded partition, continue to find others.
+ return COLDBOOT_CONTINUE;
}
// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
@@ -233,10 +236,9 @@
return true;
}
-bool FirstStageMountVBootV1::GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
- bool* out_need_dm_verity) {
+bool FirstStageMountVBootV1::GetRequiredDevices() {
std::string verity_loc_device;
- *out_need_dm_verity = false;
+ need_dm_verity_ = false;
for (auto fstab_rec : mount_fstab_recs_) {
// Don't allow verifyatboot in the first stage.
@@ -246,7 +248,7 @@
}
// Checks for verified partitions.
if (fs_mgr_is_verified(fstab_rec)) {
- *out_need_dm_verity = true;
+ need_dm_verity_ = true;
}
// Checks if verity metadata is on a separate partition. Note that it is
// not partition specific, so there must be only one additional partition
@@ -265,11 +267,11 @@
// Includes the partition names of fstab records and verity_loc_device (if any).
// Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
for (auto fstab_rec : mount_fstab_recs_) {
- out_devices_partition_names->emplace(basename(fstab_rec->blk_device));
+ required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
}
if (!verity_loc_device.empty()) {
- out_devices_partition_names->emplace(basename(verity_loc_device.c_str()));
+ required_devices_partition_names_.emplace(basename(verity_loc_device.c_str()));
}
return true;
@@ -292,15 +294,13 @@
}
// FirstStageMountVBootV2 constructor.
-// Gets the vbmeta configurations from device tree.
-// Specifically, the 'parts' and 'by_name_prefix' below.
+// Gets the vbmeta partitions from device tree.
// /{
// firmware {
// android {
// vbmeta {
// compatible = "android,vbmeta";
// parts = "vbmeta,boot,system,vendor"
-// by_name_prefix = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/"
// };
// };
// };
@@ -310,31 +310,24 @@
PLOG(ERROR) << "Failed to read vbmeta/parts from device tree";
return;
}
-
- // TODO: removes by_name_prefix to allow partitions on different block devices.
- if (!read_android_dt_file("vbmeta/by_name_prefix", &device_tree_by_name_prefix_)) {
- PLOG(ERROR) << "Failed to read vbmeta/by_name_prefix from dt";
- return;
- }
}
-bool FirstStageMountVBootV2::GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
- bool* out_need_dm_verity) {
- *out_need_dm_verity = false;
+bool FirstStageMountVBootV2::GetRequiredDevices() {
+ need_dm_verity_ = false;
// fstab_rec->blk_device has A/B suffix.
for (auto fstab_rec : mount_fstab_recs_) {
if (fs_mgr_is_avb(fstab_rec)) {
- *out_need_dm_verity = true;
+ need_dm_verity_ = true;
}
- out_devices_partition_names->emplace(basename(fstab_rec->blk_device));
+ required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
}
// libavb verifies AVB metadata on all verified partitions at once.
// e.g., The device_tree_vbmeta_parts_ will be "vbmeta,boot,system,vendor"
// for libavb to verify metadata, even if there is only /vendor in the
// above mount_fstab_recs_.
- if (*out_need_dm_verity) {
+ if (need_dm_verity_) {
if (device_tree_vbmeta_parts_.empty()) {
LOG(ERROR) << "Missing vbmeta parts in device tree";
return false;
@@ -342,16 +335,45 @@
std::vector<std::string> partitions = android::base::Split(device_tree_vbmeta_parts_, ",");
std::string ab_suffix = fs_mgr_get_slot_suffix();
for (const auto& partition : partitions) {
- // out_devices_partition_names is of type std::set so it's not an issue to emplace
- // a partition twice. e.g., /vendor might be in both places:
+ // required_devices_partition_names_ is of type std::set so it's not an issue
+ // to emplace a partition twice. e.g., /vendor might be in both places:
// - device_tree_vbmeta_parts_ = "vbmeta,boot,system,vendor"
// - mount_fstab_recs_: /vendor_a
- out_devices_partition_names->emplace(partition + ab_suffix);
+ required_devices_partition_names_.emplace(partition + ab_suffix);
}
}
return true;
}
+coldboot_action_t FirstStageMountVBootV2::ColdbootCallback(uevent* uevent) {
+ // Invokes the parent function to see if any desired partition has been found.
+ // If yes, record the by-name symlink for creating FsManagerAvbHandle later.
+ coldboot_action_t parent_callback_ret = FirstStageMount::ColdbootCallback(uevent);
+
+ // Skips the uevent if the parent function returns COLDBOOT_CONTINUE (meaning
+ // that the uevent was skipped) or there is no uevent->partition_name to
+ // create the by-name symlink.
+ if (parent_callback_ret != COLDBOOT_CONTINUE && !uevent->partition_name.empty()) {
+ // get_block_device_symlinks() will return three symlinks at most, depending on
+ // the content of uevent. by-name symlink will be at [0] if uevent->partition_name
+ // is not empty. e.g.,
+ // - /dev/block/platform/soc.0/f9824900.sdhci/by-name/modem
+ // - /dev/block/platform/soc.0/f9824900.sdhci/by-num/p1
+ // - /dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1
+ std::vector<std::string> links = get_block_device_symlinks(uevent);
+ if (!links.empty()) {
+ auto[it, inserted] = by_name_symlink_map_.emplace(uevent->partition_name, links[0]);
+ if (!inserted) {
+ LOG(ERROR) << "Partition '" << uevent->partition_name
+ << "' already existed in the by-name symlink map with a value of '"
+ << it->second << "', new value '" << links[0] << "' will be ignored.";
+ }
+ }
+ }
+
+ return parent_callback_ret;
+}
+
bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
if (fs_mgr_is_avb(fstab_rec)) {
if (!InitAvbHandle()) return false;
@@ -371,7 +393,14 @@
bool FirstStageMountVBootV2::InitAvbHandle() {
if (avb_handle_) return true; // Returns true if the handle is already initialized.
- avb_handle_ = FsManagerAvbHandle::Open(device_tree_by_name_prefix_);
+ if (by_name_symlink_map_.empty()) {
+ LOG(ERROR) << "by_name_symlink_map_ is empty";
+ return false;
+ }
+
+ avb_handle_ = FsManagerAvbHandle::Open(std::move(by_name_symlink_map_));
+ by_name_symlink_map_.clear(); // Removes all elements after the above std::move().
+
if (!avb_handle_) {
PLOG(ERROR) << "Failed to open FsManagerAvbHandle";
return false;
@@ -427,7 +456,8 @@
return;
}
- FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open(avb_first_mount.by_name_prefix());
+ FsManagerAvbUniquePtr avb_handle =
+ FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
if (!avb_handle) {
PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
return;
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 7722750..18e47e3 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -177,7 +177,7 @@
}
if (name == "selinux.restorecon_recursive" && valuelen > 0) {
- if (restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+ if (selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
LOG(ERROR) << "Failed to restorecon_recursive " << value;
}
}
diff --git a/init/service.cpp b/init/service.cpp
index 296c04c..7c931da 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -209,21 +209,33 @@
}
void Service::KillProcessGroup(int signal) {
- LOG(INFO) << "Sending signal " << signal
- << " to service '" << name_
- << "' (pid " << pid_ << ") process group...";
- int r;
- if (signal == SIGTERM) {
- r = killProcessGroupOnce(uid_, pid_, signal);
- } else {
- r = killProcessGroup(uid_, pid_, signal);
- }
- if (r == -1) {
- LOG(ERROR) << "killProcessGroup(" << uid_ << ", " << pid_ << ", " << signal << ") failed";
- }
- if (kill(-pid_, signal) == -1) {
+ // We ignore reporting errors of ESRCH as this commonly happens in the below case,
+ // 1) Terminate() is called, which sends SIGTERM to the process
+ // 2) The process successfully exits
+ // 3) ReapOneProcess() is called, which calls waitpid(-1, ...) which removes the pid entry.
+ // 4) Reap() is called, which sends SIGKILL, but the pid no longer exists.
+ // TODO: sigaction for SIGCHLD reports the pid of the exiting process,
+ // we should do this kill with that pid first before calling waitpid().
+ if (kill(-pid_, signal) == -1 && errno != ESRCH) {
PLOG(ERROR) << "kill(" << pid_ << ", " << signal << ") failed";
}
+
+ // If we've already seen a successful result from killProcessGroup*(), then we have removed
+ // the cgroup already and calling these functions a second time will simply result in an error.
+ // This is true regardless of which signal was sent.
+ // These functions handle their own logging, so no additional logging is needed.
+ if (!process_cgroup_empty_) {
+ LOG(INFO) << "Sending signal " << signal << " to service '" << name_ << "' (pid " << pid_
+ << ") process group...";
+ int r;
+ if (signal == SIGTERM) {
+ r = killProcessGroupOnce(uid_, pid_, signal);
+ } else {
+ r = killProcessGroup(uid_, pid_, signal);
+ }
+
+ if (r == 0) process_cgroup_empty_ = true;
+ }
}
void Service::SetProcessAttributes() {
@@ -766,6 +778,7 @@
time_started_ = boot_clock::now();
pid_ = pid;
flags_ |= SVC_RUNNING;
+ process_cgroup_empty_ = false;
errno = -createProcessGroup(uid_, pid_);
if (errno != 0) {
diff --git a/init/service.h b/init/service.h
index 426577f..b9c270a 100644
--- a/init/service.h
+++ b/init/service.h
@@ -107,6 +107,7 @@
int ioprio_pri() const { return ioprio_pri_; }
int priority() const { return priority_; }
int oom_score_adjust() const { return oom_score_adjust_; }
+ bool process_cgroup_empty() const { return process_cgroup_empty_; }
const std::vector<std::string>& args() const { return args_; }
private:
@@ -179,6 +180,8 @@
int oom_score_adjust_;
+ bool process_cgroup_empty_ = false;
+
std::vector<std::string> args_;
};
diff --git a/init/service_test.cpp b/init/service_test.cpp
index 4493f25..b9c4627 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -45,6 +45,7 @@
EXPECT_EQ(0, service_in_old_memory->ioprio_pri());
EXPECT_EQ(0, service_in_old_memory->priority());
EXPECT_EQ(-1000, service_in_old_memory->oom_score_adjust());
+ EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
for (std::size_t i = 0; i < memory_size; ++i) {
old_memory[i] = 0xFF;
@@ -64,4 +65,5 @@
EXPECT_EQ(0, service_in_old_memory2->ioprio_pri());
EXPECT_EQ(0, service_in_old_memory2->priority());
EXPECT_EQ(-1000, service_in_old_memory2->oom_score_adjust());
+ EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
}
diff --git a/init/util.cpp b/init/util.cpp
index 5afe285..75f81b9 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -266,11 +266,6 @@
return rc;
}
-int restorecon(const char* pathname, int flags)
-{
- return selinux_android_restorecon(pathname, flags);
-}
-
/*
* Writes hex_len hex characters (1/2 byte) to hex from bytes.
*/
diff --git a/init/util.h b/init/util.h
index f3252c2..1ad6b77 100644
--- a/init/util.h
+++ b/init/util.h
@@ -68,7 +68,6 @@
void import_kernel_cmdline(bool in_qemu,
const std::function<void(const std::string&, const std::string&, bool)>&);
int make_dir(const char* path, mode_t mode, selabel_handle* sehandle);
-int restorecon(const char *pathname, int flags = 0);
std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
bool is_dir(const char* pathname);
bool expand_props(const std::string& src, std::string* dst);
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index fdead23..48b50a5 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -152,6 +152,7 @@
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
#define AID_READPROC 3009 /* Allow /proc read access */
#define AID_WAKELOCK 3010 /* Allow system wakelock read/write access */
+#define AID_UHID 3011 /* Allow read/write to /dev/uhid node */
/* The range 5000-5999 is also reserved for OEM, and must never be used here. */
#define AID_OEM_RESERVED_2_START 5000
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 5fc7e35..83064fd 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -297,9 +297,9 @@
while (isspace(*cp) && (*cp != '\n')) ++cp;
const char* fmt = NULL;
size_t fmtLen = 0;
- if (*cp != '#') {
+ if (*cp && (*cp != '#')) {
fmt = cp;
- while ((*cp != '\n') && (*cp != '#')) ++cp;
+ while (*cp && (*cp != '\n') && (*cp != '#')) ++cp;
while ((cp > fmt) && isspace(*(cp - 1))) --cp;
fmtLen = cp - fmt;
}
@@ -309,7 +309,7 @@
// recorded for the same uid, but recording that
// unused detail in our database is too burdensome.
bool verbose = true;
- while ((*cp != '#') && (*cp != '\n')) ++cp;
+ while (*cp && (*cp != '#') && (*cp != '\n')) ++cp;
if (*cp == '#') {
do {
++cp;
@@ -317,7 +317,7 @@
verbose = !!fastcmp<strncmp>(cp, "uid=", strlen("uid="));
}
- while (*cp != '\n') ++cp;
+ while (*cp && (*cp != '\n')) ++cp;
#ifdef DEBUG
fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - pData), pData);
#endif
diff --git a/libnativeloader/include/nativeloader/dlext_namespaces.h b/libnativeloader/include/nativeloader/dlext_namespaces.h
index ac64f71..9121277 100644
--- a/libnativeloader/include/nativeloader/dlext_namespaces.h
+++ b/libnativeloader/include/nativeloader/dlext_namespaces.h
@@ -55,6 +55,12 @@
* permitted_path from the caller's namespace.
*/
ANDROID_NAMESPACE_TYPE_SHARED = 2,
+
+ /* This flag instructs linker to enable grey-list workaround for the namespace.
+ * See http://b/26394120 for details.
+ */
+ ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000,
+
ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
ANDROID_NAMESPACE_TYPE_ISOLATED,
};
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index f3391d1..d9cb90d 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -99,6 +99,7 @@
LibraryNamespaces() : initialized_(false) { }
bool Create(JNIEnv* env,
+ uint32_t target_sdk_version,
jobject class_loader,
bool is_shared,
jstring java_library_path,
@@ -141,6 +142,10 @@
namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
}
+ if (target_sdk_version < 24) {
+ namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
+ }
+
NativeLoaderNamespace parent_ns;
bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
@@ -397,12 +402,12 @@
jstring library_path,
jstring permitted_path) {
#if defined(__ANDROID__)
- UNUSED(target_sdk_version);
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
std::string error_msg;
NativeLoaderNamespace ns;
bool success = g_namespaces->Create(env,
+ target_sdk_version,
class_loader,
is_shared,
library_path,
@@ -439,7 +444,14 @@
if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
- if (!g_namespaces->Create(env, class_loader, false, library_path, nullptr, &ns, error_msg)) {
+ if (!g_namespaces->Create(env,
+ target_sdk_version,
+ class_loader,
+ false,
+ library_path,
+ nullptr,
+ &ns,
+ error_msg)) {
return nullptr;
}
}
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 37e4dbf..1974f2c 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -1,6 +1,7 @@
cc_library {
srcs: ["processgroup.cpp"],
name: "libprocessgroup",
+ defaults: ["linux_bionic_supported"],
shared_libs: ["libbase"],
export_include_dirs: ["include"],
cflags: [
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 47f6ff3..f0c3795 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -22,8 +22,13 @@
__BEGIN_DECLS
+// Return 0 and removes the cgroup if there are no longer any processes in it.
+// Returns -1 in the case of an error occurring or if there are processes still running
+// even after retrying for up to 200ms.
int killProcessGroup(uid_t uid, int initialPid, int signal);
+// Returns the same as killProcessGroup(), however it does not retry, which means
+// that it only returns 0 in the case that the cgroup exists and it contains no processes.
int killProcessGroupOnce(uid_t uid, int initialPid, int signal);
int createProcessGroup(uid_t uid, int initialPid);
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 1572cb3..27b4065 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -34,6 +34,7 @@
#include <thread>
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include <private/android_filesystem_config.h>
#include <processgroup/processgroup.h>
@@ -64,12 +65,27 @@
std::once_flag init_path_flag;
-struct ctx {
- bool initialized;
- int fd;
- char buf[128];
- char *buf_ptr;
- size_t buf_len;
+class ProcessGroup {
+ public:
+ ProcessGroup() : buf_ptr_(buf_), buf_len_(0) {}
+
+ bool Open(uid_t uid, int pid);
+
+ // Return positive number and sets *pid = next pid in process cgroup on success
+ // Returns 0 if there are no pids left in the process cgroup
+ // Returns -errno if an error was encountered
+ int GetOneAppProcess(pid_t* pid);
+
+ private:
+ // Returns positive number of bytes filled on success
+ // Returns 0 if there was nothing to read
+ // Returns -errno if an error was encountered
+ int RefillBuffer();
+
+ android::base::unique_fd fd_;
+ char buf_[128];
+ char* buf_ptr_;
+ size_t buf_len_;
};
static const char* getCgroupRootPath() {
@@ -105,87 +121,67 @@
pid);
}
-static int initCtx(uid_t uid, int pid, struct ctx *ctx)
-{
- int ret;
+bool ProcessGroup::Open(uid_t uid, int pid) {
char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
convertUidPidToPath(path, sizeof(path), uid, pid);
strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
int fd = open(path, O_RDONLY);
- if (fd < 0) {
- ret = -errno;
- PLOG(WARNING) << "failed to open " << path;
- return ret;
- }
+ if (fd < 0) return false;
- ctx->fd = fd;
- ctx->buf_ptr = ctx->buf;
- ctx->buf_len = 0;
- ctx->initialized = true;
+ fd_.reset(fd);
LOG(VERBOSE) << "Initialized context for " << path;
- return 0;
+ return true;
}
-static int refillBuffer(struct ctx *ctx)
-{
- memmove(ctx->buf, ctx->buf_ptr, ctx->buf_len);
- ctx->buf_ptr = ctx->buf;
+int ProcessGroup::RefillBuffer() {
+ memmove(buf_, buf_ptr_, buf_len_);
+ buf_ptr_ = buf_;
- ssize_t ret = read(ctx->fd, ctx->buf_ptr + ctx->buf_len,
- sizeof(ctx->buf) - ctx->buf_len - 1);
+ ssize_t ret = read(fd_, buf_ptr_ + buf_len_, sizeof(buf_) - buf_len_ - 1);
if (ret < 0) {
return -errno;
} else if (ret == 0) {
return 0;
}
- ctx->buf_len += ret;
- ctx->buf[ctx->buf_len] = 0;
- LOG(VERBOSE) << "Read " << ret << " to buffer: " << ctx->buf;
+ buf_len_ += ret;
+ buf_[buf_len_] = 0;
+ LOG(VERBOSE) << "Read " << ret << " to buffer: " << buf_;
- assert(ctx->buf_len <= sizeof(ctx->buf));
+ assert(buf_len_ <= sizeof(buf_));
return ret;
}
-static pid_t getOneAppProcess(uid_t uid, int appProcessPid, struct ctx *ctx)
-{
- if (!ctx->initialized) {
- int ret = initCtx(uid, appProcessPid, ctx);
- if (ret < 0) {
- return ret;
- }
- }
+int ProcessGroup::GetOneAppProcess(pid_t* out_pid) {
+ *out_pid = 0;
- char *eptr;
- while ((eptr = (char *)memchr(ctx->buf_ptr, '\n', ctx->buf_len)) == NULL) {
- int ret = refillBuffer(ctx);
- if (ret == 0) {
- return -ERANGE;
- }
- if (ret < 0) {
- return ret;
- }
+ char* eptr;
+ while ((eptr = static_cast<char*>(memchr(buf_ptr_, '\n', buf_len_))) == nullptr) {
+ int ret = RefillBuffer();
+ if (ret <= 0) return ret;
}
*eptr = '\0';
- char *pid_eptr = NULL;
+ char* pid_eptr = nullptr;
errno = 0;
- long pid = strtol(ctx->buf_ptr, &pid_eptr, 10);
+ long pid = strtol(buf_ptr_, &pid_eptr, 10);
if (errno != 0) {
return -errno;
}
if (pid_eptr != eptr) {
- return -EINVAL;
+ errno = EINVAL;
+ return -errno;
}
- ctx->buf_len -= (eptr - ctx->buf_ptr) + 1;
- ctx->buf_ptr = eptr + 1;
+ buf_len_ -= (eptr - buf_ptr_) + 1;
+ buf_ptr_ = eptr + 1;
- return (pid_t)pid;
+ *out_pid = static_cast<pid_t>(pid);
+ return 1;
}
static int removeProcessGroup(uid_t uid, int pid)
@@ -219,8 +215,8 @@
}
snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
- LOG(VERBOSE) << "removing " << path;
- if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << path;
+ LOG(VERBOSE) << "Removing " << path;
+ if (rmdir(path) == -1) PLOG(WARNING) << "Failed to remove " << path;
}
}
}
@@ -231,7 +227,7 @@
const char* cgroup_root_path = getCgroupRootPath();
std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path), closedir);
if (root == NULL) {
- PLOG(ERROR) << "failed to open " << cgroup_root_path;
+ PLOG(ERROR) << "Failed to open " << cgroup_root_path;
} else {
dirent* dir;
while ((dir = readdir(root.get())) != nullptr) {
@@ -246,20 +242,26 @@
snprintf(path, sizeof(path), "%s/%s", cgroup_root_path, dir->d_name);
removeUidProcessGroups(path);
- LOG(VERBOSE) << "removing " << path;
- if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << path;
+ LOG(VERBOSE) << "Removing " << path;
+ if (rmdir(path) == -1) PLOG(WARNING) << "Failed to remove " << path;
}
}
}
+// Returns number of processes killed on success
+// Returns 0 if there are no processes in the process cgroup left to kill
+// Returns -errno on error
static int doKillProcessGroupOnce(uid_t uid, int initialPid, int signal) {
- int processes = 0;
- struct ctx ctx;
+ ProcessGroup process_group;
+ if (!process_group.Open(uid, initialPid)) {
+ PLOG(WARNING) << "Failed to open process cgroup uid " << uid << " pid " << initialPid;
+ return -errno;
+ }
+
+ int ret;
pid_t pid;
-
- ctx.initialized = false;
-
- while ((pid = getOneAppProcess(uid, initialPid, &ctx)) >= 0) {
+ int processes = 0;
+ while ((ret = process_group.GetOneAppProcess(&pid)) > 0 && pid >= 0) {
processes++;
if (pid == 0) {
// Should never happen... but if it does, trying to kill this
@@ -267,55 +269,68 @@
LOG(WARNING) << "Yikes, we've been told to kill pid 0! How about we don't do that?";
continue;
}
- LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid
- << " as part of process group " << initialPid;
+ LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid << " as part of process cgroup "
+ << initialPid;
if (kill(pid, signal) == -1) {
PLOG(WARNING) << "kill(" << pid << ", " << signal << ") failed";
}
}
- if (ctx.initialized) {
- close(ctx.fd);
- }
-
- return processes;
+ return ret >= 0 ? processes : ret;
}
-static int killProcessGroup(uid_t uid, int initialPid, int signal, int retry) {
+static int killProcessGroup(uid_t uid, int initialPid, int signal, int retries) {
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
+ int retry = retries;
int processes;
while ((processes = doKillProcessGroupOnce(uid, initialPid, signal)) > 0) {
- LOG(VERBOSE) << "killed " << processes << " processes for processgroup " << initialPid;
+ LOG(VERBOSE) << "Killed " << processes << " processes for processgroup " << initialPid;
if (retry > 0) {
std::this_thread::sleep_for(5ms);
--retry;
} else {
- LOG(ERROR) << "failed to kill " << processes << " processes for processgroup "
- << initialPid;
break;
}
}
- std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
+ if (processes < 0) {
+ PLOG(ERROR) << "Error encountered killing process cgroup uid " << uid << " pid "
+ << initialPid;
+ return -1;
+ }
+ std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
- LOG(VERBOSE) << "Killed process group uid " << uid << " pid " << initialPid << " in "
- << static_cast<int>(ms) << "ms, " << processes << " procs remain";
+
+ // We only calculate the number of 'processes' when killing the processes.
+ // In the retries == 0 case, we only kill the processes once and therefore
+ // will not have waited then recalculated how many processes are remaining
+ // after the first signals have been sent.
+ // Logging anything regarding the number of 'processes' here does not make sense.
if (processes == 0) {
+ if (retries > 0) {
+ LOG(INFO) << "Successfully killed process cgroup uid " << uid << " pid " << initialPid
+ << " in " << static_cast<int>(ms) << "ms";
+ }
return removeProcessGroup(uid, initialPid);
} else {
+ if (retries > 0) {
+ LOG(ERROR) << "Failed to kill process cgroup uid " << uid << " pid " << initialPid
+ << " in " << static_cast<int>(ms) << "ms, " << processes
+ << " processes remain";
+ }
return -1;
}
}
int killProcessGroup(uid_t uid, int initialPid, int signal) {
- return killProcessGroup(uid, initialPid, signal, 40 /*maxRetry*/);
+ return killProcessGroup(uid, initialPid, signal, 40 /*retries*/);
}
int killProcessGroupOnce(uid_t uid, int initialPid, int signal) {
- return killProcessGroup(uid, initialPid, signal, 0 /*maxRetry*/);
+ return killProcessGroup(uid, initialPid, signal, 0 /*retries*/);
}
static bool mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
@@ -341,14 +356,14 @@
convertUidToPath(path, sizeof(path), uid);
if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
- PLOG(ERROR) << "failed to make and chown " << path;
+ PLOG(ERROR) << "Failed to make and chown " << path;
return -errno;
}
convertUidPidToPath(path, sizeof(path), uid, initialPid);
if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
- PLOG(ERROR) << "failed to make and chown " << path;
+ PLOG(ERROR) << "Failed to make and chown " << path;
return -errno;
}
@@ -357,7 +372,7 @@
int fd = open(path, O_WRONLY);
if (fd == -1) {
int ret = -errno;
- PLOG(ERROR) << "failed to open " << path;
+ PLOG(ERROR) << "Failed to open " << path;
return ret;
}
@@ -367,7 +382,7 @@
int ret = 0;
if (write(fd, pid, len) < 0) {
ret = -errno;
- PLOG(ERROR) << "failed to write '" << pid << "' to " << path;
+ PLOG(ERROR) << "Failed to write '" << pid << "' to " << path;
}
close(fd);
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 1afa1ec..3c4d81c 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -48,8 +48,16 @@
// Constructor. Create an empty object.
FileMap::FileMap(void)
- : mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
- mDataPtr(NULL), mDataLength(0)
+ : mFileName(NULL),
+ mBasePtr(NULL),
+ mBaseLength(0),
+ mDataPtr(NULL),
+ mDataLength(0)
+#if defined(__MINGW32__)
+ ,
+ mFileHandle(INVALID_HANDLE_VALUE),
+ mFileMapping(NULL)
+#endif
{
}
@@ -65,8 +73,8 @@
other.mBasePtr = NULL;
other.mDataPtr = NULL;
#if defined(__MINGW32__)
- other.mFileHandle = 0;
- other.mFileMapping = 0;
+ other.mFileHandle = INVALID_HANDLE_VALUE;
+ other.mFileMapping = NULL;
#endif
}
@@ -84,8 +92,8 @@
#if defined(__MINGW32__)
mFileHandle = other.mFileHandle;
mFileMapping = other.mFileMapping;
- other.mFileHandle = 0;
- other.mFileMapping = 0;
+ other.mFileHandle = INVALID_HANDLE_VALUE;
+ other.mFileMapping = NULL;
#endif
return *this;
}
@@ -101,7 +109,7 @@
ALOGD("UnmapViewOfFile(%p) failed, error = %lu\n", mBasePtr,
GetLastError() );
}
- if (mFileMapping != INVALID_HANDLE_VALUE) {
+ if (mFileMapping != NULL) {
CloseHandle(mFileMapping);
}
#else
@@ -156,7 +164,7 @@
ALOGE("MapViewOfFile(%" PRId64 ", %zu) failed with error %lu\n",
adjOffset, adjLength, GetLastError() );
CloseHandle(mFileMapping);
- mFileMapping = INVALID_HANDLE_VALUE;
+ mFileMapping = NULL;
return false;
}
#else // !defined(__MINGW32__)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 9c07472..786fb14 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -31,6 +31,7 @@
#include <string>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <gtest/gtest.h>
#include <log/event_tag_map.h>
#include <log/log.h>
@@ -80,8 +81,13 @@
logcat_define(ctx);
#undef LOG_TAG
-#define LOG_TAG "inject"
- RLOGE(logcat_executable ".buckets");
+#define LOG_TAG "inject.buckets"
+ // inject messages into radio, system, main and events buffers to
+ // ensure that we see all the begin[] bucket messages.
+ RLOGE(logcat_executable);
+ SLOGE(logcat_executable);
+ ALOGE(logcat_executable);
+ __android_log_bswrite(0, logcat_executable ".inject.buckets");
rest();
ASSERT_TRUE(NULL !=
@@ -107,32 +113,45 @@
logcat_pclose(ctx, fp);
- EXPECT_EQ(15, ids);
+ EXPECT_EQ(ids, 15);
- EXPECT_EQ(4, count);
+ EXPECT_EQ(count, 4);
}
TEST(logcat, event_tag_filter) {
FILE* fp;
logcat_define(ctx);
- ASSERT_TRUE(NULL !=
- (fp = logcat_popen(ctx, logcat_executable
- " -b events -d -s auditd "
- "am_proc_start am_pss am_proc_bound "
- "dvm_lock_sample am_wtf 2>/dev/null")));
+#undef LOG_TAG
+#define LOG_TAG "inject.filter"
+ // inject messages into radio, system and main buffers
+ // with our unique log tag to test logcat filter.
+ RLOGE(logcat_executable);
+ SLOGE(logcat_executable);
+ ALOGE(logcat_executable);
+ rest();
+
+ std::string command = android::base::StringPrintf(
+ logcat_executable
+ " -b radio -b system -b main --pid=%d -d -s inject.filter 2>/dev/null",
+ getpid());
+ ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, command.c_str())));
char buffer[BIG_BUFFER];
int count = 0;
while (fgets(buffer, sizeof(buffer), fp)) {
- ++count;
+ if (strncmp(begin, buffer, sizeof(begin) - 1)) ++count;
}
logcat_pclose(ctx, fp);
- EXPECT_LT(4, count);
+ // logcat, liblogcat and logcatd test instances result in the progression
+ // of 3, 6 and 9 for our counts as each round is performed.
+ EXPECT_GE(count, 3);
+ EXPECT_LE(count, 9);
+ EXPECT_EQ(count % 3, 0);
}
// If there is not enough background noise in the logs, then spam the logs to
@@ -376,7 +395,7 @@
} while ((count < 10) && --tries && inject(10 - count));
- EXPECT_EQ(10, count); // We want _some_ history, too small, falses below
+ EXPECT_EQ(count, 10); // We want _some_ history, too small, falses below
EXPECT_TRUE(last_timestamp != NULL);
EXPECT_TRUE(first_timestamp != NULL);
EXPECT_TRUE(second_timestamp != NULL);
@@ -701,9 +720,9 @@
pclose(fp);
- EXPECT_LE(2, count);
+ EXPECT_GE(count, 2);
- EXPECT_EQ(1, signals);
+ EXPECT_EQ(signals, 1);
}
static void caught_blocking_tail(int signum) {
@@ -771,9 +790,9 @@
pclose(fp);
- EXPECT_LE(2, count);
+ EXPECT_GE(count, 2);
- EXPECT_EQ(1, signals);
+ EXPECT_EQ(signals, 1);
}
#endif
@@ -881,7 +900,7 @@
ADD_FAILURE();
}
pclose(fp);
- EXPECT_EQ(11, log_file_count);
+ EXPECT_EQ(log_file_count, 11);
}
snprintf(command, sizeof(command), "rm -rf %s", tmp_out_dir);
EXPECT_FALSE(IsFalse(system(command), command));
@@ -1134,17 +1153,17 @@
char tmp_out_dir[strlen(tmp_out_dir_form) + 1];
ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
- EXPECT_EQ(34, logrotate_count_id(logcat_cmd, tmp_out_dir));
- EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+ EXPECT_EQ(logrotate_count_id(logcat_cmd, tmp_out_dir), 34);
+ EXPECT_EQ(logrotate_count_id(logcat_short_cmd, tmp_out_dir), 34);
char id_file[strlen(tmp_out_dir_form) + strlen(log_filename) + 5];
snprintf(id_file, sizeof(id_file), "%s/%s.id", tmp_out_dir, log_filename);
if (getuid() != 0) {
chmod(id_file, 0);
- EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+ EXPECT_EQ(logrotate_count_id(logcat_short_cmd, tmp_out_dir), 34);
}
unlink(id_file);
- EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+ EXPECT_EQ(logrotate_count_id(logcat_short_cmd, tmp_out_dir), 34);
FILE* fp = fopen(id_file, "w");
if (fp) {
@@ -1159,9 +1178,9 @@
}
int new_signature;
- EXPECT_LE(
- 2, (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir)));
- EXPECT_GT(34, new_signature);
+ EXPECT_GE(
+ (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir)), 2);
+ EXPECT_LT(new_signature, 34);
static const char cleanup_cmd[] = "rm -rf %s";
char command[strlen(cleanup_cmd) + strlen(tmp_out_dir_form)];
@@ -1302,10 +1321,10 @@
pclose(fp);
- EXPECT_LE(1, count);
- EXPECT_EQ(1, minus_g);
+ EXPECT_GE(count, 1);
+ EXPECT_EQ(minus_g, 1);
- EXPECT_EQ(1, signals);
+ EXPECT_EQ(signals, 1);
}
#endif
@@ -1560,7 +1579,7 @@
ctx << theAnswer;
// crafted to rest at least once after, and rest between retries.
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(
End_to_End(hhgtg.tagStr, "to life the universe etc=%s", theAnswer));
}
@@ -1572,7 +1591,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr,
"[id=%s,event=42,source=-1,account=0]", id));
}
@@ -1582,7 +1601,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "[id=%s,event=43,-1,0]", id));
}
@@ -1591,7 +1610,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
fprintf(stderr, "Expect a \"Closest match\" message\n");
EXPECT_FALSE(End_to_End(
sync.tagStr, "[id=%s,event=44,source=-1,account=0]", id));
@@ -1604,7 +1623,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << (uint64_t)30 << (int32_t)2;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(
End_to_End(sync.tagStr, "[aggregation time=30ms,count=2]"));
}
@@ -1613,7 +1632,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << (uint64_t)31570 << (int32_t)911;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(
End_to_End(sync.tagStr, "[aggregation time=31.57s,count=911]"));
}
@@ -1625,7 +1644,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)512;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
}
@@ -1633,7 +1652,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)3072;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
}
@@ -1641,7 +1660,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)2097152;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
}
@@ -1649,7 +1668,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)2097153;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
}
@@ -1657,7 +1676,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)1073741824;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
}
@@ -1665,7 +1684,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
}
}
@@ -1674,7 +1693,7 @@
static const struct tag sync = { 27501, "notification_panel_hidden" };
android_log_event_list ctx(sync.tagNo);
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, ""));
}
@@ -1694,28 +1713,28 @@
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)7;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "new=7s"));
}
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)62;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "new=1:02"));
}
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)3673;
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "new=1:01:13"));
}
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint32_t)(86400 + 7200 + 180 + 58);
for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_LE(0, ret);
+ EXPECT_GE(ret, 0);
EXPECT_TRUE(End_to_End(sync.tagStr, "new=1d 2:03:58"));
}
}
@@ -1756,7 +1775,7 @@
TEST(logcat, help) {
size_t logcatHelpTextSize = commandOutputSize(logcat_executable " -h 2>&1");
- EXPECT_LT(4096UL, logcatHelpTextSize);
+ EXPECT_GT(logcatHelpTextSize, 4096UL);
size_t logcatLastHelpTextSize =
commandOutputSize(logcat_executable " -L -h 2>&1");
#ifdef USING_LOGCAT_EXECUTABLE_DEFAULT // logcat and liblogcat
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index e597754..f0d6fcb 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -159,9 +159,12 @@
const char* pidToName(pid_t pid) {
return stats.pidToName(pid);
}
- uid_t pidToUid(pid_t pid) {
+ virtual uid_t pidToUid(pid_t pid) override {
return stats.pidToUid(pid);
}
+ virtual pid_t tidToPid(pid_t tid) override {
+ return stats.tidToPid(tid);
+ }
const char* uidToName(uid_t uid) {
return stats.uidToName(uid);
}
diff --git a/logd/LogBufferInterface.cpp b/logd/LogBufferInterface.cpp
index 3cb2b89..4b6d363 100644
--- a/logd/LogBufferInterface.cpp
+++ b/logd/LogBufferInterface.cpp
@@ -15,8 +15,15 @@
*/
#include "LogBufferInterface.h"
+#include "LogUtils.h"
LogBufferInterface::LogBufferInterface() {
}
LogBufferInterface::~LogBufferInterface() {
-}
\ No newline at end of file
+}
+uid_t LogBufferInterface::pidToUid(pid_t pid) {
+ return android::pidToUid(pid);
+}
+pid_t LogBufferInterface::tidToPid(pid_t tid) {
+ return android::tidToPid(tid);
+}
diff --git a/logd/LogBufferInterface.h b/logd/LogBufferInterface.h
index 7d82b91..ff73a22 100644
--- a/logd/LogBufferInterface.h
+++ b/logd/LogBufferInterface.h
@@ -33,6 +33,9 @@
virtual int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
pid_t tid, const char* msg, unsigned short len) = 0;
+ virtual uid_t pidToUid(pid_t pid);
+ virtual pid_t tidToPid(pid_t tid);
+
private:
DISALLOW_COPY_AND_ASSIGN(LogBufferInterface);
};
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 3c0d08d..d2df68e 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+#include <ctype.h>
#include <limits.h>
+#include <stdio.h>
#include <sys/cdefs.h>
#include <sys/prctl.h>
#include <sys/socket.h>
@@ -72,8 +74,11 @@
cmsg = CMSG_NXTHDR(&hdr, cmsg);
}
+ struct ucred fake_cred;
if (cred == NULL) {
- return false;
+ cred = &fake_cred;
+ cred->pid = 0;
+ cred->uid = DEFAULT_OVERFLOWUID;
}
if (cred->uid == AID_LOGD) {
@@ -96,6 +101,27 @@
return false;
}
+ // Check credential validity, acquire corrected details if not supplied.
+ if (cred->pid == 0) {
+ cred->pid = logbuf ? logbuf->tidToPid(header->tid)
+ : android::tidToPid(header->tid);
+ if (cred->pid == getpid()) {
+ // We expect that /proc/<tid>/ is accessible to self even without
+ // readproc group, so that we will always drop messages that come
+ // from any of our logd threads and their library calls.
+ return false; // ignore self
+ }
+ }
+ if (cred->uid == DEFAULT_OVERFLOWUID) {
+ uid_t uid =
+ logbuf ? logbuf->pidToUid(cred->pid) : android::pidToUid(cred->pid);
+ if (uid == AID_LOGD) {
+ uid = logbuf ? logbuf->pidToUid(header->tid)
+ : android::pidToUid(cred->pid);
+ }
+ if (uid != AID_LOGD) cred->uid = uid;
+ }
+
char* msg = ((char*)buffer) + sizeof(android_log_header_t);
n -= sizeof(android_log_header_t);
diff --git a/logd/LogListener.h b/logd/LogListener.h
index e16c5fb..a562a54 100644
--- a/logd/LogListener.h
+++ b/logd/LogListener.h
@@ -20,6 +20,16 @@
#include <sysutils/SocketListener.h>
#include "LogReader.h"
+// DEFAULT_OVERFLOWUID is defined in linux/highuid.h, which is not part of
+// the uapi headers for userspace to use. This value is filled in on the
+// out-of-band socket credentials if the OS fails to find one available.
+// One of the causes of this is if SO_PASSCRED is set, all the packets before
+// that point will have this value. We also use it in a fake credential if
+// no socket credentials are supplied.
+#ifndef DEFAULT_OVERFLOWUID
+#define DEFAULT_OVERFLOWUID 65534
+#endif
+
class LogListener : public SocketListener {
LogBufferInterface* logbuf;
LogReader* reader;
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index d20d90e..af59ddc 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <ctype.h>
#include <fcntl.h>
#include <inttypes.h>
#include <pwd.h>
@@ -824,8 +825,10 @@
FILE* fp = fopen(buffer, "r");
if (fp) {
while (fgets(buffer, sizeof(buffer), fp)) {
- int uid;
- if (sscanf(buffer, "Uid: %d", &uid) == 1) {
+ int uid = AID_LOGD;
+ char space = 0;
+ if ((sscanf(buffer, "Uid: %d%c", &uid, &space) == 2) &&
+ isspace(space)) {
fclose(fp);
return uid;
}
@@ -834,12 +837,35 @@
}
return AID_LOGD; // associate this with the logger
}
+
+pid_t tidToPid(pid_t tid) {
+ char buffer[512];
+ snprintf(buffer, sizeof(buffer), "/proc/%u/status", tid);
+ FILE* fp = fopen(buffer, "r");
+ if (fp) {
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ int pid = tid;
+ char space = 0;
+ if ((sscanf(buffer, "Tgid: %d%c", &pid, &space) == 2) &&
+ isspace(space)) {
+ fclose(fp);
+ return pid;
+ }
+ }
+ fclose(fp);
+ }
+ return tid;
+}
}
uid_t LogStatistics::pidToUid(pid_t pid) {
return pidTable.add(pid)->second.getUid();
}
+pid_t LogStatistics::tidToPid(pid_t tid) {
+ return tidTable.add(tid)->second.getPid();
+}
+
// caller must free character string
const char* LogStatistics::pidToName(pid_t pid) const {
// An inconvenient truth ... getName() can alter the object
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 945fc0a..8808aac 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -306,10 +306,6 @@
std::string format(const LogStatistics& stat, log_id_t id) const;
};
-namespace android {
-uid_t pidToUid(pid_t pid);
-}
-
struct PidEntry : public EntryBaseDropped {
const pid_t pid;
uid_t uid;
@@ -389,6 +385,13 @@
uid(android::pidToUid(tid)),
name(android::tidToName(tid)) {
}
+ TidEntry(pid_t tid)
+ : EntryBaseDropped(),
+ tid(tid),
+ pid(android::tidToPid(tid)),
+ uid(android::pidToUid(tid)),
+ name(android::tidToName(tid)) {
+ }
explicit TidEntry(const LogBufferElement* element)
: EntryBaseDropped(element),
tid(element->getTid()),
@@ -785,6 +788,7 @@
// helper (must be locked directly or implicitly by mLogElementsLock)
const char* pidToName(pid_t pid) const;
uid_t pidToUid(pid_t pid);
+ pid_t tidToPid(pid_t tid);
const char* uidToName(uid_t uid) const;
};
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index fa9f398..4dcd3e7 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -38,6 +38,8 @@
// Caller must own and free returned value
char* pidToName(pid_t pid);
char* tidToName(pid_t tid);
+uid_t pidToUid(pid_t pid);
+pid_t tidToPid(pid_t tid);
// Furnished in LogTags.cpp. Thread safe.
const char* tagToName(uint32_t tag);
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index f90c9fb..cd80212 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -32,8 +32,8 @@
#include <android-base/stringprintf.h>
#include <cutils/sockets.h>
#include <gtest/gtest.h>
-#include <log/log.h>
#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
#ifdef __ANDROID__
#include <selinux/selinux.h>
#endif
@@ -1061,8 +1061,8 @@
if (pid) {
siginfo_t info = {};
- if (TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))) return 0;
- if (info.si_status) return 0;
+ if (TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))) return -1;
+ if (info.si_status) return -1;
return pid;
}
@@ -1077,7 +1077,7 @@
freecon(context);
_exit(-1);
// NOTREACHED
- return 0;
+ return -1;
}
}
@@ -1106,25 +1106,39 @@
if (access(android::base::StringPrintf(file, num).c_str(), F_OK) == 0) {
_exit(-1);
// NOTREACHED
- return 0;
+ return -1;
}
usleep(usec);
--num;
}
_exit(0);
// NOTREACHED
- return 0;
+ return -1;
}
+static constexpr int background_period = 10;
+
static int count_avc(pid_t pid) {
int count = 0;
- if (pid == 0) return count;
+ // pid=-1 skip as pid is in error
+ if (pid == (pid_t)-1) return count;
- struct logger_list* logger_list;
- if (!(logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)))
+ // pid=0 means we want to report the background count of avc: activities
+ struct logger_list* logger_list =
+ pid ? android_logger_list_alloc(
+ ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)
+ : android_logger_list_alloc_time(
+ ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ log_time(android_log_clockid()) -
+ log_time(background_period, 0),
+ 0);
+ if (!logger_list) return count;
+ struct logger* logger = android_logger_open(logger_list, LOG_ID_EVENTS);
+ if (!logger) {
+ android_logger_list_close(logger_list);
return count;
+ }
for (;;) {
log_msg log_msg;
@@ -1156,56 +1170,64 @@
}
#endif
-TEST(logd, sepolicy_rate_limiter_maximum) {
+TEST(logd, sepolicy_rate_limiter) {
#ifdef __ANDROID__
- static const int rate = AUDIT_RATE_LIMIT_MAX;
- static const int duration = 2;
- // Two seconds of a liveable sustained rate
- EXPECT_EQ(rate * duration, count_avc(sepolicy_rate(rate, rate * duration)));
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(logd, sepolicy_rate_limiter_sub_burst) {
-#ifdef __ANDROID__
- // maximum period below half way between sustainable and burst rate.
- static const int threshold =
- ((AUDIT_RATE_LIMIT_BURST_DURATION *
- (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
- 1) /
- 2;
- static const int rate = (threshold / AUDIT_RATE_LIMIT_BURST_DURATION) - 1;
- static const int duration = AUDIT_RATE_LIMIT_BURST_DURATION;
- EXPECT_EQ(rate * duration, count_avc(sepolicy_rate(rate, rate * duration)));
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(logd, sepolicy_rate_limiter_spam) {
-#ifdef __ANDROID__
- // maximum period of double the maximum burst rate
- static const int threshold =
- ((AUDIT_RATE_LIMIT_BURST_DURATION *
- (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
- 1) /
- 2;
- static const int rate = AUDIT_RATE_LIMIT_DEFAULT * 2;
- static const int duration = threshold / AUDIT_RATE_LIMIT_DEFAULT;
- EXPECT_GE(
- ((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) / 100, // +15% margin
- count_avc(sepolicy_rate(rate, rate * duration)));
- // give logd another 3 seconds to react to the burst before checking
- sepolicy_rate(rate, rate * 3);
- // maximum period at double the maximum burst rate (spam filter kicked in)
- EXPECT_GE(
- threshold * 2,
- count_avc(sepolicy_rate(rate, rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
- // cool down, and check unspammy rate still works
- sleep(2);
- EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ to be lost
- count_avc(sepolicy_rate(1, AUDIT_RATE_LIMIT_BURST_DURATION)));
+ int background_selinux_activity_too_high = count_avc(0);
+ if (background_selinux_activity_too_high > 2) {
+ GTEST_LOG_(ERROR) << "Too much background selinux activity "
+ << background_selinux_activity_too_high * 60 /
+ background_period
+ << "/minute on the device, this test\n"
+ << "can not measure the functionality of the "
+ << "sepolicy rate limiter. Expect test to\n"
+ << "fail as this device is in a bad state, "
+ << "but is not strictly a unit test failure.";
+ }
+ // sepolicy_rate_limiter_maximum
+ { // maximum precharch test block.
+ static constexpr int rate = AUDIT_RATE_LIMIT_MAX;
+ static constexpr int duration = 2;
+ // Two seconds of a liveable sustained rate
+ EXPECT_EQ(rate * duration,
+ count_avc(sepolicy_rate(rate, rate * duration)));
+ }
+ // sepolicy_rate_limiter_sub_burst
+ { // maximum period below half way between sustainable and burst rate
+ static constexpr int threshold =
+ ((AUDIT_RATE_LIMIT_BURST_DURATION *
+ (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
+ 1) /
+ 2;
+ static constexpr int rate =
+ (threshold / AUDIT_RATE_LIMIT_BURST_DURATION) - 1;
+ static constexpr int duration = AUDIT_RATE_LIMIT_BURST_DURATION;
+ EXPECT_EQ(rate * duration,
+ count_avc(sepolicy_rate(rate, rate * duration)));
+ }
+ // sepolicy_rate_limiter_spam
+ { // hit avc: hard beyond reason block.
+ // maximum period of double the maximum burst rate
+ static constexpr int threshold =
+ ((AUDIT_RATE_LIMIT_BURST_DURATION *
+ (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
+ 1) /
+ 2;
+ static constexpr int rate = AUDIT_RATE_LIMIT_DEFAULT * 2;
+ static constexpr int duration = threshold / AUDIT_RATE_LIMIT_DEFAULT;
+ EXPECT_GE(
+ ((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) / 100, // +15% margin
+ count_avc(sepolicy_rate(rate, rate * duration)));
+ // give logd another 3 seconds to react to the burst before checking
+ sepolicy_rate(rate, rate * 3);
+ // maximum period at double maximum burst rate (spam filter kicked in)
+ EXPECT_GE(threshold * 2,
+ count_avc(sepolicy_rate(
+ rate, rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
+ // cool down, and check unspammy rate still works
+ sleep(2);
+ EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ lost
+ count_avc(sepolicy_rate(1, AUDIT_RATE_LIMIT_BURST_DURATION)));
+ }
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/platform_tools_tool_version.mk b/platform_tools_tool_version.mk
new file mode 100644
index 0000000..73229e6
--- /dev/null
+++ b/platform_tools_tool_version.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2017 Google Inc.
+#
+# 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.
+
+# We rewrite ${PLATFORM_SDK_VERSION} with 0 rather than $(PLATFORM_SDK_VERSION)
+# because on the actual platform tools release branches the file contains a
+# literal instead. Using 0 lets us easily distinguish non-canonical builds.
+platform_tools_version := $(shell sed \
+ 's/$${PLATFORM_SDK_VERSION}/0/ ; s/^Pkg.Revision=\(.*\)/\1/p ; d' \
+ $(ANDROID_BUILD_TOP)/development/sdk/plat_tools_source.prop_template \
+ )
+tool_version := $(platform_tools_version)-$(BUILD_NUMBER_FROM_FILE)
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 1609ef2..efd0da5 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -68,7 +68,7 @@
/dev/diag 0660 radio radio
/dev/diag_arm9 0660 radio radio
/dev/ttyMSM0 0600 bluetooth bluetooth
-/dev/uhid 0660 system bluetooth
+/dev/uhid 0660 uhid uhid
/dev/uinput 0660 system bluetooth
/dev/alarm 0664 system radio
/dev/rtc0 0640 system system
diff --git a/trusty/Android.bp b/trusty/Android.bp
index 9681488..386fbe6 100644
--- a/trusty/Android.bp
+++ b/trusty/Android.bp
@@ -1,4 +1,7 @@
subdirs = [
+ "gatekeeper",
+ "keymaster",
"libtrusty",
+ "nvram",
"storage/*",
]
diff --git a/trusty/gatekeeper/Android.bp b/trusty/gatekeeper/Android.bp
new file mode 100644
index 0000000..a9566a1
--- /dev/null
+++ b/trusty/gatekeeper/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2015 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.
+//
+
+// WARNING: Everything listed here will be built on ALL platforms,
+// including x86, the emulator, and the SDK. Modules must be uniquely
+// named (liblights.panda), and must build everywhere, or limit themselves
+// to only building on ARM if they include assembly. Individual makefiles
+// are responsible for having their own logic, for fine-grained control.
+
+cc_library_shared {
+ name: "gatekeeper.trusty",
+
+ relative_install_path: "hw",
+
+ srcs: [
+ "module.cpp",
+ "trusty_gatekeeper_ipc.c",
+ "trusty_gatekeeper.cpp",
+ ],
+
+ cflags: [
+ "-fvisibility=hidden",
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "libgatekeeper",
+ "liblog",
+ "libcutils",
+ "libtrusty",
+ ],
+}
diff --git a/trusty/gatekeeper/Android.mk b/trusty/gatekeeper/Android.mk
deleted file mode 100644
index 3982c8f..0000000
--- a/trusty/gatekeeper/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# Copyright (C) 2015 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.
-#
-
-# WARNING: Everything listed here will be built on ALL platforms,
-# including x86, the emulator, and the SDK. Modules must be uniquely
-# named (liblights.panda), and must build everywhere, or limit themselves
-# to only building on ARM if they include assembly. Individual makefiles
-# are responsible for having their own logic, for fine-grained control.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := gatekeeper.trusty
-
-LOCAL_MODULE_RELATIVE_PATH := hw
-
-LOCAL_SRC_FILES := \
- module.cpp \
- trusty_gatekeeper_ipc.c \
- trusty_gatekeeper.cpp
-
-LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libgatekeeper \
- liblog \
- libcutils \
- libtrusty
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
new file mode 100644
index 0000000..3b6867c
--- /dev/null
+++ b/trusty/keymaster/Android.bp
@@ -0,0 +1,67 @@
+//
+// Copyright (C) 2015 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.
+//
+
+// WARNING: Everything listed here will be built on ALL platforms,
+// including x86, the emulator, and the SDK. Modules must be uniquely
+// named (liblights.panda), and must build everywhere, or limit themselves
+// to only building on ARM if they include assembly. Individual makefiles
+// are responsible for having their own logic, for fine-grained control.
+
+// trusty_keymaster is a binary used only for on-device testing. It
+// runs Trusty Keymaster through a basic set of operations with RSA
+// and ECDSA keys.
+cc_binary {
+ name: "trusty_keymaster_tipc",
+ srcs: [
+ "trusty_keymaster_device.cpp",
+ "trusty_keymaster_ipc.cpp",
+ "trusty_keymaster_main.cpp",
+ ],
+ shared_libs: [
+ "libcrypto",
+ "libcutils",
+ "libkeymaster1",
+ "libtrusty",
+ "libkeymaster_messages",
+ "libsoftkeymasterdevice",
+ "liblog",
+ ],
+}
+
+// keystore.trusty is the HAL used by keystore on Trusty devices.
+cc_library_shared {
+ name: "keystore.trusty",
+ relative_install_path: "hw",
+ srcs: [
+ "module.cpp",
+ "trusty_keymaster_ipc.cpp",
+ "trusty_keymaster_device.cpp",
+ ],
+
+ cflags: [
+ "-fvisibility=hidden",
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "libcrypto",
+ "libkeymaster_messages",
+ "libtrusty",
+ "liblog",
+ "libcutils",
+ ],
+}
diff --git a/trusty/keymaster/Android.mk b/trusty/keymaster/Android.mk
deleted file mode 100644
index 2d614ae..0000000
--- a/trusty/keymaster/Android.mk
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# Copyright (C) 2015 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.
-#
-
-# WARNING: Everything listed here will be built on ALL platforms,
-# including x86, the emulator, and the SDK. Modules must be uniquely
-# named (liblights.panda), and must build everywhere, or limit themselves
-# to only building on ARM if they include assembly. Individual makefiles
-# are responsible for having their own logic, for fine-grained control.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-###
-# trusty_keymaster is a binary used only for on-device testing. It
-# runs Trusty Keymaster through a basic set of operations with RSA
-# and ECDSA keys.
-###
-LOCAL_MODULE := trusty_keymaster_tipc
-LOCAL_SRC_FILES := \
- trusty_keymaster_device.cpp \
- trusty_keymaster_ipc.cpp \
- trusty_keymaster_main.cpp
-LOCAL_SHARED_LIBRARIES := \
- libcrypto \
- libcutils \
- libkeymaster1 \
- libtrusty \
- libkeymaster_messages \
- libsoftkeymasterdevice \
- liblog
-
-include $(BUILD_EXECUTABLE)
-
-###
-# keystore.trusty is the HAL used by keystore on Trusty devices.
-##
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := keystore.trusty
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SRC_FILES := module.cpp \
- trusty_keymaster_ipc.cpp \
- trusty_keymaster_device.cpp
-LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
-LOCAL_SHARED_LIBRARIES := \
- libcrypto \
- libkeymaster_messages \
- libtrusty \
- liblog \
- libcutils
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/nvram/Android.bp b/trusty/nvram/Android.bp
new file mode 100644
index 0000000..15e6c3e
--- /dev/null
+++ b/trusty/nvram/Android.bp
@@ -0,0 +1,61 @@
+//
+// 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.
+//
+
+// nvram.trusty is the Trusty NVRAM HAL module.
+cc_library_shared {
+ name: "nvram.trusty",
+ relative_install_path: "hw",
+ srcs: [
+ "module.c",
+ "trusty_nvram_device.cpp",
+ "trusty_nvram_implementation.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-fvisibility=hidden",
+ ],
+ static_libs: ["libnvram-hal"],
+ shared_libs: [
+ "libtrusty",
+ "libnvram-messages",
+ "liblog",
+ ],
+}
+
+// nvram-wipe is a helper tool for clearing NVRAM state.
+cc_binary {
+ name: "nvram-wipe",
+ srcs: [
+ "nvram_wipe.cpp",
+ "trusty_nvram_implementation.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-fvisibility=hidden",
+ ],
+ static_libs: ["libnvram-hal"],
+ shared_libs: [
+ "libtrusty",
+ "libnvram-messages",
+ "liblog",
+ ],
+}
diff --git a/trusty/nvram/Android.mk b/trusty/nvram/Android.mk
deleted file mode 100644
index 44e2212..0000000
--- a/trusty/nvram/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-# nvram.trusty is the Trusty NVRAM HAL module.
-include $(CLEAR_VARS)
-LOCAL_MODULE := nvram.trusty
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SRC_FILES := \
- module.c \
- trusty_nvram_device.cpp \
- trusty_nvram_implementation.cpp
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror -Wextra -fvisibility=hidden
-LOCAL_STATIC_LIBRARIES := libnvram-hal
-LOCAL_SHARED_LIBRARIES := libtrusty libnvram-messages liblog
-include $(BUILD_SHARED_LIBRARY)
-
-# nvram-wipe is a helper tool for clearing NVRAM state.
-include $(CLEAR_VARS)
-LOCAL_MODULE := nvram-wipe
-LOCAL_SRC_FILES := \
- nvram_wipe.cpp \
- trusty_nvram_implementation.cpp
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror -Wextra -fvisibility=hidden
-LOCAL_STATIC_LIBRARIES := libnvram-hal
-LOCAL_SHARED_LIBRARIES := libtrusty libnvram-messages liblog
-include $(BUILD_EXECUTABLE)