Merge "Adding 'uhid' permission for access to /dev/uhid."
diff --git a/adb/Android.mk b/adb/Android.mk
index 819bad1..382c8cb 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -5,21 +5,21 @@
LOCAL_PATH:= $(call my-dir)
+include $(LOCAL_PATH)/../platform_tools_tool_version.mk
+
adb_host_sanitize :=
adb_target_sanitize :=
-adb_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
-
ADB_COMMON_CFLAGS := \
-Wall -Wextra -Werror \
-Wno-unused-parameter \
-Wno-missing-field-initializers \
-Wvla \
- -DADB_REVISION='"$(adb_version)"' \
+ -DADB_VERSION="\"$(tool_version)\"" \
ADB_COMMON_posix_CFLAGS := \
-Wexit-time-destructors \
- -Wthread-safety
+ -Wthread-safety \
ADB_COMMON_linux_CFLAGS := \
$(ADB_COMMON_posix_CFLAGS) \
@@ -232,7 +232,7 @@
libcutils \
libdiagnose_usb \
libmdnssd \
- libgmock_host
+ libgmock_host \
LOCAL_STATIC_LIBRARIES_linux := libusb
LOCAL_STATIC_LIBRARIES_darwin := libusb
@@ -300,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 a32c605..18a8ff2 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -152,13 +152,16 @@
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),
libusb_get_device_address(device));
}
+#if defined(__linux__)
static std::string get_device_serial_path(libusb_device* device) {
uint8_t ports[7];
int port_count = libusb_get_port_numbers(device, ports, 7);
@@ -172,6 +175,7 @@
path += "/serial";
return path;
}
+#endif
static bool endpoint_is_output(uint8_t endpoint) {
return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT;
@@ -182,212 +186,215 @@
(write_length & zero_mask) == 0;
}
+static void process_device(libusb_device* device) {
+ std::string device_address = get_device_address(device);
+ std::string device_serial;
+
+ // Figure out if we want to open the device.
+ libusb_device_descriptor device_desc;
+ int rc = libusb_get_device_descriptor(device, &device_desc);
+ if (rc != 0) {
+ LOG(WARNING) << "failed to get device descriptor for device at " << device_address << ": "
+ << libusb_error_name(rc);
+ return;
+ }
+
+ if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) {
+ // Assume that all Android devices have the device class set to per interface.
+ // TODO: Is this assumption valid?
+ LOG(VERBOSE) << "skipping device with incorrect class at " << device_address;
+ return;
+ }
+
+ libusb_config_descriptor* config_raw;
+ rc = libusb_get_active_config_descriptor(device, &config_raw);
+ if (rc != 0) {
+ LOG(WARNING) << "failed to get active config descriptor for device at " << device_address
+ << ": " << libusb_error_name(rc);
+ return;
+ }
+ const unique_config_descriptor config(config_raw);
+
+ // Use size_t for interface_num so <iostream>s don't mangle it.
+ size_t interface_num;
+ uint16_t zero_mask;
+ uint8_t bulk_in = 0, bulk_out = 0;
+ size_t packet_size = 0;
+ bool found_adb = false;
+
+ for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) {
+ const libusb_interface& interface = config->interface[interface_num];
+ if (interface.num_altsetting != 1) {
+ // Assume that interfaces with alternate settings aren't adb interfaces.
+ // TODO: Is this assumption valid?
+ LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address
+ << " (interface " << interface_num << ")";
+ return;
+ }
+
+ const libusb_interface_descriptor& interface_desc = interface.altsetting[0];
+ if (!is_adb_interface(interface_desc.bInterfaceClass, interface_desc.bInterfaceSubClass,
+ interface_desc.bInterfaceProtocol)) {
+ LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface "
+ << interface_num << ")";
+ return;
+ }
+
+ LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface "
+ << interface_num << ")";
+
+ bool found_in = false;
+ bool found_out = false;
+ for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints; ++endpoint_num) {
+ const auto& endpoint_desc = interface_desc.endpoint[endpoint_num];
+ const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress;
+ const uint8_t endpoint_attr = endpoint_desc.bmAttributes;
+
+ const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK;
+
+ if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) {
+ return;
+ }
+
+ if (endpoint_is_output(endpoint_addr) && !found_out) {
+ found_out = true;
+ bulk_out = endpoint_addr;
+ zero_mask = endpoint_desc.wMaxPacketSize - 1;
+ } else if (!endpoint_is_output(endpoint_addr) && !found_in) {
+ found_in = true;
+ bulk_in = endpoint_addr;
+ }
+
+ size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize;
+ CHECK(endpoint_packet_size != 0);
+ if (packet_size == 0) {
+ packet_size = endpoint_packet_size;
+ } else {
+ CHECK(packet_size == endpoint_packet_size);
+ }
+ }
+
+ if (found_in && found_out) {
+ found_adb = true;
+ break;
+ } else {
+ LOG(VERBOSE) << "rejecting potential adb interface at " << device_address
+ << "(interface " << interface_num << "): missing bulk endpoints "
+ << "(found_in = " << found_in << ", found_out = " << found_out << ")";
+ }
+ }
+
+ if (!found_adb) {
+ LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address;
+ return;
+ }
+
+ {
+ std::unique_lock<std::mutex> lock(usb_handles_mutex);
+ if (usb_handles.find(device_address) != usb_handles.end()) {
+ LOG(VERBOSE) << "device at " << device_address
+ << " has already been registered, skipping";
+ return;
+ }
+ }
+
+ bool writable = true;
+ libusb_device_handle* handle_raw = nullptr;
+ rc = libusb_open(device, &handle_raw);
+ unique_device_handle handle(handle_raw);
+ if (rc == 0) {
+ LOG(DEBUG) << "successfully opened adb device at " << device_address << ", "
+ << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out);
+
+ device_serial.resize(255);
+ rc = libusb_get_string_descriptor_ascii(handle_raw, device_desc.iSerialNumber,
+ reinterpret_cast<unsigned char*>(&device_serial[0]),
+ device_serial.length());
+ if (rc == 0) {
+ LOG(WARNING) << "received empty serial from device at " << device_address;
+ return;
+ } else if (rc < 0) {
+ LOG(WARNING) << "failed to get serial from device at " << device_address
+ << libusb_error_name(rc);
+ return;
+ }
+ device_serial.resize(rc);
+
+ // WARNING: this isn't released via RAII.
+ rc = libusb_claim_interface(handle.get(), interface_num);
+ if (rc != 0) {
+ LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'"
+ << libusb_error_name(rc);
+ return;
+ }
+
+ for (uint8_t endpoint : {bulk_in, bulk_out}) {
+ rc = libusb_clear_halt(handle.get(), endpoint);
+ if (rc != 0) {
+ LOG(WARNING) << "failed to clear halt on device '" << device_serial
+ << "' endpoint 0x" << std::hex << endpoint << ": "
+ << libusb_error_name(rc);
+ libusb_release_interface(handle.get(), interface_num);
+ return;
+ }
+ }
+ } else {
+ LOG(WARNING) << "failed to open usb device at " << device_address << ": "
+ << libusb_error_name(rc);
+ writable = false;
+
+#if defined(__linux__)
+ // libusb doesn't think we should be messing around with devices we don't have
+ // write access to, but Linux at least lets us get the serial number anyway.
+ if (!android::base::ReadFileToString(get_device_serial_path(device), &device_serial)) {
+ // We don't actually want to treat an unknown serial as an error because
+ // devices aren't able to communicate a serial number in early bringup.
+ // http://b/20883914
+ device_serial = "unknown";
+ }
+ device_serial = android::base::Trim(device_serial);
+#else
+ // On Mac OS and Windows, we're screwed. But I don't think this situation actually
+ // happens on those OSes.
+ return;
+#endif
+ }
+
+ auto result =
+ std::make_unique<usb_handle>(device_address, device_serial, std::move(handle),
+ interface_num, bulk_in, bulk_out, zero_mask, packet_size);
+ usb_handle* usb_handle_raw = result.get();
+
+ {
+ std::unique_lock<std::mutex> lock(usb_handles_mutex);
+ usb_handles[device_address] = std::move(result);
+ }
+
+ register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable);
+
+ LOG(INFO) << "registered new usb device '" << device_serial << "'";
+}
+
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";
for (ssize_t i = 0; i < device_count; ++i) {
- libusb_device* device = list[i];
- std::string device_address = get_device_address(device);
- std::string device_serial;
-
- // Figure out if we want to open the device.
- libusb_device_descriptor device_desc;
- int rc = libusb_get_device_descriptor(device, &device_desc);
- if (rc != 0) {
- LOG(WARNING) << "failed to get device descriptor for device at " << device_address
- << ": " << libusb_error_name(rc);
- }
-
- if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) {
- // Assume that all Android devices have the device class set to per interface.
- // TODO: Is this assumption valid?
- LOG(VERBOSE) << "skipping device with incorrect class at " << device_address;
- continue;
- }
-
- libusb_config_descriptor* config_raw;
- rc = libusb_get_active_config_descriptor(device, &config_raw);
- if (rc != 0) {
- LOG(WARNING) << "failed to get active config descriptor for device at "
- << device_address << ": " << libusb_error_name(rc);
- continue;
- }
- const unique_config_descriptor config(config_raw);
-
- // Use size_t for interface_num so <iostream>s don't mangle it.
- size_t interface_num;
- uint16_t zero_mask;
- uint8_t bulk_in = 0, bulk_out = 0;
- size_t packet_size = 0;
- bool found_adb = false;
-
- for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) {
- const libusb_interface& interface = config->interface[interface_num];
- if (interface.num_altsetting != 1) {
- // Assume that interfaces with alternate settings aren't adb interfaces.
- // TODO: Is this assumption valid?
- LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at "
- << device_address << " (interface " << interface_num << ")";
- continue;
- }
-
- const libusb_interface_descriptor& interface_desc = interface.altsetting[0];
- if (!is_adb_interface(interface_desc.bInterfaceClass,
- interface_desc.bInterfaceSubClass,
- interface_desc.bInterfaceProtocol)) {
- LOG(VERBOSE) << "skipping non-adb interface at " << device_address
- << " (interface " << interface_num << ")";
- continue;
- }
-
- LOG(VERBOSE) << "found potential adb interface at " << device_address
- << " (interface " << interface_num << ")";
-
- bool found_in = false;
- bool found_out = false;
- for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints;
- ++endpoint_num) {
- const auto& endpoint_desc = interface_desc.endpoint[endpoint_num];
- const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress;
- const uint8_t endpoint_attr = endpoint_desc.bmAttributes;
-
- const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK;
-
- if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) {
- continue;
- }
-
- if (endpoint_is_output(endpoint_addr) && !found_out) {
- found_out = true;
- bulk_out = endpoint_addr;
- zero_mask = endpoint_desc.wMaxPacketSize - 1;
- } else if (!endpoint_is_output(endpoint_addr) && !found_in) {
- found_in = true;
- bulk_in = endpoint_addr;
- }
-
- size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize;
- CHECK(endpoint_packet_size != 0);
- if (packet_size == 0) {
- packet_size = endpoint_packet_size;
- } else {
- CHECK(packet_size == endpoint_packet_size);
- }
- }
-
- if (found_in && found_out) {
- found_adb = true;
- break;
- } else {
- LOG(VERBOSE) << "rejecting potential adb interface at " << device_address
- << "(interface " << interface_num << "): missing bulk endpoints "
- << "(found_in = " << found_in << ", found_out = " << found_out
- << ")";
- }
- }
-
- if (!found_adb) {
- LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address;
- continue;
- }
-
- {
- std::unique_lock<std::mutex> lock(usb_handles_mutex);
- if (usb_handles.find(device_address) != usb_handles.end()) {
- LOG(VERBOSE) << "device at " << device_address
- << " has already been registered, skipping";
- continue;
- }
- }
-
- bool writable = true;
- libusb_device_handle* handle_raw = nullptr;
- rc = libusb_open(device, &handle_raw);
- unique_device_handle handle(handle_raw);
- if (rc == 0) {
- LOG(DEBUG) << "successfully opened adb device at " << device_address << ", "
- << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out);
-
- device_serial.resize(255);
- rc = libusb_get_string_descriptor_ascii(
- handle_raw, device_desc.iSerialNumber,
- reinterpret_cast<unsigned char*>(&device_serial[0]), device_serial.length());
- if (rc == 0) {
- LOG(WARNING) << "received empty serial from device at " << device_address;
- continue;
- } else if (rc < 0) {
- LOG(WARNING) << "failed to get serial from device at " << device_address
- << libusb_error_name(rc);
- continue;
- }
- device_serial.resize(rc);
-
- // WARNING: this isn't released via RAII.
- rc = libusb_claim_interface(handle.get(), interface_num);
- if (rc != 0) {
- LOG(WARNING) << "failed to claim adb interface for device '" << device_serial
- << "'" << libusb_error_name(rc);
- continue;
- }
-
- for (uint8_t endpoint : {bulk_in, bulk_out}) {
- rc = libusb_clear_halt(handle.get(), endpoint);
- if (rc != 0) {
- LOG(WARNING) << "failed to clear halt on device '" << device_serial
- << "' endpoint 0x" << std::hex << endpoint << ": "
- << libusb_error_name(rc);
- libusb_release_interface(handle.get(), interface_num);
- continue;
- }
- }
- } else {
- LOG(WARNING) << "failed to open usb device at " << device_address << ": "
- << libusb_error_name(rc);
- writable = false;
-
-#if defined(__linux__)
- // libusb doesn't think we should be messing around with devices we don't have
- // write access to, but Linux at least lets us get the serial number anyway.
- if (!android::base::ReadFileToString(get_device_serial_path(device),
- &device_serial)) {
- // We don't actually want to treat an unknown serial as an error because
- // devices aren't able to communicate a serial number in early bringup.
- // http://b/20883914
- device_serial = "unknown";
- }
- device_serial = android::base::Trim(device_serial);
-#else
- // On Mac OS and Windows, we're screwed. But I don't think this situation actually
- // happens on those OSes.
- continue;
-#endif
- }
-
- auto result = std::make_unique<usb_handle>(device_address, device_serial,
- std::move(handle), interface_num, bulk_in,
- bulk_out, zero_mask, packet_size);
- usb_handle* usb_handle_raw = result.get();
-
- {
- std::unique_lock<std::mutex> lock(usb_handles_mutex);
- usb_handles[device_address] = std::move(result);
- }
-
- register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(),
- writable);
-
- LOG(INFO) << "registered new usb device '" << device_serial << "'";
+ process_device(list[i]);
}
+
libusb_free_device_list(list, 1);
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;
+ }
}
}
@@ -408,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 7d5352d..1c94298 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -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 79d5c08..37d54d7 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -1,6 +1,5 @@
cc_defaults {
name: "debuggerd_defaults",
- defaults: ["linux_bionic_supported"],
cflags: [
"-Wall",
"-Wextra",
@@ -222,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/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 568879e..0b4bbfb 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -29,6 +29,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/macros.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
@@ -149,7 +150,7 @@
// Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
void FinishIntercept(int* result);
- void StartProcess(std::function<void()> function);
+ void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
void StartCrasher(const std::string& crash_type);
void FinishCrasher();
void AssertDeath(int signo);
@@ -195,14 +196,14 @@
}
}
-void CrasherTest::StartProcess(std::function<void()> function) {
+void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
unique_fd read_pipe;
unique_fd crasher_read_pipe;
if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
FAIL() << "failed to create pipe: " << strerror(errno);
}
- crasher_pid = fork();
+ crasher_pid = forker();
if (crasher_pid == -1) {
FAIL() << "fork failed: " << strerror(errno);
} else if (crasher_pid == 0) {
@@ -527,6 +528,37 @@
ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
}
+TEST_F(CrasherTest, fake_pid) {
+ int intercept_result;
+ unique_fd output_fd;
+
+ // Prime the getpid/gettid caches.
+ UNUSED(getpid());
+ UNUSED(gettid());
+
+ std::function<pid_t()> clone_fn = []() {
+ return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
+ };
+ StartProcess(
+ []() {
+ ASSERT_NE(getpid(), syscall(__NR_getpid));
+ ASSERT_NE(gettid(), syscall(__NR_gettid));
+ raise(SIGSEGV);
+ },
+ clone_fn);
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
+}
+
TEST(crash_dump, zombie) {
pid_t forkpid = fork();
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 6e3e6ac..8fd6e11 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -61,6 +61,16 @@
#define CRASH_DUMP_PATH "/system/bin/" CRASH_DUMP_NAME
+// Wrappers that directly invoke the respective syscalls, in case the cached values are invalid.
+#pragma GCC poison getpid gettid
+static pid_t __getpid() {
+ return syscall(__NR_getpid);
+}
+
+static pid_t __gettid() {
+ return syscall(__NR_gettid);
+}
+
static inline void futex_wait(volatile void* ftx, int value) {
syscall(__NR_futex, ftx, FUTEX_WAIT, value, nullptr, nullptr, 0);
}
@@ -124,7 +134,7 @@
}
if (signum == DEBUGGER_SIGNAL) {
- async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", gettid(),
+ async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", __gettid(),
thread_name);
return;
}
@@ -177,7 +187,7 @@
}
async_safe_format_log(ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s)",
- signum, signal_name, code_desc, addr_desc, gettid(), thread_name);
+ signum, signal_name, code_desc, addr_desc, __gettid(), thread_name);
}
/*
@@ -337,7 +347,7 @@
// rt_tgsigqueueinfo(2) to preserve SA_SIGINFO) will cause it to be delivered
// when our signal handler returns.
if (crash_dump_started || info->si_signo != DEBUGGER_SIGNAL) {
- int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), info->si_signo, info);
+ int rc = syscall(SYS_rt_tgsigqueueinfo, __getpid(), __gettid(), info->si_signo, info);
if (rc != 0) {
fatal_errno("failed to resend signal during crash");
}
@@ -362,7 +372,7 @@
memset(&si, 0, sizeof(si));
si.si_signo = signal_number;
si.si_code = SI_USER;
- si.si_pid = getpid();
+ si.si_pid = __getpid();
si.si_uid = getuid();
info = &si;
} else if (info->si_code >= 0 || info->si_code == SI_TKILL) {
@@ -404,7 +414,7 @@
debugger_thread_info thread_info = {
.crash_dump_started = false,
.pseudothread_tid = -1,
- .crashing_tid = gettid(),
+ .crashing_tid = __gettid(),
.signal_number = signal_number,
.info = info
};
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 2c578a9..80def73 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -14,10 +14,12 @@
LOCAL_PATH:= $(call my-dir)
-fastboot_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
+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 \
@@ -39,8 +41,6 @@
LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
-
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..f10b9ce 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) {
+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,35 @@
}
}
-#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 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;
- while (argc > 0) {
- command += *argv;
- skip(1);
- if (argc != 0) command += " ";
+ while (!args->empty()) {
+ if (!command.empty()) command += ' ';
+ command += next_arg(args);
}
fb_queue_command(command.c_str(), "");
- return 0;
}
static int64_t parse_num(const char *arg)
@@ -1354,7 +1344,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 +1365,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 +1377,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 +1495,7 @@
cmdline = optarg;
break;
case 'h':
- usage();
- return 1;
+ return show_help();
case 'i': {
char *endptr = nullptr;
unsigned long val;
@@ -1555,7 +1544,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 +1572,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 +1609,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 +1629,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 +1709,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 +1731,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 +1755,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 +1797,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..c21139e 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,8 +486,7 @@
return nullptr;
}
- FsManagerAvbOps avb_ops(device_file_by_name_prefix);
- AvbSlotVerifyResult verify_result = avb_ops.AvbSlotVerify(
+ AvbSlotVerifyResult verify_result = avb_ops->AvbSlotVerify(
fs_mgr_get_slot_suffix(), avb_verifier->IsDeviceUnlocked(), &avb_handle->avb_slot_data_);
// Only allow two verify results:
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index caee4ec..8feeb53 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;
}
diff --git a/fs_mgr/fs_mgr_avb_ops.h b/fs_mgr/fs_mgr_priv_avb_ops.h
similarity index 87%
rename from fs_mgr/fs_mgr_avb_ops.h
rename to fs_mgr/fs_mgr_priv_avb_ops.h
index ec4a8c9..a6b52e4 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);
@@ -56,7 +60,9 @@
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/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 0bf173b..5fa10bc 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -663,7 +663,7 @@
/* use the kernel parameter if set */
std::string veritymode;
if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
- if (veritymode.compare("enforcing")) {
+ if (veritymode == "enforcing") {
*mode = VERITY_MODE_DEFAULT;
}
return 0;
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 537bbee..d25e119 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 \
@@ -139,6 +143,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 3dadfd7..1eacb36 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -150,7 +150,12 @@
}
static int do_domainname(const std::vector<std::string>& args) {
- return write_file("/proc/sys/kernel/domainname", args[1]) ? 0 : 1;
+ std::string err;
+ if (!WriteFile("/proc/sys/kernel/domainname", args[1], &err)) {
+ LOG(ERROR) << err;
+ return -1;
+ }
+ return 0;
}
static int do_enable(const std::vector<std::string>& args) {
@@ -174,7 +179,12 @@
}
static int do_hostname(const std::vector<std::string>& args) {
- return write_file("/proc/sys/kernel/hostname", args[1]) ? 0 : 1;
+ std::string err;
+ if (!WriteFile("/proc/sys/kernel/hostname", args[1], &err)) {
+ LOG(ERROR) << err;
+ return -1;
+ }
+ return 0;
}
static int do_ifup(const std::vector<std::string>& args) {
@@ -215,11 +225,19 @@
}
if (args.size() >= 4) {
- uid_t uid = decode_uid(args[3].c_str());
+ uid_t uid;
+ std::string decode_uid_err;
+ if (!DecodeUid(args[3], &uid, &decode_uid_err)) {
+ LOG(ERROR) << "Unable to find UID for '" << args[3] << "': " << decode_uid_err;
+ return -1;
+ }
gid_t gid = -1;
if (args.size() == 5) {
- gid = decode_uid(args[4].c_str());
+ if (!DecodeUid(args[4], &gid, &decode_uid_err)) {
+ LOG(ERROR) << "Unable to find GID for '" << args[3] << "': " << decode_uid_err;
+ return -1;
+ }
}
if (lchown(args[1].c_str(), uid, gid) == -1) {
@@ -643,29 +661,49 @@
}
static int do_write(const std::vector<std::string>& args) {
- return write_file(args[1], args[2]) ? 0 : 1;
+ std::string err;
+ if (!WriteFile(args[1], args[2], &err)) {
+ LOG(ERROR) << err;
+ return -1;
+ }
+ return 0;
}
static int do_copy(const std::vector<std::string>& args) {
std::string data;
- if (read_file(args[1], &data)) {
- return write_file(args[2], data) ? 0 : 1;
+ std::string err;
+ if (!ReadFile(args[1], &data, &err)) {
+ LOG(ERROR) << err;
+ return -1;
}
- return 1;
+ if (!WriteFile(args[2], data, &err)) {
+ LOG(ERROR) << err;
+ return -1;
+ }
+ return 0;
}
static int do_chown(const std::vector<std::string>& args) {
- /* GID is optional. */
- if (args.size() == 3) {
- if (lchown(args[2].c_str(), decode_uid(args[1].c_str()), -1) == -1)
- return -errno;
- } else if (args.size() == 4) {
- if (lchown(args[3].c_str(), decode_uid(args[1].c_str()),
- decode_uid(args[2].c_str())) == -1)
- return -errno;
- } else {
+ uid_t uid;
+ std::string decode_uid_err;
+ if (!DecodeUid(args[1], &uid, &decode_uid_err)) {
+ LOG(ERROR) << "Unable to find UID for '" << args[1] << "': " << decode_uid_err;
return -1;
}
+
+ // GID is optional and pushes the index of path out by one if specified.
+ const std::string& path = (args.size() == 4) ? args[3] : args[2];
+ gid_t gid = -1;
+
+ if (args.size() == 4) {
+ if (!DecodeUid(args[2], &gid, &decode_uid_err)) {
+ LOG(ERROR) << "Unable to find GID for '" << args[2] << "': " << decode_uid_err;
+ return -1;
+ }
+ }
+
+ if (lchown(path.c_str(), uid, gid) == -1) return -errno;
+
return 0;
}
@@ -724,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/descriptors.cpp b/init/descriptors.cpp
index b2142ca..6f729a3 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -23,6 +23,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/android_get_control_file.h>
#include <cutils/sockets.h>
@@ -77,10 +78,12 @@
}
int SocketInfo::Create(const std::string& context) const {
- int flags = ((type() == "stream" ? SOCK_STREAM :
- (type() == "dgram" ? SOCK_DGRAM :
- SOCK_SEQPACKET)));
- return create_socket(name().c_str(), flags, perm(), uid(), gid(), context.c_str(), sehandle);
+ auto types = android::base::Split(type(), "+");
+ int flags =
+ ((types[0] == "stream" ? SOCK_STREAM : (types[0] == "dgram" ? SOCK_DGRAM : SOCK_SEQPACKET)));
+ bool passcred = types.size() > 1 && types[1] == "passcred";
+ return CreateSocket(name().c_str(), flags, passcred, perm(), uid(), gid(), context.c_str(),
+ sehandle);
}
const std::string SocketInfo::key() const {
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 52f6b0c..878f164 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -853,7 +853,9 @@
}
}
- if (!write_file("/sys/fs/selinux/checkreqprot", "0")) {
+ std::string err;
+ if (!WriteFile("/sys/fs/selinux/checkreqprot", "0", &err)) {
+ LOG(ERROR) << err;
security_failure();
}
@@ -869,23 +871,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.
@@ -994,7 +996,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/init_parser.cpp b/init/init_parser.cpp
index 620367a..1b31cf2 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -110,7 +110,9 @@
LOG(INFO) << "Parsing file " << path << "...";
Timer t;
std::string data;
- if (!read_file(path, &data)) {
+ std::string err;
+ if (!ReadFile(path, &data, &err)) {
+ LOG(ERROR) << err;
return false;
}
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
index d8fd2ba..86d60d0 100644
--- a/init/init_parser_test.cpp
+++ b/init/init_parser_test.cpp
@@ -86,19 +86,29 @@
ASSERT_EQ("", svc->seclabel());
}
if (uid) {
- ASSERT_EQ(decode_uid("log"), svc->uid());
+ uid_t decoded_uid;
+ std::string err;
+ ASSERT_TRUE(DecodeUid("log", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->uid());
} else {
ASSERT_EQ(0U, svc->uid());
}
if (gid) {
- ASSERT_EQ(decode_uid("shell"), svc->gid());
+ uid_t decoded_uid;
+ std::string err;
+ ASSERT_TRUE(DecodeUid("shell", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->gid());
} else {
ASSERT_EQ(0U, svc->gid());
}
if (supplementary_gids) {
ASSERT_EQ(2U, svc->supp_gids().size());
- ASSERT_EQ(decode_uid("system"), svc->supp_gids()[0]);
- ASSERT_EQ(decode_uid("adb"), svc->supp_gids()[1]);
+ uid_t decoded_uid;
+ std::string err;
+ ASSERT_TRUE(DecodeUid("system", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->supp_gids()[0]);
+ ASSERT_TRUE(DecodeUid("adb", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->supp_gids()[1]);
} else {
ASSERT_EQ(0U, svc->supp_gids().size());
}
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 3da14b5..7093ba9 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -152,10 +152,11 @@
"on boot\n"
"execute 3";
// clang-format on
- // write_file() ensures the right mode is set
- ASSERT_TRUE(write_file(std::string(dir.path) + "/a.rc", dir_a_script));
+ // WriteFile() ensures the right mode is set
+ std::string err;
+ ASSERT_TRUE(WriteFile(std::string(dir.path) + "/a.rc", dir_a_script, &err));
- ASSERT_TRUE(write_file(std::string(dir.path) + "/b.rc", "on boot\nexecute 5"));
+ ASSERT_TRUE(WriteFile(std::string(dir.path) + "/b.rc", "on boot\nexecute 5", &err));
// clang-format off
std::string start_script = "import " + std::string(first_import.path) + "\n"
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 6f40d1c..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;
}
}
@@ -510,8 +510,9 @@
static void load_properties_from_file(const char* filename, const char* filter) {
Timer t;
std::string data;
- if (!read_file(filename, &data)) {
- PLOG(WARNING) << "Couldn't load properties from " << filename;
+ std::string err;
+ if (!ReadFile(filename, &data, &err)) {
+ PLOG(WARNING) << "Couldn't load property file: " << err;
return;
}
data.push_back('\n');
@@ -658,8 +659,8 @@
void start_property_service() {
property_set("ro.property_service.version", "2");
- property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- 0666, 0, 0, nullptr, sehandle);
+ property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+ false, 0666, 0, 0, nullptr, sehandle);
if (property_set_fd == -1) {
PLOG(ERROR) << "start_property_service socket creation failed";
exit(1);
diff --git a/init/service.cpp b/init/service.cpp
index 3a9f622..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() {
@@ -380,9 +392,18 @@
}
bool Service::ParseGroup(const std::vector<std::string>& args, std::string* err) {
- gid_ = decode_uid(args[1].c_str());
+ std::string decode_uid_err;
+ if (!DecodeUid(args[1], &gid_, &decode_uid_err)) {
+ *err = "Unable to find GID for '" + args[1] + "': " + decode_uid_err;
+ return false;
+ }
for (std::size_t n = 2; n < args.size(); n++) {
- supp_gids_.emplace_back(decode_uid(args[n].c_str()));
+ gid_t gid;
+ if (!DecodeUid(args[n], &gid, &decode_uid_err)) {
+ *err = "Unable to find GID for '" + args[n] + "': " + decode_uid_err;
+ return false;
+ }
+ supp_gids_.emplace_back(gid);
}
return true;
}
@@ -480,10 +501,25 @@
template <typename T>
bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
- uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
- gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
+ uid_t uid = 0;
+ gid_t gid = 0;
std::string context = args.size() > 6 ? args[6] : "";
+ std::string decode_uid_err;
+ if (args.size() > 4) {
+ if (!DecodeUid(args[4], &uid, &decode_uid_err)) {
+ *err = "Unable to find UID for '" + args[4] + "': " + decode_uid_err;
+ return false;
+ }
+ }
+
+ if (args.size() > 5) {
+ if (!DecodeUid(args[5], &gid, &decode_uid_err)) {
+ *err = "Unable to find GID for '" + args[5] + "': " + decode_uid_err;
+ return false;
+ }
+ }
+
auto descriptor = std::make_unique<T>(args[1], args[2], uid, gid, perm, context);
auto old =
@@ -501,7 +537,9 @@
// name type perm [ uid gid context ]
bool Service::ParseSocket(const std::vector<std::string>& args, std::string* err) {
- if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
+ if (!android::base::StartsWith(args[2], "dgram") &&
+ !android::base::StartsWith(args[2], "stream") &&
+ !android::base::StartsWith(args[2], "seqpacket")) {
*err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
return false;
}
@@ -522,7 +560,11 @@
}
bool Service::ParseUser(const std::vector<std::string>& args, std::string* err) {
- uid_ = decode_uid(args[1].c_str());
+ std::string decode_uid_err;
+ if (!DecodeUid(args[1], &uid_, &decode_uid_err)) {
+ *err = "Unable to find UID for '" + args[1] + "': " + decode_uid_err;
+ return false;
+ }
return true;
}
@@ -736,6 +778,7 @@
time_started_ = boot_clock::now();
pid_ = pid;
flags_ |= SVC_RUNNING;
+ process_cgroup_empty_ = false;
errno = -createProcessGroup(uid_, pid_);
if (errno != 0) {
@@ -936,15 +979,28 @@
}
uid_t uid = 0;
if (command_arg > 3) {
- uid = decode_uid(args[2].c_str());
+ std::string decode_uid_err;
+ if (!DecodeUid(args[2], &uid, &decode_uid_err)) {
+ LOG(ERROR) << "Unable to find UID for '" << args[2] << "': " << decode_uid_err;
+ return nullptr;
+ }
}
gid_t gid = 0;
std::vector<gid_t> supp_gids;
if (command_arg > 4) {
- gid = decode_uid(args[3].c_str());
+ std::string decode_uid_err;
+ if (!DecodeUid(args[3], &gid, &decode_uid_err)) {
+ LOG(ERROR) << "Unable to find GID for '" << args[3] << "': " << decode_uid_err;
+ return nullptr;
+ }
std::size_t nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
for (size_t i = 0; i < nr_supp_gids; ++i) {
- supp_gids.push_back(decode_uid(args[4 + i].c_str()));
+ gid_t supp_gid;
+ if (!DecodeUid(args[4 + i], &supp_gid, &decode_uid_err)) {
+ LOG(ERROR) << "Unable to find UID for '" << args[4 + i] << "': " << decode_uid_err;
+ return nullptr;
+ }
+ supp_gids.push_back(supp_gid);
}
}
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 87b8d9d..75f81b9 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -48,49 +48,43 @@
#endif
using android::base::boot_clock;
+using namespace std::literals::string_literals;
-static unsigned int do_decode_uid(const char *s)
-{
- unsigned int v;
+// DecodeUid() - decodes and returns the given string, which can be either the
+// numeric or name representation, into the integer uid or gid. Returns
+// UINT_MAX on error.
+bool DecodeUid(const std::string& name, uid_t* uid, std::string* err) {
+ *uid = UINT_MAX;
+ *err = "";
- if (!s || *s == '\0')
- return UINT_MAX;
-
- if (isalpha(s[0])) {
- struct passwd* pwd = getpwnam(s);
- if (!pwd)
- return UINT_MAX;
- return pwd->pw_uid;
+ if (isalpha(name[0])) {
+ passwd* pwd = getpwnam(name.c_str());
+ if (!pwd) {
+ *err = "getpwnam failed: "s + strerror(errno);
+ return false;
+ }
+ *uid = pwd->pw_uid;
+ return true;
}
errno = 0;
- v = (unsigned int) strtoul(s, 0, 0);
- if (errno)
- return UINT_MAX;
- return v;
-}
-
-/*
- * decode_uid - decodes and returns the given string, which can be either the
- * numeric or name representation, into the integer uid or gid. Returns
- * UINT_MAX on error.
- */
-unsigned int decode_uid(const char *s) {
- unsigned int v = do_decode_uid(s);
- if (v == UINT_MAX) {
- LOG(ERROR) << "decode_uid: Unable to find UID for '" << s << "'; returning UINT_MAX";
+ uid_t result = static_cast<uid_t>(strtoul(name.c_str(), 0, 0));
+ if (errno) {
+ *err = "strtoul failed: "s + strerror(errno);
+ return false;
}
- return v;
+ *uid = result;
+ return true;
}
/*
- * create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR
+ * CreateSocket - creates a Unix domain socket in ANDROID_SOCKET_DIR
* ("/dev/socket") as dictated in init.rc. This socket is inherited by the
* daemon. We communicate the file descriptor's value via the environment
* variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
*/
-int create_socket(const char* name, int type, mode_t perm, uid_t uid, gid_t gid,
- const char* socketcon, selabel_handle* sehandle) {
+int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
+ const char* socketcon, selabel_handle* sehandle) {
if (socketcon) {
if (setsockcreatecon(socketcon) == -1) {
PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
@@ -124,6 +118,14 @@
}
}
+ if (passcred) {
+ int on = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
+ PLOG(ERROR) << "Failed to set SO_PASSCRED '" << name << "'";
+ return -1;
+ }
+ }
+
int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
int savederrno = errno;
@@ -157,12 +159,14 @@
return -1;
}
-bool read_file(const std::string& path, std::string* content) {
+bool ReadFile(const std::string& path, std::string* content, std::string* err) {
content->clear();
+ *err = "";
android::base::unique_fd fd(
TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
if (fd == -1) {
+ *err = "Unable to open '" + path + "': " + strerror(errno);
return false;
}
@@ -170,29 +174,35 @@
// or group-writable files.
struct stat sb;
if (fstat(fd, &sb) == -1) {
- PLOG(ERROR) << "fstat failed for '" << path << "'";
+ *err = "fstat failed for '" + path + "': " + strerror(errno);
return false;
}
if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
- LOG(ERROR) << "skipping insecure file '" << path << "'";
+ *err = "Skipping insecure file '" + path + "'";
return false;
}
- return android::base::ReadFdToString(fd, content);
+ if (!android::base::ReadFdToString(fd, content)) {
+ *err = "Unable to read '" + path + "': " + strerror(errno);
+ return false;
+ }
+ return true;
}
-bool write_file(const std::string& path, const std::string& content) {
+bool WriteFile(const std::string& path, const std::string& content, std::string* err) {
+ *err = "";
+
android::base::unique_fd fd(TEMP_FAILURE_RETRY(
open(path.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
if (fd == -1) {
- PLOG(ERROR) << "write_file: Unable to open '" << path << "'";
+ *err = "Unable to open '" + path + "': " + strerror(errno);
return false;
}
- bool success = android::base::WriteStringToFd(content, fd);
- if (!success) {
- PLOG(ERROR) << "write_file: Unable to write to '" << path << "'";
+ if (!android::base::WriteStringToFd(content, fd)) {
+ *err = "Unable to write to '" + path + "': " + strerror(errno);
+ return false;
}
- return success;
+ return true;
}
int mkdir_recursive(const std::string& path, mode_t mode, selabel_handle* sehandle) {
@@ -256,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 55ebded..1ad6b77 100644
--- a/init/util.h
+++ b/init/util.h
@@ -35,11 +35,11 @@
using android::base::boot_clock;
using namespace std::chrono_literals;
-int create_socket(const char* name, int type, mode_t perm, uid_t uid, gid_t gid,
- const char* socketcon, selabel_handle* sehandle);
+int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
+ const char* socketcon, selabel_handle* sehandle);
-bool read_file(const std::string& path, std::string* content);
-bool write_file(const std::string& path, const std::string& content);
+bool ReadFile(const std::string& path, std::string* content, std::string* err);
+bool WriteFile(const std::string& path, const std::string& content, std::string* err);
class Timer {
public:
@@ -61,14 +61,13 @@
std::ostream& operator<<(std::ostream& os, const Timer& t);
-unsigned int decode_uid(const char *s);
+bool DecodeUid(const std::string& name, uid_t* uid, std::string* err);
int mkdir_recursive(const std::string& pathname, mode_t mode, selabel_handle* sehandle);
int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
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/init/util_test.cpp b/init/util_test.cpp
index ac23a32..4bb8a83 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -24,53 +24,67 @@
#include <android-base/test_utils.h>
#include <gtest/gtest.h>
-TEST(util, read_file_ENOENT) {
- std::string s("hello");
- errno = 0;
- EXPECT_FALSE(read_file("/proc/does-not-exist", &s));
- EXPECT_EQ(ENOENT, errno);
- EXPECT_EQ("", s); // s was cleared.
+using namespace std::literals::string_literals;
+
+TEST(util, ReadFile_ENOENT) {
+ std::string s("hello");
+ std::string err;
+ errno = 0;
+ EXPECT_FALSE(ReadFile("/proc/does-not-exist", &s, &err));
+ EXPECT_EQ("Unable to open '/proc/does-not-exist': No such file or directory", err);
+ EXPECT_EQ(ENOENT, errno);
+ EXPECT_EQ("", s); // s was cleared.
}
-TEST(util, read_file_group_writeable) {
+TEST(util, ReadFileGroupWriteable) {
std::string s("hello");
TemporaryFile tf;
+ std::string err;
ASSERT_TRUE(tf.fd != -1);
- EXPECT_TRUE(write_file(tf.path, s)) << strerror(errno);
+ EXPECT_TRUE(WriteFile(tf.path, s, &err)) << strerror(errno);
+ EXPECT_EQ("", err);
EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0620, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
- EXPECT_FALSE(read_file(tf.path, &s)) << strerror(errno);
+ EXPECT_FALSE(ReadFile(tf.path, &s, &err)) << strerror(errno);
+ EXPECT_EQ("Skipping insecure file '"s + tf.path + "'", err);
EXPECT_EQ("", s); // s was cleared.
}
-TEST(util, read_file_world_writeable) {
+TEST(util, ReadFileWorldWiteable) {
std::string s("hello");
TemporaryFile tf;
+ std::string err;
ASSERT_TRUE(tf.fd != -1);
- EXPECT_TRUE(write_file(tf.path, s.c_str())) << strerror(errno);
+ EXPECT_TRUE(WriteFile(tf.path, s, &err)) << strerror(errno);
+ EXPECT_EQ("", err);
EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0602, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
- EXPECT_FALSE(read_file(tf.path, &s)) << strerror(errno);
+ EXPECT_FALSE(ReadFile(tf.path, &s, &err)) << strerror(errno);
+ EXPECT_EQ("Skipping insecure file '"s + tf.path + "'", err);
EXPECT_EQ("", s); // s was cleared.
}
-TEST(util, read_file_symbolic_link) {
+TEST(util, ReadFileSymbolicLink) {
std::string s("hello");
errno = 0;
// lrwxrwxrwx 1 root root 13 1970-01-01 00:00 charger -> /sbin/healthd
- EXPECT_FALSE(read_file("/charger", &s));
+ std::string err;
+ EXPECT_FALSE(ReadFile("/charger", &s, &err));
+ EXPECT_EQ("Unable to open '/charger': Too many symbolic links encountered", err);
EXPECT_EQ(ELOOP, errno);
EXPECT_EQ("", s); // s was cleared.
}
-TEST(util, read_file_success) {
- std::string s("hello");
- EXPECT_TRUE(read_file("/proc/version", &s));
- EXPECT_GT(s.length(), 6U);
- EXPECT_EQ('\n', s[s.length() - 1]);
- s[5] = 0;
- EXPECT_STREQ("Linux", s.c_str());
+TEST(util, ReadFileSuccess) {
+ std::string s("hello");
+ std::string err;
+ EXPECT_TRUE(ReadFile("/proc/version", &s, &err));
+ EXPECT_EQ("", err);
+ EXPECT_GT(s.length(), 6U);
+ EXPECT_EQ('\n', s[s.length() - 1]);
+ s[5] = 0;
+ EXPECT_STREQ("Linux", s.c_str());
}
-TEST(util, write_file_binary) {
+TEST(util, WriteFileBinary) {
std::string contents("abcd");
contents.push_back('\0');
contents.push_back('\0');
@@ -78,22 +92,28 @@
ASSERT_EQ(10u, contents.size());
TemporaryFile tf;
+ std::string err;
ASSERT_TRUE(tf.fd != -1);
- EXPECT_TRUE(write_file(tf.path, contents)) << strerror(errno);
+ EXPECT_TRUE(WriteFile(tf.path, contents, &err)) << strerror(errno);
+ EXPECT_EQ("", err);
std::string read_back_contents;
- EXPECT_TRUE(read_file(tf.path, &read_back_contents)) << strerror(errno);
+ EXPECT_TRUE(ReadFile(tf.path, &read_back_contents, &err)) << strerror(errno);
+ EXPECT_EQ("", err);
EXPECT_EQ(contents, read_back_contents);
EXPECT_EQ(10u, read_back_contents.size());
}
-TEST(util, write_file_not_exist) {
+TEST(util, WriteFileNotExist) {
std::string s("hello");
std::string s2("hello");
TemporaryDir test_dir;
std::string path = android::base::StringPrintf("%s/does-not-exist", test_dir.path);
- EXPECT_TRUE(write_file(path, s));
- EXPECT_TRUE(read_file(path, &s2));
+ std::string err;
+ EXPECT_TRUE(WriteFile(path, s, &err));
+ EXPECT_EQ("", err);
+ EXPECT_TRUE(ReadFile(path, &s2, &err));
+ EXPECT_EQ("", err);
EXPECT_EQ(s, s2);
struct stat sb;
int fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
@@ -103,22 +123,38 @@
EXPECT_EQ(0, unlink(path.c_str()));
}
-TEST(util, write_file_exist) {
+TEST(util, WriteFileExist) {
std::string s2("");
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
- EXPECT_TRUE(write_file(tf.path, "1hello1")) << strerror(errno);
- EXPECT_TRUE(read_file(tf.path, &s2));
+ std::string err;
+ EXPECT_TRUE(WriteFile(tf.path, "1hello1", &err)) << strerror(errno);
+ EXPECT_EQ("", err);
+ EXPECT_TRUE(ReadFile(tf.path, &s2, &err));
+ EXPECT_EQ("", err);
EXPECT_STREQ("1hello1", s2.c_str());
- EXPECT_TRUE(write_file(tf.path, "2ll2"));
- EXPECT_TRUE(read_file(tf.path, &s2));
+ EXPECT_TRUE(WriteFile(tf.path, "2ll2", &err));
+ EXPECT_EQ("", err);
+ EXPECT_TRUE(ReadFile(tf.path, &s2, &err));
+ EXPECT_EQ("", err);
EXPECT_STREQ("2ll2", s2.c_str());
}
-TEST(util, decode_uid) {
- EXPECT_EQ(0U, decode_uid("root"));
- EXPECT_EQ(UINT_MAX, decode_uid("toot"));
- EXPECT_EQ(123U, decode_uid("123"));
+TEST(util, DecodeUid) {
+ uid_t decoded_uid;
+ std::string err;
+
+ EXPECT_TRUE(DecodeUid("root", &decoded_uid, &err));
+ EXPECT_EQ("", err);
+ EXPECT_EQ(0U, decoded_uid);
+
+ EXPECT_FALSE(DecodeUid("toot", &decoded_uid, &err));
+ EXPECT_EQ("getpwnam failed: No such file or directory", err);
+ EXPECT_EQ(UINT_MAX, decoded_uid);
+
+ EXPECT_TRUE(DecodeUid("123", &decoded_uid, &err));
+ EXPECT_EQ("", err);
+ EXPECT_EQ(123U, decoded_uid);
}
TEST(util, is_dir) {
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 97c4975..48b50a5 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -53,7 +53,7 @@
#include <sys/cdefs.h>
#include <sys/types.h>
-#if defined(__ANDROID__)
+#if defined(__BIONIC__)
#include <linux/capability.h>
#else
#include "android_filesystem_capability.h"
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index ae7a334..1483c24 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -15,9 +15,7 @@
*/
/*
* Intercepts log messages intended for the Android log device.
- * When running in the context of the simulator, the messages are
- * passed on to the underlying (fake) log device. When not in the
- * simulator, messages are printed to stderr.
+ * Messages are printed to stderr.
*/
#include <ctype.h>
#include <errno.h>
@@ -561,7 +559,8 @@
* tag (N bytes -- null-terminated ASCII string)
* message (N bytes -- null-terminated ASCII string)
*/
-static ssize_t logWritev(int fd, const struct iovec* vector, int count) {
+LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd, const struct iovec* vector,
+ int count) {
LogState* state;
/* Make sure that no-one frees the LogState while we're using it.
@@ -626,8 +625,18 @@
/*
* Free up our state and close the fake descriptor.
+ *
+ * The logger API has no means or need to 'stop' or 'close' using the logs,
+ * and as such, there is no way for that 'stop' or 'close' to translate into
+ * a close operation to the fake log handler. fakeLogClose is provided for
+ * completeness only.
+ *
+ * We have no intention of adding a log close operation as it would complicate
+ * every user of the logging API with no gain since the only valid place to
+ * call is in the exit handler. Logging can continue in the exit handler to
+ * help debug HOST tools ...
*/
-static int logClose(int fd) {
+LIBLOG_HIDDEN int fakeLogClose(int fd) {
deleteFakeFd(fd);
return 0;
}
@@ -635,7 +644,7 @@
/*
* Open a log output device and return a fake fd.
*/
-static int logOpen(const char* pathName, int flags __unused) {
+LIBLOG_HIDDEN int fakeLogOpen(const char* pathName) {
LogState* logState;
int fd = -1;
@@ -654,66 +663,6 @@
return fd;
}
-/*
- * Runtime redirection. If this binary is running in the simulator,
- * just pass log messages to the emulated device. If it's running
- * outside of the simulator, write the log messages to stderr.
- */
-
-static int (*redirectOpen)(const char* pathName, int flags) = NULL;
-static int (*redirectClose)(int fd) = NULL;
-static ssize_t (*redirectWritev)(int fd, const struct iovec* vector,
- int count) = NULL;
-
-static void setRedirects() {
- const char* ws;
-
- /* Wrapsim sets this environment variable on children that it's
- * created using its LD_PRELOAD wrapper.
- */
- ws = getenv("ANDROID_WRAPSIM");
- if (ws != NULL && strcmp(ws, "1") == 0) {
- /* We're running inside wrapsim, so we can just write to the device. */
- redirectOpen = (int (*)(const char* pathName, int flags))open;
- redirectClose = close;
- redirectWritev = writev;
- } else {
- /* There's no device to delegate to; handle the logging ourselves. */
- redirectOpen = logOpen;
- redirectClose = logClose;
- redirectWritev = logWritev;
- }
-}
-
-LIBLOG_HIDDEN int fakeLogOpen(const char* pathName, int flags) {
- if (redirectOpen == NULL) {
- setRedirects();
- }
- return redirectOpen(pathName, flags);
-}
-
-/*
- * The logger API has no means or need to 'stop' or 'close' using the logs,
- * and as such, there is no way for that 'stop' or 'close' to translate into
- * a close operation to the fake log handler. fakeLogClose is provided for
- * completeness only.
- *
- * We have no intention of adding a log close operation as it would complicate
- * every user of the logging API with no gain since the only valid place to
- * call is in the exit handler. Logging can continue in the exit handler to
- * help debug HOST tools ...
- */
-LIBLOG_HIDDEN int fakeLogClose(int fd) {
- /* Assume that open() was called first. */
- return redirectClose(fd);
-}
-
-LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd, const struct iovec* vector,
- int count) {
- /* Assume that open() was called first. */
- return redirectWritev(fd, vector, count);
-}
-
LIBLOG_HIDDEN ssize_t __send_log_msg(char* buf __unused,
size_t buf_size __unused) {
return -ENODEV;
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index 462d026..7b0e745 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -23,7 +23,7 @@
struct iovec;
-LIBLOG_HIDDEN int fakeLogOpen(const char* pathName, int flags);
+LIBLOG_HIDDEN int fakeLogOpen(const char* pathName);
LIBLOG_HIDDEN int fakeLogClose(int fd);
LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd, const struct iovec* vector,
int count);
diff --git a/liblog/fake_writer.c b/liblog/fake_writer.c
index 969661a..403dc72 100644
--- a/liblog/fake_writer.c
+++ b/liblog/fake_writer.c
@@ -55,9 +55,9 @@
continue;
}
snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
- logFds[i] = fakeLogOpen(buf, O_WRONLY);
+ logFds[i] = fakeLogOpen(buf);
if (logFds[i] < 0) {
- fprintf(stderr, "fakeLogOpen(%s, O_WRONLY) failed\n", buf);
+ fprintf(stderr, "fakeLogOpen(%s) failed\n", buf);
}
}
return 0;
diff --git a/libmemunreachable/tests/DisableMalloc_test.cpp b/libmemunreachable/tests/DisableMalloc_test.cpp
index ea5c22c..4e6155b 100644
--- a/libmemunreachable/tests/DisableMalloc_test.cpp
+++ b/libmemunreachable/tests/DisableMalloc_test.cpp
@@ -74,7 +74,7 @@
{
alarm(100ms);
ScopedDisableMalloc disable_malloc;
- char* ptr = new(char);
+ char* ptr = new (std::nothrow)(char);
ASSERT_NE(ptr, nullptr);
delete(ptr);
}
@@ -89,6 +89,8 @@
alarm(250ms);
ScopedDisableMalloc disable_malloc;
delete(ptr);
+ // Force ptr usage or this code gets optimized away by the arm64 compiler.
+ ASSERT_NE(ptr, nullptr);
}
}, "");
}
diff --git a/libmemunreachable/tests/MemUnreachable_test.cpp b/libmemunreachable/tests/MemUnreachable_test.cpp
index 2ae3db8..71da365 100644
--- a/libmemunreachable/tests/MemUnreachable_test.cpp
+++ b/libmemunreachable/tests/MemUnreachable_test.cpp
@@ -23,8 +23,6 @@
#include <memunreachable/memunreachable.h>
-void* ptr;
-
class HiddenPointer {
public:
explicit HiddenPointer(size_t size = 256) {
@@ -92,10 +90,12 @@
}
}
+void* g_ptr;
+
TEST(MemunreachableTest, global) {
HiddenPointer hidden_ptr;
- ptr = hidden_ptr.Get();
+ g_ptr = hidden_ptr.Get();
{
UnreachableMemoryInfo info;
@@ -104,7 +104,7 @@
ASSERT_EQ(0U, info.leaks.size());
}
- ptr = NULL;
+ g_ptr = nullptr;
{
UnreachableMemoryInfo info;
@@ -126,7 +126,7 @@
TEST(MemunreachableTest, tls) {
HiddenPointer hidden_ptr;
pthread_key_t key;
- pthread_key_create(&key, NULL);
+ pthread_key_create(&key, nullptr);
pthread_setspecific(key, hidden_ptr.Get());
diff --git a/libmemunreachable/tests/ThreadCapture_test.cpp b/libmemunreachable/tests/ThreadCapture_test.cpp
index 41ed84e..44aabd7 100644
--- a/libmemunreachable/tests/ThreadCapture_test.cpp
+++ b/libmemunreachable/tests/ThreadCapture_test.cpp
@@ -55,7 +55,7 @@
threads_.reserve(threads);
tids_.reserve(threads);
for (unsigned int i = 0; i < threads; i++) {
- threads_.emplace_back([&, i, threads, this]() {
+ threads_.emplace_back([&, threads, this]() {
{
std::lock_guard<std::mutex> lk(m_);
tids_.push_back(gettid());
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 5fb56f2..377b7dd 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -22,3 +22,5 @@
},
},
}
+
+subdirs = ["tests"]
\ No newline at end of file
diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp
new file mode 100644
index 0000000..efd3978
--- /dev/null
+++ b/libnativebridge/tests/Android.bp
@@ -0,0 +1,53 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_defaults {
+ name: "libnativebridge-dummy-defaults",
+
+ host_supported: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ cppflags: ["-fvisibility=protected"],
+ target: {
+ android: {
+ shared_libs: ["libdl"],
+ },
+ host: {
+ host_ldlibs: ["-ldl"],
+ },
+ },
+}
+
+cc_library_shared {
+ name: "libnativebridge-dummy",
+ srcs: ["DummyNativeBridge.cpp"],
+ defaults: ["libnativebridge-dummy-defaults"],
+}
+
+cc_library_shared {
+ name: "libnativebridge2-dummy",
+ srcs: ["DummyNativeBridge2.cpp"],
+ defaults: ["libnativebridge-dummy-defaults"],
+}
+
+cc_library_shared {
+ name: "libnativebridge3-dummy",
+ srcs: ["DummyNativeBridge3.cpp"],
+ defaults: ["libnativebridge-dummy-defaults"],
+}
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index c9468f0..70b3fcc 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -1,8 +1,6 @@
# Build the unit tests.
LOCAL_PATH := $(call my-dir)
-include $(LOCAL_PATH)/Android.nativebridge-dummy.mk
-
include $(CLEAR_VARS)
# Build the unit tests.
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
deleted file mode 100644
index 2d78be0..0000000
--- a/libnativebridge/tests/Android.nativebridge-dummy.mk
+++ /dev/null
@@ -1,108 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-NATIVE_BRIDGE_COMMON_SRC_FILES := \
- DummyNativeBridge.cpp
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_SHARED_LIBRARIES := libdl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-# v2.
-
-NATIVE_BRIDGE2_COMMON_SRC_FILES := \
- DummyNativeBridge2.cpp
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge2-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_SHARED_LIBRARIES := libdl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge2-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-# v3.
-
-NATIVE_BRIDGE3_COMMON_SRC_FILES := \
- DummyNativeBridge3.cpp
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge3-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge3-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
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/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/logd/LogListener.cpp b/logd/LogListener.cpp
index 709646e..3c0d08d 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -119,14 +119,14 @@
static const char socketName[] = "logdw";
int sock = android_get_control_socket(socketName);
- if (sock < 0) {
+ if (sock < 0) { // logd started up in init.sh
sock = socket_local_server(
socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
- }
- int on = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
- return -1;
+ int on = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
+ return -1;
+ }
}
return sock;
}
diff --git a/logd/logd.rc b/logd/logd.rc
index 7494d8f..8804246 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -1,7 +1,7 @@
service logd /system/bin/logd
socket logd stream 0666 logd logd
socket logdr seqpacket 0666 logd logd
- socket logdw dgram 0222 logd logd
+ socket logdw dgram+passcred 0222 logd logd
file /proc/kmsg r
file /dev/kmsg w
user logd
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/init.rc b/rootdir/init.rc
index 8cdc13f..540e976 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -419,6 +419,7 @@
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp
mkdir /data/local/tmp 0771 shell shell
+ mkdir /data/data 0771 system system
mkdir /data/app-private 0771 system system
mkdir /data/app-ephemeral 0771 system system
mkdir /data/app-asec 0700 root root
@@ -471,8 +472,7 @@
mkdir /data/user 0711 system system
mkdir /data/user_de 0711 system system
- mkdir /data/user/0 0711 system system
- symlink /data/user/0 /data/data
+ symlink /data/data /data/user/0
mkdir /data/media 0770 media_rw media_rw
mkdir /data/media/obb 0770 media_rw media_rw
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)