Merge "first stage mount: removing the requirement of by-name prefix for AVB"
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 7539e5a..15d4b7a 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -184,6 +184,195 @@
(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");
@@ -193,198 +382,9 @@
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();
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/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..be7bf4a 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;
@@ -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_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/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_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/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/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/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/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)