Merge "fix static-analyzer logging/CHECK macros"
diff --git a/adb/Android.mk b/adb/Android.mk
index 112bc80..ca337ee 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -5,23 +5,27 @@
LOCAL_PATH:= $(call my-dir)
+include $(LOCAL_PATH)/../platform_tools_tool_version.mk
+
adb_host_sanitize :=
adb_target_sanitize :=
-adb_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
-
ADB_COMMON_CFLAGS := \
-Wall -Wextra -Werror \
-Wno-unused-parameter \
-Wno-missing-field-initializers \
-Wvla \
- -DADB_REVISION='"$(adb_version)"' \
+ -DADB_VERSION=\"$(tool_version)\" \
+
+ADB_COMMON_posix_CFLAGS := \
+ -Wexit-time-destructors \
+ -Wthread-safety
ADB_COMMON_linux_CFLAGS := \
- -Wexit-time-destructors \
+ $(ADB_COMMON_posix_CFLAGS) \
ADB_COMMON_darwin_CFLAGS := \
- -Wexit-time-destructors \
+ $(ADB_COMMON_posix_CFLAGS) \
# Define windows.h and tchar.h Unicode preprocessor symbols so that
# CreateFile(), _tfopen(), etc. map to versions that take wchar_t*, breaking the
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 39e71e5..c1e0d98 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -31,6 +31,8 @@
#include <time.h>
#include <chrono>
+#include <condition_variable>
+#include <mutex>
#include <string>
#include <thread>
#include <vector>
@@ -48,6 +50,7 @@
#include "adb_io.h"
#include "adb_listeners.h"
#include "adb_utils.h"
+#include "sysdeps/chrono.h"
#include "transport.h"
#if !ADB_HOST
@@ -61,9 +64,9 @@
// Don't change the format of this --- it's parsed by ddmlib.
return android::base::StringPrintf(
"Android Debug Bridge version %d.%d.%d\n"
- "Revision %s\n"
+ "Version %s\n"
"Installed as %s\n",
- ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_REVISION,
+ ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_VERSION,
android::base::GetExecutablePath().c_str());
}
@@ -313,19 +316,15 @@
if (type == "bootloader") {
D("setting connection_state to kCsBootloader");
t->SetConnectionState(kCsBootloader);
- update_transports();
} else if (type == "device") {
D("setting connection_state to kCsDevice");
t->SetConnectionState(kCsDevice);
- update_transports();
} else if (type == "recovery") {
D("setting connection_state to kCsRecovery");
t->SetConnectionState(kCsRecovery);
- update_transports();
} else if (type == "sideload") {
D("setting connection_state to kCsSideload");
t->SetConnectionState(kCsSideload);
- update_transports();
} else {
D("setting connection_state to kCsHost");
t->SetConnectionState(kCsHost);
@@ -353,6 +352,8 @@
send_auth_request(t);
}
#endif
+
+ update_transports();
}
void handle_packet(apacket *p, atransport *t)
@@ -1229,4 +1230,50 @@
return ret - 1;
return -1;
}
+
+static auto& init_mutex = *new std::mutex();
+static auto& init_cv = *new std::condition_variable();
+static bool device_scan_complete = false;
+static bool transports_ready = false;
+
+void update_transport_status() {
+ bool result = iterate_transports([](const atransport* t) {
+ if (t->type == kTransportUsb && t->online != 1) {
+ return false;
+ }
+ return true;
+ });
+
+ D("update_transport_status: transports_ready = %s", result ? "true" : "false");
+
+ bool ready;
+
+ {
+ std::lock_guard<std::mutex> lock(init_mutex);
+ transports_ready = result;
+ ready = transports_ready && device_scan_complete;
+ }
+
+ if (ready) {
+ D("update_transport_status: notifying");
+ init_cv.notify_all();
+ }
+}
+
+void adb_notify_device_scan_complete() {
+ D("device scan complete");
+
+ {
+ std::lock_guard<std::mutex> lock(init_mutex);
+ device_scan_complete = true;
+ }
+
+ update_transport_status();
+}
+
+void adb_wait_for_device_initialization() {
+ std::unique_lock<std::mutex> lock(init_mutex);
+ init_cv.wait_for(lock, 3s, []() { return device_scan_complete && transports_ready; });
+}
+
#endif // ADB_HOST
diff --git a/adb/adb.h b/adb/adb.h
index e3675d8..d6b2b81 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -228,4 +228,18 @@
void parse_banner(const std::string&, atransport* t);
+// On startup, the adb server needs to wait until all of the connected devices are ready.
+// To do this, we need to know when the scan has identified all of the potential new transports, and
+// when each transport becomes ready.
+// TODO: Do this for mDNS as well, instead of just USB?
+
+// We've found all of the transports we potentially care about.
+void adb_notify_device_scan_complete();
+
+// One or more transports have changed status, check to see if we're ready.
+void update_transport_status();
+
+// Wait until device scan has completed and every transport is ready, or a timeout elapses.
+void adb_wait_for_device_initialization();
+
#endif
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index b656887..4f3ff25 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -28,12 +28,15 @@
#include <sys/stat.h>
#include <sys/types.h>
+#include <condition_variable>
+#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/thread_annotations.h>
#include <cutils/sockets.h>
#include "adb_io.h"
@@ -177,9 +180,8 @@
} else {
fprintf(stderr, "* daemon started successfully\n");
}
- // Give the server some time to start properly and detect devices.
- std::this_thread::sleep_for(3s);
- // fall through to _adb_connect
+ // The server will wait until it detects all of its connected devices before acking.
+ // Fall through to _adb_connect.
} else {
// If a server is already running, check its version matches.
int version = ADB_SERVER_VERSION - 1;
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index da2cfa2..d0cc072 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -48,7 +48,7 @@
show_progress_(show_progress),
status_(0),
line_(),
- last_progress_(0) {
+ last_progress_percentage_(0) {
SetLineMessage("generating");
}
@@ -147,13 +147,14 @@
size_t idx1 = line.rfind(BUGZ_PROGRESS_PREFIX) + strlen(BUGZ_PROGRESS_PREFIX);
size_t idx2 = line.rfind(BUGZ_PROGRESS_SEPARATOR);
int progress = std::stoi(line.substr(idx1, (idx2 - idx1)));
- if (progress <= last_progress_) {
+ int total = std::stoi(line.substr(idx2 + 1));
+ int progress_percentage = (progress * 100 / total);
+ if (progress_percentage <= last_progress_percentage_) {
// Ignore.
return;
}
- last_progress_ = progress;
- int total = std::stoi(line.substr(idx2 + 1));
- br_->UpdateProgress(line_message_, progress, total);
+ last_progress_percentage_ = progress_percentage;
+ br_->UpdateProgress(line_message_, progress_percentage);
} else {
invalid_lines_.push_back(line);
}
@@ -189,7 +190,7 @@
// Last displayed progress.
// Since dumpstate progress can recede, only forward progress should be displayed
- int last_progress_;
+ int last_progress_percentage_;
DISALLOW_COPY_AND_ASSIGN(BugreportStandardStreamsCallback);
};
@@ -267,8 +268,7 @@
return SendShellCommand(transport_type, serial, bugz_command, false, &bugz_callback);
}
-void Bugreport::UpdateProgress(const std::string& message, int progress, int total) {
- int progress_percentage = (progress * 100 / total);
+void Bugreport::UpdateProgress(const std::string& message, int progress_percentage) {
line_printer_.Print(
android::base::StringPrintf("[%3d%%] %s", progress_percentage, message.c_str()),
LinePrinter::INFO);
diff --git a/adb/bugreport.h b/adb/bugreport.h
index ee99cbc..d9a4468 100644
--- a/adb/bugreport.h
+++ b/adb/bugreport.h
@@ -43,7 +43,7 @@
const char* name);
private:
- virtual void UpdateProgress(const std::string& file_name, int progress, int total);
+ virtual void UpdateProgress(const std::string& file_name, int progress_percentage);
LinePrinter line_printer_;
DISALLOW_COPY_AND_ASSIGN(Bugreport);
};
diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp
index b500c49..2b368d7 100644
--- a/adb/bugreport_test.cpp
+++ b/adb/bugreport_test.cpp
@@ -123,7 +123,7 @@
bool disable_shell_protocol, StandardStreamsCallbackInterface* callback));
MOCK_METHOD4(DoSyncPull, bool(const std::vector<const char*>& srcs, const char* dst,
bool copy_attrs, const char* name));
- MOCK_METHOD3(UpdateProgress, void(const std::string&, int, int));
+ MOCK_METHOD2(UpdateProgress, void(const std::string&, int));
};
class BugreportTest : public ::testing::Test {
@@ -142,8 +142,8 @@
WithArg<4>(ReturnCallbackDone(0))));
}
- void ExpectProgress(int progress, int total, const std::string& file = "file.zip") {
- EXPECT_CALL(br_, UpdateProgress(StrEq("generating " + file), progress, total));
+ void ExpectProgress(int progress_percentage, const std::string& file = "file.zip") {
+ EXPECT_CALL(br_, UpdateProgress(StrEq("generating " + file), progress_percentage));
}
BugreportMock br_;
@@ -200,7 +200,7 @@
ExpectBugreportzVersion("1.1");
std::string dest_file =
android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
- ExpectProgress(50, 100, "da_bugreport.zip");
+ ExpectProgress(50, "da_bugreport.zip");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")),
@@ -247,10 +247,10 @@
// Tests 'adb bugreport file.zip' when it succeeds and displays progress.
TEST_F(BugreportTest, OkProgress) {
ExpectBugreportzVersion("1.1");
- ExpectProgress(1, 100);
- ExpectProgress(10, 100);
- ExpectProgress(50, 100);
- ExpectProgress(99, 100);
+ ExpectProgress(1);
+ ExpectProgress(10);
+ ExpectProgress(50);
+ ExpectProgress(99);
// clang-format off
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
// NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
@@ -283,21 +283,23 @@
// Tests 'adb bugreport file.zip' when it succeeds and displays progress, even if progress recedes.
TEST_F(BugreportTest, OkProgressAlwaysForward) {
ExpectBugreportzVersion("1.1");
- ExpectProgress(1, 100);
- ExpectProgress(50, 100);
- ExpectProgress(75, 100);
+ ExpectProgress(1);
+ ExpectProgress(50);
+ ExpectProgress(75);
// clang-format off
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
// NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
.WillOnce(DoAll(
WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
- WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")),
- WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")),
- // 25 should be ignored becaused it receded.
- WithArg<4>(WriteOnStdout("PROGRESS:25/100\n")),
- WithArg<4>(WriteOnStdout("PROGRESS:75/100\n")),
- // 75 should be ignored becaused it didn't change.
- WithArg<4>(WriteOnStdout("PROGRESS:75/100\n")),
+ WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
+ WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")), // 50%
+ // 25% should be ignored becaused it receded.
+ WithArg<4>(WriteOnStdout("PROGRESS:25/100\n")), // 25%
+ WithArg<4>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
+ // 75% should be ignored becaused it didn't change.
+ WithArg<4>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
+ // Try a receeding percentage with a different max progress
+ WithArg<4>(WriteOnStdout("PROGRESS:700/1000\n")), // 70%
WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
// clang-format on
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 606203c..fe5099c 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -156,33 +156,38 @@
}
#endif
- // Inform our parent that we are up and running.
+ // Wait for the USB scan to complete before notifying the parent that we're up.
+ // We need to perform this in a thread, because we would otherwise block the event loop.
+ std::thread notify_thread([ack_reply_fd]() {
+ adb_wait_for_device_initialization();
- // Any error output written to stderr now goes to adb.log. We could
- // keep around a copy of the stderr fd and use that to write any errors
- // encountered by the following code, but that is probably overkill.
+ // Any error output written to stderr now goes to adb.log. We could
+ // keep around a copy of the stderr fd and use that to write any errors
+ // encountered by the following code, but that is probably overkill.
#if defined(_WIN32)
- const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd);
- const CHAR ack[] = "OK\n";
- const DWORD bytes_to_write = arraysize(ack) - 1;
- DWORD written = 0;
- if (!WriteFile(ack_reply_handle, ack, bytes_to_write, &written, NULL)) {
- fatal("adb: cannot write ACK to handle 0x%p: %s", ack_reply_handle,
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- }
- if (written != bytes_to_write) {
- fatal("adb: cannot write %lu bytes of ACK: only wrote %lu bytes",
- bytes_to_write, written);
- }
- CloseHandle(ack_reply_handle);
+ const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd);
+ const CHAR ack[] = "OK\n";
+ const DWORD bytes_to_write = arraysize(ack) - 1;
+ DWORD written = 0;
+ if (!WriteFile(ack_reply_handle, ack, bytes_to_write, &written, NULL)) {
+ fatal("adb: cannot write ACK to handle 0x%p: %s", ack_reply_handle,
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ }
+ if (written != bytes_to_write) {
+ fatal("adb: cannot write %lu bytes of ACK: only wrote %lu bytes", bytes_to_write,
+ written);
+ }
+ CloseHandle(ack_reply_handle);
#else
- // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
- // "OKAY".
- if (!android::base::WriteStringToFd("OK\n", ack_reply_fd)) {
- fatal_errno("error writing ACK to fd %d", ack_reply_fd);
- }
- unix_close(ack_reply_fd);
+ // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
+ // "OKAY".
+ if (!android::base::WriteStringToFd("OK\n", ack_reply_fd)) {
+ fatal_errno("error writing ACK to fd %d", ack_reply_fd);
+ }
+ unix_close(ack_reply_fd);
#endif
+ });
+ notify_thread.detach();
}
D("Event loop starting");
diff --git a/adb/client/usb_dispatch.cpp b/adb/client/usb_dispatch.cpp
index bfc8e16..710a3ce 100644
--- a/adb/client/usb_dispatch.cpp
+++ b/adb/client/usb_dispatch.cpp
@@ -48,3 +48,9 @@
should_use_libusb() ? libusb::usb_kick(reinterpret_cast<libusb::usb_handle*>(h))
: native::usb_kick(reinterpret_cast<native::usb_handle*>(h));
}
+
+size_t usb_get_max_packet_size(usb_handle* h) {
+ return should_use_libusb()
+ ? libusb::usb_get_max_packet_size(reinterpret_cast<libusb::usb_handle*>(h))
+ : native::usb_get_max_packet_size(reinterpret_cast<native::usb_handle*>(h));
+}
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index fec4742..15d4b7a 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -91,7 +91,7 @@
struct usb_handle : public ::usb_handle {
usb_handle(const std::string& device_address, const std::string& serial,
unique_device_handle&& device_handle, uint8_t interface, uint8_t bulk_in,
- uint8_t bulk_out, size_t zero_mask)
+ uint8_t bulk_out, size_t zero_mask, size_t max_packet_size)
: device_address(device_address),
serial(serial),
closing(false),
@@ -100,7 +100,8 @@
write("write", zero_mask, true),
interface(interface),
bulk_in(bulk_in),
- bulk_out(bulk_out) {}
+ bulk_out(bulk_out),
+ max_packet_size(max_packet_size) {}
~usb_handle() {
Close();
@@ -143,6 +144,8 @@
uint8_t interface;
uint8_t bulk_in;
uint8_t bulk_out;
+
+ size_t max_packet_size;
};
static auto& usb_handles = *new std::unordered_map<std::string, std::unique_ptr<usb_handle>>();
@@ -156,6 +159,22 @@
libusb_get_device_address(device));
}
+#if defined(__linux__)
+static std::string get_device_serial_path(libusb_device* device) {
+ uint8_t ports[7];
+ int port_count = libusb_get_port_numbers(device, ports, 7);
+ if (port_count < 0) return "";
+
+ std::string path =
+ StringPrintf("/sys/bus/usb/devices/%d-%d", libusb_get_bus_number(device), ports[0]);
+ for (int port = 1; port < port_count; ++port) {
+ path += StringPrintf(".%d", ports[port]);
+ }
+ path += "/serial";
+ return path;
+}
+#endif
+
static bool endpoint_is_output(uint8_t endpoint) {
return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT;
}
@@ -165,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");
@@ -174,172 +382,13 @@
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;
- 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;
- }
- }
-
- 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;
- }
- }
-
- libusb_device_handle* handle_raw;
- rc = libusb_open(list[i], &handle_raw);
- if (rc != 0) {
- LOG(WARNING) << "failed to open usb device at " << device_address << ": "
- << libusb_error_name(rc);
- continue;
- }
-
- unique_device_handle handle(handle_raw);
- 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;
- }
- }
-
- auto result =
- std::make_unique<usb_handle>(device_address, device_serial, std::move(handle),
- interface_num, bulk_in, bulk_out, zero_mask);
- 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(), 1);
-
- LOG(INFO) << "registered new usb device '" << device_serial << "'";
+ process_device(list[i]);
}
+
libusb_free_device_list(list, 1);
+ adb_notify_device_scan_complete();
+
std::this_thread::sleep_for(500ms);
}
}
@@ -507,4 +556,10 @@
void usb_kick(usb_handle* h) {
h->Close();
}
+
+size_t usb_get_max_packet_size(usb_handle* h) {
+ CHECK(h->max_packet_size != 0);
+ return h->max_packet_size;
+}
+
} // namespace libusb
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index 6efed27..f9ba7cb 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -65,6 +65,7 @@
unsigned char ep_in;
unsigned char ep_out;
+ size_t max_packet_size;
unsigned zero_mask;
unsigned writeable = 1;
@@ -120,9 +121,9 @@
}
static void find_usb_device(const std::string& base,
- void (*register_device_callback)
- (const char*, const char*, unsigned char, unsigned char, int, int, unsigned))
-{
+ void (*register_device_callback)(const char*, const char*,
+ unsigned char, unsigned char, int, int,
+ unsigned, size_t)) {
std::unique_ptr<DIR, int(*)(DIR*)> bus_dir(opendir(base.c_str()), closedir);
if (!bus_dir) return;
@@ -144,6 +145,7 @@
struct usb_interface_descriptor* interface;
struct usb_endpoint_descriptor *ep1, *ep2;
unsigned zero_mask = 0;
+ size_t max_packet_size = 0;
unsigned vid, pid;
if (contains_non_digit(de->d_name)) continue;
@@ -251,7 +253,8 @@
continue;
}
/* aproto 01 needs 0 termination */
- if(interface->bInterfaceProtocol == 0x01) {
+ if (interface->bInterfaceProtocol == 0x01) {
+ max_packet_size = ep1->wMaxPacketSize;
zero_mask = ep1->wMaxPacketSize - 1;
}
@@ -281,9 +284,9 @@
}
}
- register_device_callback(dev_name.c_str(), devpath,
- local_ep_in, local_ep_out,
- interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
+ register_device_callback(dev_name.c_str(), devpath, local_ep_in,
+ local_ep_out, interface->bInterfaceNumber,
+ device->iSerialNumber, zero_mask, max_packet_size);
break;
}
} else {
@@ -497,10 +500,13 @@
return 0;
}
-static void register_device(const char* dev_name, const char* dev_path,
- unsigned char ep_in, unsigned char ep_out,
- int interface, int serial_index,
- unsigned zero_mask) {
+size_t usb_get_max_packet_size(usb_handle* h) {
+ return h->max_packet_size;
+}
+
+static void register_device(const char* dev_name, const char* dev_path, unsigned char ep_in,
+ unsigned char ep_out, int interface, int serial_index,
+ unsigned zero_mask, size_t max_packet_size) {
// Since Linux will not reassign the device ID (and dev_name) as long as the
// device is open, we can add to the list here once we open it and remove
// from the list when we're finally closed and everything will work out
@@ -523,6 +529,7 @@
usb->ep_in = ep_in;
usb->ep_out = ep_out;
usb->zero_mask = zero_mask;
+ usb->max_packet_size = max_packet_size;
// Initialize mark so we don't get garbage collected after the device scan.
usb->mark = true;
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index fcd0bc0..e366754 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -38,6 +38,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
#include "adb.h"
#include "transport.h"
@@ -51,15 +52,21 @@
UInt8 bulkOut;
IOUSBInterfaceInterface190** interface;
unsigned int zero_mask;
+ size_t max_packet_size;
// For garbage collecting disconnected devices.
bool mark;
std::string devpath;
std::atomic<bool> dead;
- usb_handle() : bulkIn(0), bulkOut(0), interface(nullptr),
- zero_mask(0), mark(false), dead(false) {
- }
+ usb_handle()
+ : bulkIn(0),
+ bulkOut(0),
+ interface(nullptr),
+ zero_mask(0),
+ max_packet_size(0),
+ mark(false),
+ dead(false) {}
};
static std::atomic<bool> usb_inited_flag;
@@ -390,6 +397,7 @@
}
handle->zero_mask = maxPacketSize - 1;
+ handle->max_packet_size = maxPacketSize;
}
handle->interface = interface;
@@ -422,7 +430,7 @@
VLOG(USB) << "RunLoopThread done";
}
-static void usb_cleanup() {
+static void usb_cleanup() NO_THREAD_SAFETY_ANALYSIS {
VLOG(USB) << "usb_cleanup";
// Wait until usb operations in RunLoopThread finish, and prevent further operations.
operate_device_lock.lock();
@@ -558,4 +566,9 @@
std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
usb_kick_locked(handle);
}
+
+size_t usb_get_max_packet_size(usb_handle* handle) {
+ return handle->max_packet_size;
+}
+
} // namespace native
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index ee7f802..ec55b0e 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -65,6 +65,9 @@
/// Interface name
wchar_t* interface_name;
+ /// Maximum packet size.
+ unsigned max_packet_size;
+
/// Mask for determining when to use zero length packets
unsigned zero_mask;
};
@@ -522,6 +525,10 @@
return 0;
}
+size_t usb_get_max_packet_size(usb_handle* handle) {
+ return handle->max_packet_size;
+}
+
int recognized_device(usb_handle* handle) {
if (NULL == handle)
return 0;
@@ -557,6 +564,7 @@
AdbEndpointInformation endpoint_info;
// assuming zero is a valid bulk endpoint ID
if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
+ handle->max_packet_size = endpoint_info.max_packet_size;
handle->zero_mask = endpoint_info.max_packet_size - 1;
D("device zero_mask: 0x%x", handle->zero_mask);
} else {
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index b8f790d..a9b1540 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -761,55 +761,46 @@
return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command);
}
-static int adb_download_buffer(const char* service, const char* filename) {
- std::string content;
- if (!android::base::ReadFileToString(filename, &content)) {
- fprintf(stderr, "error: couldn't read %s: %s\n", filename, strerror(errno));
- return -1;
- }
-
- const uint8_t* data = reinterpret_cast<const uint8_t*>(content.data());
- unsigned sz = content.size();
-
+static int adb_sideload_legacy(const char* filename, int in_fd, int size) {
std::string error;
- int fd = adb_connect(android::base::StringPrintf("%s:%d", service, sz), &error);
- if (fd < 0) {
- fprintf(stderr,"error: %s\n", error.c_str());
+ int out_fd = adb_connect(android::base::StringPrintf("sideload:%d", size), &error);
+ if (out_fd < 0) {
+ fprintf(stderr, "adb: pre-KitKat sideload connection failed: %s\n", error.c_str());
return -1;
}
int opt = CHUNK_SIZE;
- opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+ opt = adb_setsockopt(out_fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
- unsigned total = sz;
- const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
-
- const char* x = strrchr(service, ':');
- if (x) service = x + 1;
-
- while (sz > 0) {
- unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
- if (!WriteFdExactly(fd, ptr, xfer)) {
- std::string error;
- adb_status(fd, &error);
- fprintf(stderr,"* failed to write data '%s' *\n", error.c_str());
- adb_close(fd);
+ char buf[CHUNK_SIZE];
+ int total = size;
+ while (size > 0) {
+ unsigned xfer = (size > CHUNK_SIZE) ? CHUNK_SIZE : size;
+ if (!ReadFdExactly(in_fd, buf, xfer)) {
+ fprintf(stderr, "adb: failed to read data from %s: %s\n", filename, strerror(errno));
+ adb_close(out_fd);
return -1;
}
- sz -= xfer;
- ptr += xfer;
- printf("sending: '%s' %4d%% \r", filename, (int)(100LL - ((100LL * sz) / (total))));
+ if (!WriteFdExactly(out_fd, buf, xfer)) {
+ std::string error;
+ adb_status(out_fd, &error);
+ fprintf(stderr, "adb: failed to write data: %s\n", error.c_str());
+ adb_close(out_fd);
+ return -1;
+ }
+ size -= xfer;
+ printf("sending: '%s' %4d%% \r", filename, (int)(100LL - ((100LL * size) / (total))));
fflush(stdout);
}
printf("\n");
- if (!adb_status(fd, &error)) {
- fprintf(stderr,"* error response '%s' *\n", error.c_str());
- adb_close(fd);
+ if (!adb_status(out_fd, &error)) {
+ fprintf(stderr, "adb: error response: %s\n", error.c_str());
+ adb_close(out_fd);
return -1;
}
- adb_close(fd);
+ adb_close(out_fd);
return 0;
}
@@ -836,22 +827,17 @@
*/
static int adb_sideload_host(const char* filename) {
// TODO: use a LinePrinter instead...
- fprintf(stdout, "opening '%s'...\n", filename);
- fflush(stdout);
-
struct stat sb;
if (stat(filename, &sb) == -1) {
- fprintf(stderr, "failed to stat file %s: %s\n", filename, strerror(errno));
+ fprintf(stderr, "adb: failed to stat file %s: %s\n", filename, strerror(errno));
return -1;
}
unique_fd package_fd(adb_open(filename, O_RDONLY));
if (package_fd == -1) {
- fprintf(stderr, "failed to open file %s: %s\n", filename, strerror(errno));
+ fprintf(stderr, "adb: failed to open file %s: %s\n", filename, strerror(errno));
return -1;
}
- fprintf(stdout, "connecting...\n");
- fflush(stdout);
std::string service = android::base::StringPrintf(
"sideload-host:%d:%d", static_cast<int>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
std::string error;
@@ -859,8 +845,9 @@
if (device_fd < 0) {
// Try falling back to the older (<= K) sideload method. Maybe this
// is an older device that doesn't support sideload-host.
- fprintf(stderr, "falling back to older sideload method...\n");
- return adb_download_buffer("sideload", filename);
+ fprintf(stderr, "adb: sideload connection failed: %s\n", error.c_str());
+ fprintf(stderr, "adb: trying pre-KitKat sideload method...\n");
+ return adb_sideload_legacy(filename, package_fd, static_cast<int>(sb.st_size));
}
int opt = SIDELOAD_HOST_BLOCK_SIZE;
@@ -872,7 +859,7 @@
int last_percent = -1;
while (true) {
if (!ReadFdExactly(device_fd, buf, 8)) {
- fprintf(stderr, "* failed to read command: %s\n", strerror(errno));
+ fprintf(stderr, "adb: failed to read command: %s\n", strerror(errno));
return -1;
}
buf[8] = '\0';
@@ -888,7 +875,7 @@
size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
if (offset >= static_cast<size_t>(sb.st_size)) {
- fprintf(stderr, "* attempt to read block %d past end\n", block);
+ fprintf(stderr, "adb: failed to read block %d past end\n", block);
return -1;
}
@@ -898,17 +885,17 @@
}
if (adb_lseek(package_fd, offset, SEEK_SET) != static_cast<int>(offset)) {
- fprintf(stderr, "* failed to seek to package block: %s\n", strerror(errno));
+ fprintf(stderr, "adb: failed to seek to package block: %s\n", strerror(errno));
return -1;
}
if (!ReadFdExactly(package_fd, buf, to_write)) {
- fprintf(stderr, "* failed to read package block: %s\n", strerror(errno));
+ fprintf(stderr, "adb: failed to read package block: %s\n", strerror(errno));
return -1;
}
if (!WriteFdExactly(device_fd, buf, to_write)) {
adb_status(device_fd, &error);
- fprintf(stderr,"* failed to write data '%s' *\n", error.c_str());
+ fprintf(stderr, "adb: failed to write data '%s' *\n", error.c_str());
return -1;
}
xfer += to_write;
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 7a87df4..a6d43ea 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -233,9 +233,8 @@
adb_device_banner = optarg;
break;
case 'v':
- printf("Android Debug Bridge Daemon version %d.%d.%d %s\n",
- ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION,
- ADB_REVISION);
+ printf("Android Debug Bridge Daemon version %d.%d.%d (%s)\n", ADB_VERSION_MAJOR,
+ ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_VERSION);
return 0;
default:
// getopt already prints "adbd: invalid option -- %c" for us.
diff --git a/adb/diagnose_usb.cpp b/adb/diagnose_usb.cpp
index 0f067b0..9f721bf 100644
--- a/adb/diagnose_usb.cpp
+++ b/adb/diagnose_usb.cpp
@@ -25,13 +25,14 @@
#if defined(__linux__)
#include <grp.h>
+#include <pwd.h>
#endif
static const char kPermissionsHelpUrl[] = "http://developer.android.com/tools/device.html";
-// Returns a message describing any potential problems we find with udev, or nullptr if we can't
-// find plugdev information (i.e. udev is not installed).
-static const char* GetUdevProblem() {
+// Returns a message describing any potential problems we find with udev, or an empty string if we
+// can't find plugdev information (i.e. udev is not installed).
+static std::string GetUdevProblem() {
#if defined(__linux__)
errno = 0;
group* plugdev_group = getgrnam("plugdev");
@@ -41,43 +42,45 @@
perror("failed to read plugdev group info");
}
// We can't give any generally useful advice here, just let the caller print the help URL.
- return nullptr;
+ return "";
}
- // getgroups(2) indicates that the group_member() may not check the egid so we check it
+ // getgroups(2) indicates that the GNU group_member(3) may not check the egid so we check it
// additionally just to be sure.
if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
// The user is in plugdev so the problem is likely with the udev rules.
- return "verify udev rules";
+ return "user in plugdev group; are your udev rules wrong?";
}
- return "udev requires plugdev group membership";
+ passwd* pwd = getpwuid(getuid());
+ return android::base::StringPrintf("user %s is not in the plugdev group",
+ pwd ? pwd->pw_name : "?");
#else
- return nullptr;
+ return "";
#endif
}
// Short help text must be a single line, and will look something like:
-// no permissions (reason); see <URL>
+//
+// no permissions (reason); see [URL]
std::string UsbNoPermissionsShortHelpText() {
std::string help_text = "no permissions";
- const char* problem = GetUdevProblem();
- if (problem != nullptr) {
- help_text += android::base::StringPrintf(" (%s)", problem);
- }
+ std::string problem(GetUdevProblem());
+ if (!problem.empty()) help_text += " (" + problem + ")";
return android::base::StringPrintf("%s; see [%s]", help_text.c_str(), kPermissionsHelpUrl);
}
-// Long help text can span multiple lines and should provide more detailed information.
+// Long help text can span multiple lines but doesn't currently provide more detailed information:
+//
+// insufficient permissions for device: reason
+// See [URL] for more information
std::string UsbNoPermissionsLongHelpText() {
std::string header = "insufficient permissions for device";
- const char* problem = GetUdevProblem();
- if (problem != nullptr) {
- header += android::base::StringPrintf(": %s", problem);
- }
+ std::string problem(GetUdevProblem());
+ if (!problem.empty()) header += ": " + problem;
- return android::base::StringPrintf("%s.\nSee [%s] for more information.",
- header.c_str(), kPermissionsHelpUrl);
+ return android::base::StringPrintf("%s\nSee [%s] for more information", header.c_str(),
+ kPermissionsHelpUrl);
}
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 72c9eef..b28de4b 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -26,15 +26,19 @@
#include <unistd.h>
#include <atomic>
+#include <functional>
#include <list>
+#include <mutex>
#include <unordered_map>
#include <vector>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
#include "adb_io.h"
#include "adb_trace.h"
+#include "adb_unique_fd.h"
#include "adb_utils.h"
#if !ADB_HOST
@@ -75,6 +79,10 @@
static bool main_thread_valid;
static unsigned long main_thread_id;
+static auto& run_queue_notify_fd = *new unique_fd();
+static auto& run_queue_mutex = *new std::mutex();
+static auto& run_queue GUARDED_BY(run_queue_mutex) = *new std::vector<std::function<void()>>();
+
void check_main_thread() {
if (main_thread_valid) {
CHECK_EQ(main_thread_id, adb_thread_id());
@@ -112,8 +120,7 @@
return android::base::StringPrintf("(fdevent %d %s)", fde->fd, state.c_str());
}
-fdevent *fdevent_create(int fd, fd_func func, void *arg)
-{
+fdevent* fdevent_create(int fd, fd_func func, void* arg) {
check_main_thread();
fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
if(fde == 0) return 0;
@@ -122,8 +129,7 @@
return fde;
}
-void fdevent_destroy(fdevent *fde)
-{
+void fdevent_destroy(fdevent* fde) {
check_main_thread();
if(fde == 0) return;
if(!(fde->state & FDE_CREATED)) {
@@ -278,8 +284,7 @@
}
}
-static void fdevent_call_fdfunc(fdevent* fde)
-{
+static void fdevent_call_fdfunc(fdevent* fde) {
unsigned events = fde->events;
fde->events = 0;
CHECK(fde->state & FDE_PENDING);
@@ -292,10 +297,7 @@
#include <sys/ioctl.h>
-static void fdevent_subproc_event_func(int fd, unsigned ev,
- void* /* userdata */)
-{
-
+static void fdevent_subproc_event_func(int fd, unsigned ev, void* /* userdata */) {
D("subproc handling on fd = %d, ev = %x", fd, ev);
CHECK_GE(fd, 0);
@@ -342,8 +344,7 @@
}
}
-void fdevent_subproc_setup()
-{
+static void fdevent_subproc_setup() {
int s[2];
if(adb_socketpair(s)) {
@@ -358,12 +359,63 @@
}
#endif // !ADB_HOST
-void fdevent_loop()
-{
+static void fdevent_run_flush() REQUIRES(run_queue_mutex) {
+ for (auto& f : run_queue) {
+ f();
+ }
+ run_queue.clear();
+}
+
+static void fdevent_run_func(int fd, unsigned ev, void* /* userdata */) {
+ CHECK_GE(fd, 0);
+ CHECK(ev & FDE_READ);
+
+ char buf[1024];
+
+ // Empty the fd.
+ if (adb_read(fd, buf, sizeof(buf)) == -1) {
+ PLOG(FATAL) << "failed to empty run queue notify fd";
+ }
+
+ std::lock_guard<std::mutex> lock(run_queue_mutex);
+ fdevent_run_flush();
+}
+
+static void fdevent_run_setup() {
+ std::lock_guard<std::mutex> lock(run_queue_mutex);
+ CHECK(run_queue_notify_fd.get() == -1);
+ int s[2];
+ if (adb_socketpair(s) != 0) {
+ PLOG(FATAL) << "failed to create run queue notify socketpair";
+ }
+
+ run_queue_notify_fd.reset(s[0]);
+ fdevent* fde = fdevent_create(s[1], fdevent_run_func, nullptr);
+ CHECK(fde != nullptr);
+ fdevent_add(fde, FDE_READ);
+
+ fdevent_run_flush();
+}
+
+void fdevent_run_on_main_thread(std::function<void()> fn) {
+ std::lock_guard<std::mutex> lock(run_queue_mutex);
+ run_queue.push_back(std::move(fn));
+
+ // run_queue_notify_fd could still be -1 if we're called before fdevent has finished setting up.
+ // In that case, rely on the setup code to flush the queue without a notification being needed.
+ if (run_queue_notify_fd != -1) {
+ if (adb_write(run_queue_notify_fd.get(), "", 1) != 1) {
+ PLOG(FATAL) << "failed to write to run queue notify fd";
+ }
+ }
+}
+
+void fdevent_loop() {
set_main_thread();
#if !ADB_HOST
fdevent_subproc_setup();
#endif // !ADB_HOST
+ fdevent_run_setup();
while (true) {
if (terminate_loop) {
@@ -393,6 +445,11 @@
void fdevent_reset() {
g_poll_node_map.clear();
g_pending_list.clear();
+
+ std::lock_guard<std::mutex> lock(run_queue_mutex);
+ run_queue_notify_fd.reset();
+ run_queue.clear();
+
main_thread_valid = false;
terminate_loop = false;
}
diff --git a/adb/fdevent.h b/adb/fdevent.h
index e32845a..896400a 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -20,6 +20,8 @@
#include <stddef.h>
#include <stdint.h> /* for int64_t */
+#include <functional>
+
/* events that may be observed */
#define FDE_READ 0x0001
#define FDE_WRITE 0x0002
@@ -78,6 +80,9 @@
void check_main_thread();
+// Queue an operation to run on the main thread.
+void fdevent_run_on_main_thread(std::function<void()> fn);
+
// The following functions are used only for tests.
void fdevent_terminate_loop();
size_t fdevent_installed_count();
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index bdb973a..86e0209 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -173,3 +173,24 @@
std::thread thread(InvalidFdThreadFunc);
thread.join();
}
+
+TEST_F(FdeventTest, run_on_main_thread) {
+ std::vector<int> vec;
+
+ PrepareThread();
+ std::thread thread(fdevent_loop);
+
+ for (int i = 0; i < 100; ++i) {
+ fdevent_run_on_main_thread([i, &vec]() {
+ check_main_thread();
+ vec.push_back(i);
+ });
+ }
+
+ TerminateThread(thread);
+
+ ASSERT_EQ(100u, vec.size());
+ for (int i = 0; i < 100; ++i) {
+ ASSERT_EQ(i, vec[i]);
+ }
+}
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index f4215ae..5ca49ac 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -53,11 +53,11 @@
size_t GetAdditionalLocalSocketCount() {
#if ADB_HOST
- // dummy socket installed in PrepareThread()
- return 1;
-#else
- // dummy socket and one more socket installed in fdevent_subproc_setup()
+ // dummy socket installed in PrepareThread() + fdevent_run_on_main_thread socket
return 2;
+#else
+ // dummy socket + fdevent_run_on_main_thread + fdevent_subproc_setup() sockets
+ return 3;
#endif
}
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index edb0fb3..fd19882 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -201,55 +201,6 @@
}
}
-TEST(sysdeps_mutex, mutex_smoke) {
- static std::atomic<bool> finished(false);
- static std::mutex &m = *new std::mutex();
- m.lock();
- ASSERT_FALSE(m.try_lock());
- std::thread thread([]() {
- ASSERT_FALSE(m.try_lock());
- m.lock();
- finished.store(true);
- std::this_thread::sleep_for(200ms);
- m.unlock();
- });
-
- ASSERT_FALSE(finished.load());
- std::this_thread::sleep_for(100ms);
- ASSERT_FALSE(finished.load());
- m.unlock();
- std::this_thread::sleep_for(100ms);
- m.lock();
- ASSERT_TRUE(finished.load());
- m.unlock();
-
- thread.join();
-}
-
-TEST(sysdeps_mutex, recursive_mutex_smoke) {
- static std::recursive_mutex &m = *new std::recursive_mutex();
-
- m.lock();
- ASSERT_TRUE(m.try_lock());
- m.unlock();
-
- std::thread thread([]() {
- ASSERT_FALSE(m.try_lock());
- m.lock();
- std::this_thread::sleep_for(500ms);
- m.unlock();
- });
-
- std::this_thread::sleep_for(100ms);
- m.unlock();
- std::this_thread::sleep_for(100ms);
- ASSERT_FALSE(m.try_lock());
- m.lock();
- m.unlock();
-
- thread.join();
-}
-
TEST(sysdeps_condition_variable, smoke) {
static std::mutex &m = *new std::mutex;
static std::condition_variable &cond = *new std::condition_variable;
diff --git a/adb/test_device.py b/adb/test_device.py
index a30972e..e44cc83 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -1259,6 +1259,26 @@
self.assertEqual(self._get_device_state(serialno), 'device')
+ def test_packet_size_regression(self):
+ """Test for http://b/37783561
+
+ Receiving packets of a length divisible by 512 but not 1024 resulted in
+ the adb client waiting indefinitely for more input.
+ """
+ # The values that trigger things are 507 (512 - 5 bytes from shell protocol) + 1024*n
+ # Probe some surrounding values as well, for the hell of it.
+ for length in [506, 507, 508, 1018, 1019, 1020, 1530, 1531, 1532]:
+ cmd = ['dd', 'if=/dev/zero', 'bs={}'.format(length), 'count=1', '2>/dev/null;'
+ 'echo', 'foo']
+ rc, stdout, _ = self.device.shell_nocheck(cmd)
+
+ self.assertEqual(0, rc)
+
+ # Output should be '\0' * length, followed by "foo\n"
+ self.assertEqual(length, len(stdout) - 4)
+ self.assertEqual(stdout, "\0" * length + "foo\n")
+
+
def main():
random.seed(0)
if len(adb.get_devices()) > 0:
diff --git a/adb/transport.cpp b/adb/transport.cpp
index cc8c162..20de642 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -400,8 +400,27 @@
return &tracker->socket;
}
+// Check if all of the USB transports are connected.
+bool iterate_transports(std::function<bool(const atransport*)> fn) {
+ std::lock_guard<std::mutex> lock(transport_lock);
+ for (const auto& t : transport_list) {
+ if (!fn(t)) {
+ return false;
+ }
+ }
+ for (const auto& t : pending_list) {
+ if (!fn(t)) {
+ return false;
+ }
+ }
+ return true;
+}
+
// Call this function each time the transport list has changed.
void update_transports() {
+ update_transport_status();
+
+ // Notify `adb track-devices` clients.
std::string transports = list_transports(false);
device_tracker* tracker = device_tracker_list;
diff --git a/adb/transport.h b/adb/transport.h
index 8c15d66..e129355 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -198,6 +198,10 @@
void kick_transport(atransport* t);
void update_transports(void);
+// Iterates across all of the current and pending transports.
+// Stops iteration and returns false if fn returns false, otherwise returns true.
+bool iterate_transports(std::function<bool(const atransport*)> fn);
+
void init_transport_registration(void);
void init_mdns_transport_discovery(void);
std::string list_transports(bool long_listing);
diff --git a/adb/transport_mdns.cpp b/adb/transport_mdns.cpp
index e49b1c6..3603f09 100644
--- a/adb/transport_mdns.cpp
+++ b/adb/transport_mdns.cpp
@@ -24,6 +24,8 @@
#include <arpa/inet.h>
#endif
+#include <thread>
+
#include <android-base/stringprintf.h>
#include <dns_sd.h>
@@ -262,19 +264,22 @@
}
}
-void init_mdns_transport_discovery(void) {
- DNSServiceErrorType errorCode =
- DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
- register_mdns_transport, nullptr);
+void init_mdns_transport_discovery_thread(void) {
+ DNSServiceErrorType errorCode = DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
+ register_mdns_transport, nullptr);
if (errorCode != kDNSServiceErr_NoError) {
D("Got %d initiating mDNS browse.", errorCode);
return;
}
- fdevent_install(&service_ref_fde,
- adb_DNSServiceRefSockFD(service_ref),
- pump_service_ref,
- &service_ref);
- fdevent_set(&service_ref_fde, FDE_READ);
+ fdevent_run_on_main_thread([]() {
+ fdevent_install(&service_ref_fde, adb_DNSServiceRefSockFD(service_ref), pump_service_ref,
+ &service_ref);
+ fdevent_set(&service_ref_fde, FDE_READ);
+ });
+}
+
+void init_mdns_transport_discovery(void) {
+ std::thread(init_mdns_transport_discovery_thread).detach();
}
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index ce419b8..885d723 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -27,57 +27,43 @@
#if ADB_HOST
-static constexpr size_t MAX_USB_BULK_PACKET_SIZE = 1024u;
-
-// Call usb_read using a buffer having a multiple of MAX_USB_BULK_PACKET_SIZE bytes
+// Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
// to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
static int UsbReadMessage(usb_handle* h, amessage* msg) {
D("UsbReadMessage");
- char buffer[MAX_USB_BULK_PACKET_SIZE];
- int n = usb_read(h, buffer, sizeof(buffer));
- if (n == sizeof(*msg)) {
- memcpy(msg, buffer, sizeof(*msg));
+
+ size_t usb_packet_size = usb_get_max_packet_size(h);
+ CHECK(usb_packet_size >= sizeof(*msg));
+ CHECK(usb_packet_size < 4096);
+
+ char buffer[4096];
+ int n = usb_read(h, buffer, usb_packet_size);
+ if (n != sizeof(*msg)) {
+ D("usb_read returned unexpected length %d (expected %zu)", n, sizeof(*msg));
+ return -1;
}
+ memcpy(msg, buffer, sizeof(*msg));
return n;
}
-// Call usb_read using a buffer having a multiple of MAX_USB_BULK_PACKET_SIZE bytes
+// Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
// to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
static int UsbReadPayload(usb_handle* h, apacket* p) {
- D("UsbReadPayload");
- size_t need_size = p->msg.data_length;
- size_t data_pos = 0u;
- while (need_size > 0u) {
- int n = 0;
- if (data_pos + MAX_USB_BULK_PACKET_SIZE <= sizeof(p->data)) {
- // Read directly to p->data.
- size_t rem_size = need_size % MAX_USB_BULK_PACKET_SIZE;
- size_t direct_read_size = need_size - rem_size;
- if (rem_size &&
- data_pos + direct_read_size + MAX_USB_BULK_PACKET_SIZE <= sizeof(p->data)) {
- direct_read_size += MAX_USB_BULK_PACKET_SIZE;
- }
- n = usb_read(h, &p->data[data_pos], direct_read_size);
- if (n < 0) {
- D("usb_read(size %zu) failed", direct_read_size);
- return n;
- }
- } else {
- // Read indirectly using a buffer.
- char buffer[MAX_USB_BULK_PACKET_SIZE];
- n = usb_read(h, buffer, sizeof(buffer));
- if (n < 0) {
- D("usb_read(size %zu) failed", sizeof(buffer));
- return -1;
- }
- size_t copy_size = std::min(static_cast<size_t>(n), need_size);
- D("usb read %d bytes, need %zu bytes, copy %zu bytes", n, need_size, copy_size);
- memcpy(&p->data[data_pos], buffer, copy_size);
- }
- data_pos += n;
- need_size -= std::min(static_cast<size_t>(n), need_size);
+ D("UsbReadPayload(%d)", p->msg.data_length);
+
+ size_t usb_packet_size = usb_get_max_packet_size(h);
+ CHECK(sizeof(p->data) % usb_packet_size == 0);
+
+ // Round the data length up to the nearest packet size boundary.
+ // The device won't send a zero packet for packet size aligned payloads,
+ // so don't read any more packets than needed.
+ size_t len = p->msg.data_length;
+ size_t rem_size = len % usb_packet_size;
+ if (rem_size) {
+ len += usb_packet_size - rem_size;
}
- return static_cast<int>(data_pos);
+ CHECK(len <= sizeof(p->data));
+ return usb_read(h, &p->data, len);
}
static int remote_read(apacket* p, atransport* t) {
diff --git a/adb/usb.h b/adb/usb.h
index ba70de4..e867ec8 100644
--- a/adb/usb.h
+++ b/adb/usb.h
@@ -16,6 +16,8 @@
#pragma once
+#include <sys/types.h>
+
// USB host/client interface.
#define ADB_USB_INTERFACE(handle_ref_type) \
@@ -23,7 +25,8 @@
int usb_write(handle_ref_type h, const void* data, int len); \
int usb_read(handle_ref_type h, void* data, int len); \
int usb_close(handle_ref_type h); \
- void usb_kick(handle_ref_type h)
+ void usb_kick(handle_ref_type h); \
+ size_t usb_get_max_packet_size(handle_ref_type)
#if defined(_WIN32) || !ADB_HOST
// Windows and the daemon have a single implementation.
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 4783d6e..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",
@@ -9,10 +8,6 @@
"-Os",
],
- // util.cpp gets async signal safe logging via libc_logging,
- // which defines its interface in bionic private headers.
- include_dirs: ["bionic/libc"],
-
local_include_dirs: ["include"],
}
@@ -26,7 +21,7 @@
],
whole_static_libs: [
- "libc_logging",
+ "libasync_safe",
"libcutils",
"libbase",
],
@@ -39,7 +34,7 @@
srcs: ["handler/debuggerd_handler.cpp"],
whole_static_libs: [
- "libc_logging",
+ "libasync_safe",
"libdebuggerd",
],
@@ -70,6 +65,7 @@
whole_static_libs: [
"libdebuggerd_handler_core",
"libtombstoned_client",
+ "libasync_safe",
"libbase",
"libdebuggerd",
"libbacktrace",
@@ -166,6 +162,7 @@
"tombstoned_client.cpp",
"util.cpp"
],
+ static_libs: ["libasync_safe"],
},
},
@@ -178,7 +175,6 @@
static_libs: [
"libdebuggerd",
- "libc_logging",
],
local_include_dirs: [
@@ -225,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_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 5c6c59c..47c98d1 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -39,6 +39,7 @@
#include <android-base/file.h>
#include <android-base/unique_fd.h>
+#include <async_safe/log.h>
#include "debuggerd/handler.h"
#include "debuggerd/tombstoned.h"
@@ -47,8 +48,6 @@
#include "backtrace.h"
#include "tombstone.h"
-#include "private/libc_logging.h"
-
using android::base::unique_fd;
extern "C" void __linker_enable_fallback_allocator();
@@ -81,7 +80,7 @@
DIR* dir = opendir(buf);
if (!dir) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to open %s: %s", buf, strerror(errno));
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open %s: %s", buf, strerror(errno));
return;
}
@@ -145,7 +144,8 @@
static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER;
int ret = pthread_mutex_trylock(&trace_mutex);
if (ret != 0) {
- __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_try_lock failed: %s", strerror(ret));
+ async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_try_lock failed: %s",
+ strerror(ret));
return;
}
@@ -167,7 +167,8 @@
// receiving our signal.
unique_fd pipe_read, pipe_write;
if (!Pipe(&pipe_read, &pipe_write)) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s", strerror(errno));
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s",
+ strerror(errno));
return false;
}
@@ -180,8 +181,8 @@
siginfo.si_uid = getuid();
if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, DEBUGGER_SIGNAL, &siginfo) != 0) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s", tid,
- strerror(errno));
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s",
+ tid, strerror(errno));
return false;
}
@@ -209,7 +210,7 @@
static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
int ret = pthread_mutex_lock(&crash_mutex);
if (ret != 0) {
- __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
+ async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
return;
}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index b70554f..8fd6e11 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -48,8 +48,7 @@
#include <sys/wait.h>
#include <unistd.h>
-#include "private/bionic_futex.h"
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
// see man(2) prctl, specifically the section about PR_GET_NAME
#define MAX_TASK_NAME_LEN (16)
@@ -62,6 +61,20 @@
#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);
+}
+
class ErrnoRestorer {
public:
ErrnoRestorer() : saved_errno_(errno) {
@@ -82,11 +95,12 @@
// Mutex to ensure only one crashing thread dumps itself.
static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
-// Don't use __libc_fatal because it exits via abort, which might put us back into a signal handler.
+// Don't use async_safe_fatal because it exits via abort, which might put us back into
+// a signal handler.
static void __noreturn __printflike(1, 2) fatal(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
- __libc_format_log_va_list(ANDROID_LOG_FATAL, "libc", fmt, args);
+ async_safe_format_log_va_list(ANDROID_LOG_FATAL, "libc", fmt, args);
_exit(1);
}
@@ -96,7 +110,7 @@
va_start(args, fmt);
char buf[4096];
- __libc_format_buffer_va_list(buf, sizeof(buf), fmt, args);
+ async_safe_format_buffer_va_list(buf, sizeof(buf), fmt, args);
fatal("%s: %s", buf, strerror(err));
}
@@ -120,8 +134,8 @@
}
if (signum == DEBUGGER_SIGNAL) {
- __libc_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", gettid(),
- thread_name);
+ async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", __gettid(),
+ thread_name);
return;
}
@@ -166,14 +180,14 @@
char addr_desc[32]; // ", fault addr 0x1234"
addr_desc[0] = code_desc[0] = 0;
if (info != nullptr) {
- __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
+ async_safe_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
if (has_address) {
- __libc_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
+ async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
}
}
- __libc_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);
+ 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);
}
/*
@@ -182,8 +196,8 @@
static bool have_siginfo(int signum) {
struct sigaction old_action;
if (sigaction(signum, nullptr, &old_action) < 0) {
- __libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
- strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
+ strerror(errno));
return false;
}
return (old_action.sa_flags & SA_SIGINFO) != 0;
@@ -207,7 +221,7 @@
capdata[1].inheritable = capdata[1].permitted;
if (capset(&capheader, &capdata[0]) == -1) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc", "capset failed: %s", strerror(errno));
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "capset failed: %s", strerror(errno));
}
}
@@ -217,8 +231,8 @@
for (unsigned long i = 0; i < 64; ++i) {
if (capmask & (1ULL << i)) {
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) != 0) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to raise ambient capability %lu: %s",
- i, strerror(errno));
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "failed to raise ambient capability %lu: %s", i, strerror(errno));
}
}
}
@@ -260,8 +274,8 @@
// Don't use fork(2) to avoid calling pthread_atfork handlers.
int forkpid = clone(nullptr, nullptr, 0, nullptr);
if (forkpid == -1) {
- __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to fork in debuggerd signal handler: %s",
- strerror(errno));
+ async_safe_format_log(ANDROID_LOG_FATAL, "libc",
+ "failed to fork in debuggerd signal handler: %s", strerror(errno));
} else if (forkpid == 0) {
TEMP_FAILURE_RETRY(dup2(pipefds[1], STDOUT_FILENO));
close(pipefds[0]);
@@ -271,8 +285,9 @@
char main_tid[10];
char pseudothread_tid[10];
- __libc_format_buffer(main_tid, sizeof(main_tid), "%d", thread_info->crashing_tid);
- __libc_format_buffer(pseudothread_tid, sizeof(pseudothread_tid), "%d", thread_info->pseudothread_tid);
+ async_safe_format_buffer(main_tid, sizeof(main_tid), "%d", thread_info->crashing_tid);
+ async_safe_format_buffer(pseudothread_tid, sizeof(pseudothread_tid), "%d",
+ thread_info->pseudothread_tid);
execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, nullptr);
@@ -282,15 +297,16 @@
char buf[4];
ssize_t rc = TEMP_FAILURE_RETRY(read(pipefds[0], &buf, sizeof(buf)));
if (rc == -1) {
- __libc_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s", strerror(errno));
+ async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s",
+ strerror(errno));
} else if (rc == 0) {
- __libc_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper failed to exec");
+ async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper failed to exec");
} else if (rc != 1) {
- __libc_format_log(ANDROID_LOG_FATAL, "libc",
- "read of IPC pipe returned unexpected value: %zd", rc);
+ async_safe_format_log(ANDROID_LOG_FATAL, "libc",
+ "read of IPC pipe returned unexpected value: %zd", rc);
} else {
if (buf[0] != '\1') {
- __libc_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure");
+ async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure");
} else {
thread_info->crash_dump_started = true;
}
@@ -300,10 +316,10 @@
// Don't leave a zombie child.
int status;
if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0)) == -1) {
- __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
- strerror(errno));
+ async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
+ strerror(errno));
} else if (WIFSTOPPED(status) || WIFSIGNALED(status)) {
- __libc_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped");
+ async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped");
thread_info->crash_dump_started = false;
}
}
@@ -331,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");
}
@@ -356,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) {
@@ -383,7 +399,7 @@
// Only allow one thread to handle a signal at a time.
int ret = pthread_mutex_lock(&crash_mutex);
if (ret != 0) {
- __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
+ async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
return;
}
@@ -398,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
};
@@ -419,10 +435,10 @@
}
// Wait for the child to start...
- __futex_wait(&thread_info.pseudothread_tid, -1, nullptr);
+ futex_wait(&thread_info.pseudothread_tid, -1);
// and then wait for it to finish.
- __futex_wait(&thread_info.pseudothread_tid, child_pid, nullptr);
+ futex_wait(&thread_info.pseudothread_tid, child_pid);
// Restore PR_SET_DUMPABLE to its original value.
if (prctl(PR_SET_DUMPABLE, orig_dumpable) != 0) {
diff --git a/debuggerd/tombstoned_client.cpp b/debuggerd/tombstoned_client.cpp
index 03b4a20..4741fa6 100644
--- a/debuggerd/tombstoned_client.cpp
+++ b/debuggerd/tombstoned_client.cpp
@@ -22,11 +22,11 @@
#include <utility>
#include <android-base/unique_fd.h>
+#include <async_safe/log.h>
#include <cutils/sockets.h>
#include "debuggerd/protocol.h"
#include "debuggerd/util.h"
-#include "private/libc_logging.h"
using android::base::unique_fd;
@@ -34,8 +34,8 @@
unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
if (sockfd == -1) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to connect to tombstoned: %s",
- strerror(errno));
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to connect to tombstoned: %s",
+ strerror(errno));
return false;
}
@@ -43,22 +43,22 @@
packet.packet_type = CrashPacketType::kDumpRequest;
packet.packet.dump_request.pid = pid;
if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to write DumpRequest packet: %s",
- strerror(errno));
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to write DumpRequest packet: %s",
+ strerror(errno));
return false;
}
unique_fd tmp_output_fd;
ssize_t rc = recv_fd(sockfd, &packet, sizeof(packet), &tmp_output_fd);
if (rc == -1) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc",
- "failed to read response to DumpRequest packet: %s", strerror(errno));
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "failed to read response to DumpRequest packet: %s", strerror(errno));
return false;
} else if (rc != sizeof(packet)) {
- __libc_format_log(
- ANDROID_LOG_ERROR, "libc",
- "received DumpRequest response packet of incorrect length (expected %zu, got %zd)",
- sizeof(packet), rc);
+ async_safe_format_log(
+ ANDROID_LOG_ERROR, "libc",
+ "received DumpRequest response packet of incorrect length (expected %zu, got %zd)",
+ sizeof(packet), rc);
return false;
}
@@ -67,8 +67,8 @@
// a regular fd, and writing to an fd with O_APPEND).
int flags = fcntl(tmp_output_fd.get(), F_GETFL);
if (fcntl(tmp_output_fd.get(), F_SETFL, flags | O_APPEND) != 0) {
- __libc_format_log(ANDROID_LOG_WARN, "libc", "failed to set output fd flags: %s",
- strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN, "libc", "failed to set output fd flags: %s",
+ strerror(errno));
}
*tombstoned_socket = std::move(sockfd);
diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp
index 4c015d7..32d2f18 100644
--- a/debuggerd/util.cpp
+++ b/debuggerd/util.cpp
@@ -24,8 +24,6 @@
#include <cutils/sockets.h>
#include <debuggerd/protocol.h>
-#include "private/libc_logging.h"
-
using android::base::unique_fd;
ssize_t send_fd(int sockfd, const void* data, size_t len, unique_fd fd) {
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 2c578a9..4d54175 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -14,10 +14,12 @@
LOCAL_PATH:= $(call my-dir)
-fastboot_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
+include $(LOCAL_PATH)/../platform_tools_tool_version.mk
include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DFASTBOOT_VERSION=\"$(tool_version)\"
+
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../adb \
$(LOCAL_PATH)/../mkbootimg \
@@ -39,8 +41,6 @@
LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
-
LOCAL_SRC_FILES_linux := usb_linux.cpp
LOCAL_STATIC_LIBRARIES_linux := libselinux
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 56ee816..7e10cc9 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -258,6 +258,12 @@
return cb_check(a, status, resp, 1);
}
+static char* xstrdup(const char* s) {
+ char* result = strdup(s);
+ if (!result) die("out of memory");
+ return result;
+}
+
void fb_queue_require(const char *prod, const char *var,
bool invert, size_t nvalues, const char **value)
{
@@ -276,16 +282,14 @@
fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
return status;
}
- fprintf(stderr, "%s: %s\n", (char*) a->data, resp);
+ fprintf(stderr, "%s: %s\n", static_cast<const char*>(a->data), resp);
+ free(static_cast<char*>(a->data));
return 0;
}
-void fb_queue_display(const char *var, const char *prettyname)
-{
- Action *a;
- a = queue_action(OP_QUERY, "getvar:%s", var);
- a->data = strdup(prettyname);
- if (a->data == nullptr) die("out of memory");
+void fb_queue_display(const char* var, const char* prettyname) {
+ Action* a = queue_action(OP_QUERY, "getvar:%s", var);
+ a->data = xstrdup(prettyname);
a->func = cb_display;
}
@@ -298,11 +302,9 @@
return 0;
}
-void fb_queue_query_save(const char *var, char *dest, uint32_t dest_size)
-{
- Action *a;
- a = queue_action(OP_QUERY, "getvar:%s", var);
- a->data = (void *)dest;
+void fb_queue_query_save(const char* var, char* dest, uint32_t dest_size) {
+ Action* a = queue_action(OP_QUERY, "getvar:%s", var);
+ a->data = dest;
a->size = dest_size;
a->func = cb_save;
}
@@ -342,15 +344,13 @@
a->msg = mkmsg("sending '%s' (%d KB)", name, sz / 1024);
}
-void fb_queue_upload(char *outfile)
-{
- Action *a = queue_action(OP_UPLOAD, "");
- a->data = outfile;
+void fb_queue_upload(const char* outfile) {
+ Action* a = queue_action(OP_UPLOAD, "");
+ a->data = xstrdup(outfile);
a->msg = mkmsg("uploading '%s'", outfile);
}
-void fb_queue_notice(const char *notice)
-{
+void fb_queue_notice(const char* notice) {
Action *a = queue_action(OP_NOTICE, "");
a->data = (void*) notice;
}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 982545c..f10b9ce 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -26,8 +26,6 @@
* SUCH DAMAGE.
*/
-#define _LARGEFILE64_SOURCE
-
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -77,7 +75,6 @@
char cur_product[FB_RESPONSE_SZ + 1];
static const char* serial = nullptr;
-static const char* product = nullptr;
static const char* cmdline = nullptr;
static unsigned short vendor_id = 0;
static int long_listing = 0;
@@ -110,63 +107,46 @@
};
static struct {
- char img_name[17];
- char sig_name[17];
- char part_name[9];
+ const char* nickname;
+ const char* img_name;
+ const char* sig_name;
+ const char* part_name;
bool is_optional;
bool is_secondary;
} images[] = {
- {"boot.img", "boot.sig", "boot", false, false},
- {"boot_other.img", "boot.sig", "boot", true, true},
- {"recovery.img", "recovery.sig", "recovery", true, false},
- {"system.img", "system.sig", "system", false, false},
- {"system_other.img", "system.sig", "system", true, true},
- {"vendor.img", "vendor.sig", "vendor", true, false},
- {"vendor_other.img", "vendor.sig", "vendor", true, true},
- {"vbmeta.img", "vbmeta.sig", "vbmeta", true, false},
+ // clang-format off
+ { "boot", "boot.img", "boot.sig", "boot", false, false },
+ { nullptr, "boot_other.img", "boot.sig", "boot", true, true },
+ { "dtbo", "dtbo.img", "dtbo.sig", "dtbo", true, false },
+ { "recovery", "recovery.img", "recovery.sig", "recovery", true, false },
+ { "system", "system.img", "system.sig", "system", false, false },
+ { nullptr, "system_other.img", "system.sig", "system", true, true },
+ { "vbmeta", "vbmeta.img", "vbmeta.sig", "vbmeta", true, false },
+ { "vendor", "vendor.img", "vendor.sig", "vendor", true, false },
+ { nullptr, "vendor_other.img", "vendor.sig", "vendor", true, true },
+ // clang-format on
};
-static std::string find_item_given_name(const char* img_name, const char* product) {
- if(product) {
- std::string path = android::base::GetExecutablePath();
- path.erase(path.find_last_of('/'));
- return android::base::StringPrintf("%s/../../../target/product/%s/%s",
- path.c_str(), product, img_name);
- }
-
- char *dir = getenv("ANDROID_PRODUCT_OUT");
+static std::string find_item_given_name(const char* img_name) {
+ char* dir = getenv("ANDROID_PRODUCT_OUT");
if (dir == nullptr || dir[0] == '\0') {
- die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
+ die("ANDROID_PRODUCT_OUT not set");
}
-
return android::base::StringPrintf("%s/%s", dir, img_name);
}
-std::string find_item(const char* item, const char* product) {
- const char *fn;
-
- if (!strcmp(item,"boot")) {
- fn = "boot.img";
- } else if(!strcmp(item,"recovery")) {
- fn = "recovery.img";
- } else if(!strcmp(item,"system")) {
- fn = "system.img";
- } else if(!strcmp(item,"vendor")) {
- fn = "vendor.img";
- } else if(!strcmp(item,"vbmeta")) {
- fn = "vbmeta.img";
- } else if(!strcmp(item,"userdata")) {
- fn = "userdata.img";
- } else if(!strcmp(item,"cache")) {
- fn = "cache.img";
- } else if(!strcmp(item,"info")) {
- fn = "android-info.txt";
- } else {
- fprintf(stderr,"unknown partition '%s'\n", item);
- return "";
+std::string find_item(const std::string& item) {
+ for (size_t i = 0; i < arraysize(images); ++i) {
+ if (images[i].nickname && item == images[i].nickname) {
+ return find_item_given_name(images[i].img_name);
+ }
}
- return find_item_given_name(fn, product);
+ 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.c_str());
+ return "";
}
static int64_t get_file_size(int fd) {
@@ -325,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"
@@ -364,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"
@@ -390,7 +383,6 @@
" For ethernet, provide an address in the\n"
" form <protocol>:<hostname>[:port] where\n"
" <protocol> is either tcp or udp.\n"
- " -p <product> Specify product name.\n"
" -c <cmdline> Override kernel commandline.\n"
" -i <vendor id> Specify a custom USB vendor id.\n"
" -b, --base <base_addr> Specify a custom kernel base\n"
@@ -434,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;
@@ -466,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");
@@ -490,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;
@@ -626,7 +601,7 @@
}
}
-static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
+static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
unique_fd fd(make_temporary_fd());
if (fd == -1) {
fprintf(stderr, "failed to create temporary file for '%s': %s\n",
@@ -1080,9 +1055,9 @@
flash_buf(pname, &buf);
}
-static void do_update_signature(ZipArchiveHandle zip, char* fn) {
+static void do_update_signature(ZipArchiveHandle zip, const char* filename) {
int64_t sz;
- void* data = unzip_file(zip, fn, &sz);
+ void* data = unzip_file(zip, filename, &sz);
if (data == nullptr) return;
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
@@ -1209,7 +1184,7 @@
fb_queue_query_save("product", cur_product, sizeof(cur_product));
- fname = find_item("info", product);
+ fname = find_item_given_name("android-info.txt");
if (fname.empty()) die("cannot find android-info.txt");
int64_t sz;
@@ -1241,7 +1216,7 @@
slot = slot_override.c_str();
}
if (!slot) continue;
- fname = find_item_given_name(images[i].img_name, product);
+ fname = find_item_given_name(images[i].img_name);
fastboot_buffer buf;
if (!load_buf(transport, fname.c_str(), &buf)) {
if (images[i].is_optional) continue;
@@ -1265,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)
@@ -1375,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;
@@ -1396,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;
}
@@ -1408,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;
}
@@ -1508,7 +1477,7 @@
serial = getenv("ANDROID_SERIAL");
while (1) {
- int c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:ha::", longopts, &longindex);
+ int c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lc:i:m:ha::", longopts, &longindex);
if (c < 0) {
break;
}
@@ -1526,8 +1495,7 @@
cmdline = optarg;
break;
case 'h':
- usage();
- return 1;
+ return show_help();
case 'i': {
char *endptr = nullptr;
unsigned long val;
@@ -1548,9 +1516,6 @@
page_size = (unsigned)strtoul(optarg, nullptr, 0);
if (!page_size) die("invalid page size");
break;
- case 'p':
- product = optarg;
- break;
case 'r':
ramdisk_offset = strtoul(optarg, 0, 16);
break;
@@ -1579,7 +1544,7 @@
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
} else if (strcmp("version", longopts[longindex].name) == 0) {
- fprintf(stdout, "fastboot version %s\n", FASTBOOT_REVISION);
+ fprintf(stdout, "fastboot version %s\n", FASTBOOT_VERSION);
fprintf(stdout, "Installed as %s\n", android::base::GetExecutablePath().c_str());
return 0;
} else if (strcmp("slot", longopts[longindex].name) == 0) {
@@ -1607,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();
@@ -1649,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());
@@ -1667,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, product);
- skip(2);
+ fname = find_item(pname);
}
- 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())) {
@@ -1774,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);
@@ -1804,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.
@@ -1829,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());
}
}
@@ -1877,17 +1797,17 @@
if (initial_userdata_dir.empty()) {
return 1;
}
- fb_perform_format(transport, "userdata", 1, nullptr, nullptr, initial_userdata_dir);
+ fb_perform_format(transport, "userdata", 1, "", "", initial_userdata_dir);
delete_fbemarker_tmpdir(initial_userdata_dir);
} else {
- fb_perform_format(transport, "userdata", 1, nullptr, nullptr, "");
+ fb_perform_format(transport, "userdata", 1, "", "", "");
}
std::string cache_type;
if (fb_getvar(transport, "partition-type:cache", &cache_type) && !cache_type.empty()) {
fprintf(stderr, "wiping cache...\n");
fb_queue_erase("cache");
- fb_perform_format(transport, "cache", 1, nullptr, nullptr, "");
+ fb_perform_format(transport, "cache", 1, "", "", "");
}
}
if (wants_set_active) {
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index e30c6de..e3c60ae 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -66,7 +66,7 @@
void fb_queue_command(const char *cmd, const char *msg);
void fb_queue_download(const char *name, void *data, uint32_t size);
void fb_queue_download_fd(const char *name, int fd, uint32_t sz);
-void fb_queue_upload(char *outfile);
+void fb_queue_upload(const char* outfile);
void fb_queue_notice(const char *notice);
void fb_queue_wait_for_disconnect(void);
int64_t fb_execute_queue(Transport* transport);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 6e9069e..df3c300 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -744,23 +744,6 @@
}
}
-static std::string extract_by_name_prefix(struct fstab* fstab) {
- // We assume that there's an entry for the /misc mount point in the
- // fstab file and use that to get the device file by-name prefix.
- // The device needs not to have an actual /misc partition.
- // e.g.,
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/
- struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
- if (fstab_entry == nullptr) {
- LERROR << "/misc mount point not found in fstab";
- return "";
- }
- std::string full_path(fstab_entry->blk_device);
- size_t end_slash = full_path.find_last_of("/");
- return full_path.substr(0, end_slash + 1);
-}
-
// TODO: add ueventd notifiers if they don't exist.
// This is just doing a wait_for_device for maximum of 1s
int fs_mgr_test_access(const char *device) {
@@ -850,7 +833,7 @@
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
- avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab));
+ avb_handle = FsManagerAvbHandle::Open(*fstab);
if (!avb_handle) {
LERROR << "Failed to open FsManagerAvbHandle";
return FS_MGR_MNTALL_FAIL;
@@ -1046,8 +1029,7 @@
}
int fs_stat = 0;
- int force_check = do_quota_with_shutdown_check(fstab->recs[i].blk_device,
- fstab->recs[i].fs_type,
+ int force_check = do_quota_with_shutdown_check(n_blk_device, fstab->recs[i].fs_type,
&fstab->recs[i], &fs_stat);
if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
@@ -1061,7 +1043,7 @@
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
- avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab));
+ avb_handle = FsManagerAvbHandle::Open(*fstab);
if (!avb_handle) {
LERROR << "Failed to open FsManagerAvbHandle";
return FS_MGR_DOMNT_FAILED;
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 94cea57..c21139e 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "fs_mgr_avb.h"
+
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -38,9 +40,8 @@
#include <utils/Compat.h>
#include "fs_mgr.h"
-#include "fs_mgr_avb.h"
-#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_avb_ops.h"
#include "fs_mgr_priv_dm_ioctl.h"
#include "fs_mgr_priv_sha.h"
@@ -457,12 +458,21 @@
return true;
}
-FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const std::string& device_file_by_name_prefix) {
- if (device_file_by_name_prefix.empty()) {
- LERROR << "Missing device file by-name prefix";
+FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const fstab& fstab) {
+ FsManagerAvbOps avb_ops(fstab);
+ return DoOpen(&avb_ops);
+}
+
+FsManagerAvbUniquePtr FsManagerAvbHandle::Open(ByNameSymlinkMap&& by_name_symlink_map) {
+ if (by_name_symlink_map.empty()) {
+ LERROR << "Empty by_name_symlink_map when opening FsManagerAvbHandle";
return nullptr;
}
+ FsManagerAvbOps avb_ops(std::move(by_name_symlink_map));
+ return DoOpen(&avb_ops);
+}
+FsManagerAvbUniquePtr FsManagerAvbHandle::DoOpen(FsManagerAvbOps* avb_ops) {
// Gets the expected hash value of vbmeta images from kernel cmdline.
std::unique_ptr<FsManagerAvbVerifier> avb_verifier = FsManagerAvbVerifier::Create();
if (!avb_verifier) {
@@ -476,20 +486,40 @@
return nullptr;
}
- FsManagerAvbOps avb_ops(device_file_by_name_prefix);
- AvbSlotVerifyResult verify_result = avb_ops.AvbSlotVerify(
+ AvbSlotVerifyResult verify_result = avb_ops->AvbSlotVerify(
fs_mgr_get_slot_suffix(), avb_verifier->IsDeviceUnlocked(), &avb_handle->avb_slot_data_);
// Only allow two verify results:
// - AVB_SLOT_VERIFY_RESULT_OK.
// - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (for UNLOCKED state).
- if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION) {
- if (!avb_verifier->IsDeviceUnlocked()) {
- LERROR << "ERROR_VERIFICATION isn't allowed";
+ // If the device is UNLOCKED, i.e., |allow_verification_error| is true for
+ // AvbSlotVerify(), then the following return values are all non-fatal:
+ // * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION
+ // * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED
+ // * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX
+ // The latter two results were checked by bootloader prior to start fs_mgr so
+ // we just need to handle the first result here. See *dummy* operations in
+ // FsManagerAvbOps and the comments in external/avb/libavb/avb_slot_verify.h
+ // for more details.
+ switch (verify_result) {
+ case AVB_SLOT_VERIFY_RESULT_OK:
+ avb_handle->status_ = kFsManagerAvbHandleSuccess;
+ break;
+ case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+ if (!avb_verifier->IsDeviceUnlocked()) {
+ LERROR << "ERROR_VERIFICATION isn't allowed when the device is LOCKED";
+ return nullptr;
+ }
+ avb_handle->status_ = kFsManagerAvbHandleErrorVerification;
+ break;
+ default:
+ LERROR << "avb_slot_verify failed, result: " << verify_result;
return nullptr;
- }
- } else if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
- LERROR << "avb_slot_verify failed, result: " << verify_result;
+ }
+
+ // Verifies vbmeta images against the digest passed from bootloader.
+ if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
+ LERROR << "VerifyVbmetaImages failed";
return nullptr;
}
@@ -497,30 +527,20 @@
avb_handle->avb_version_ =
android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
- // Verifies vbmeta images against the digest passed from bootloader.
- if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
- LERROR << "VerifyVbmetaImages failed";
- return nullptr;
- } else {
- // Checks whether FLAGS_HASHTREE_DISABLED is set.
- AvbVBMetaImageHeader vbmeta_header;
- avb_vbmeta_image_header_to_host_byte_order(
- (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
- &vbmeta_header);
+ // Checks whether FLAGS_HASHTREE_DISABLED is set.
+ AvbVBMetaImageHeader vbmeta_header;
+ avb_vbmeta_image_header_to_host_byte_order(
+ (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
+ &vbmeta_header);
- bool hashtree_disabled =
- ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
- if (hashtree_disabled) {
- avb_handle->status_ = kFsManagerAvbHandleHashtreeDisabled;
- return avb_handle;
- }
+ bool hashtree_disabled =
+ ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
+ if (hashtree_disabled) {
+ avb_handle->status_ = kFsManagerAvbHandleHashtreeDisabled;
}
- if (verify_result == AVB_SLOT_VERIFY_RESULT_OK) {
- avb_handle->status_ = kFsManagerAvbHandleSuccess;
- return avb_handle;
- }
- return nullptr;
+ LINFO << "Returning avb_handle with status: " << avb_handle->status_;
+ return avb_handle;
}
bool FsManagerAvbHandle::SetUpAvb(struct fstab_rec* fstab_entry, bool wait_for_verity_dev) {
@@ -528,11 +548,12 @@
if (!avb_slot_data_ || avb_slot_data_->num_vbmeta_images < 1) {
return false;
}
+
+ if (status_ == kFsManagerAvbHandleUninitialized) return false;
if (status_ == kFsManagerAvbHandleHashtreeDisabled) {
LINFO << "AVB HASHTREE disabled on:" << fstab_entry->mount_point;
return true;
}
- if (status_ != kFsManagerAvbHandleSuccess) return false;
std::string partition_name(basename(fstab_entry->mount_point));
if (!avb_validate_utf8((const uint8_t*)partition_name.c_str(), partition_name.length())) {
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index caee4ec..8feeb53 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -22,6 +22,8 @@
* SOFTWARE.
*/
+#include "fs_mgr_priv_avb_ops.h"
+
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -36,7 +38,6 @@
#include <utils/Compat.h>
#include "fs_mgr.h"
-#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
@@ -88,11 +89,7 @@
return AVB_IO_RESULT_OK;
}
-FsManagerAvbOps::FsManagerAvbOps(const std::string& device_file_by_name_prefix)
- : device_file_by_name_prefix_(device_file_by_name_prefix) {
- if (device_file_by_name_prefix_.back() != '/') {
- device_file_by_name_prefix_ += '/';
- }
+void FsManagerAvbOps::InitializeAvbOps() {
// We only need to provide the implementation of read_from_partition()
// operation since that's all what is being used by the avb_slot_verify().
// Other I/O operations are only required in bootloader but not in
@@ -109,13 +106,31 @@
avb_ops_.user_data = this;
}
+FsManagerAvbOps::FsManagerAvbOps(std::map<std::string, std::string>&& by_name_symlink_map)
+ : by_name_symlink_map_(std::move(by_name_symlink_map)) {
+ InitializeAvbOps();
+}
+
+FsManagerAvbOps::FsManagerAvbOps(const fstab& fstab) {
+ // Constructs the by-name symlink map for each fstab record.
+ // /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a =>
+ // by_name_symlink_map_["system_a"] = "/dev/block/platform/soc.0/7824900.sdhci/by-name/system_a"
+ for (int i = 0; i < fstab.num_entries; i++) {
+ std::string partition_name = basename(fstab.recs[i].blk_device);
+ by_name_symlink_map_[partition_name] = fstab.recs[i].blk_device;
+ }
+ InitializeAvbOps();
+}
+
AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
size_t num_bytes, void* buffer,
size_t* out_num_read) {
- // Appends |partition| to the device_file_by_name_prefix_, e.g.,
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
- std::string path = device_file_by_name_prefix_ + partition;
+ const auto iter = by_name_symlink_map_.find(partition);
+ if (iter == by_name_symlink_map_.end()) {
+ LERROR << "by-name symlink not found for partition: '" << partition << "'";
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+ }
+ std::string path = iter->second;
// Ensures the device path (a symlink created by init) is ready to
// access. fs_mgr_test_access() will test a few iterations if the
@@ -126,7 +141,7 @@
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd < 0) {
- PERROR << "Failed to open " << path.c_str();
+ PERROR << "Failed to open " << path;
return AVB_IO_RESULT_ERROR_IO;
}
@@ -150,8 +165,7 @@
// for EOF).
ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
if (num_read < 0 || (size_t)num_read != num_bytes) {
- PERROR << "Failed to read " << num_bytes << " bytes from " << path.c_str() << " offset "
- << offset;
+ PERROR << "Failed to read " << num_bytes << " bytes from " << path << " offset " << offset;
return AVB_IO_RESULT_ERROR_IO;
}
diff --git a/fs_mgr/fs_mgr_avb_ops.h b/fs_mgr/fs_mgr_priv_avb_ops.h
similarity index 87%
rename from fs_mgr/fs_mgr_avb_ops.h
rename to fs_mgr/fs_mgr_priv_avb_ops.h
index ec4a8c9..a6b52e4 100644
--- a/fs_mgr/fs_mgr_avb_ops.h
+++ b/fs_mgr/fs_mgr_priv_avb_ops.h
@@ -22,8 +22,11 @@
* SOFTWARE.
*/
-#ifndef __CORE_FS_MGR_AVB_OPS_H
-#define __CORE_FS_MGR_AVB_OPS_H
+#ifndef __CORE_FS_MGR_PRIV_AVB_OPS_H
+#define __CORE_FS_MGR_PRIV_AVB_OPS_H
+
+#include <map>
+#include <string>
#include <libavb/libavb.h>
@@ -43,7 +46,8 @@
//
class FsManagerAvbOps {
public:
- FsManagerAvbOps(const std::string& device_file_by_name_prefix);
+ FsManagerAvbOps(const fstab& fstab);
+ FsManagerAvbOps(std::map<std::string, std::string>&& by_name_symlink_map);
static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) {
return reinterpret_cast<FsManagerAvbOps*>(ops->user_data);
@@ -56,7 +60,9 @@
AvbSlotVerifyData** out_data);
private:
+ void InitializeAvbOps();
+
AvbOps avb_ops_;
- std::string device_file_by_name_prefix_;
+ std::map<std::string, std::string> by_name_symlink_map_;
};
-#endif /* __CORE_FS_MGR_AVB_OPS_H */
+#endif /* __CORE_FS_MGR_PRIV_AVB_OPS_H */
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 0bf173b..5fa10bc 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -663,7 +663,7 @@
/* use the kernel parameter if set */
std::string veritymode;
if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
- if (veritymode.compare("enforcing")) {
+ if (veritymode == "enforcing") {
*mode = VERITY_MODE_DEFAULT;
}
return 0;
diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/include/fs_mgr_avb.h
index a66ff42..bbafe1a 100644
--- a/fs_mgr/include/fs_mgr_avb.h
+++ b/fs_mgr/include/fs_mgr_avb.h
@@ -17,6 +17,7 @@
#ifndef __CORE_FS_MGR_AVB_H
#define __CORE_FS_MGR_AVB_H
+#include <map>
#include <memory>
#include <string>
@@ -25,14 +26,19 @@
#include "fs_mgr.h"
enum FsManagerAvbHandleStatus {
+ kFsManagerAvbHandleUninitialized = -1,
kFsManagerAvbHandleSuccess = 0,
kFsManagerAvbHandleHashtreeDisabled = 1,
- kFsManagerAvbHandleFail = 2,
+ kFsManagerAvbHandleErrorVerification = 2,
};
+class FsManagerAvbOps;
+
class FsManagerAvbHandle;
using FsManagerAvbUniquePtr = std::unique_ptr<FsManagerAvbHandle>;
+using ByNameSymlinkMap = std::map<std::string, std::string>;
+
// Provides a factory method to return a unique_ptr pointing to itself and the
// SetUpAvb() function to extract dm-verity parameters from AVB metadata to
// load verity table into kernel through ioctl.
@@ -48,6 +54,13 @@
// A typical usage will be:
// - FsManagerAvbUniquePtr handle = FsManagerAvbHandle::Open();
//
+ // There are two overloaded Open() functions with a single parameter.
+ // The argument can be a ByNameSymlinkMap describing the mapping from partition
+ // name to by-name symlink, or a fstab file to which the ByNameSymlinkMap is
+ // constructed from. e.g.,
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a ->
+ // - ByNameSymlinkMap["system_a"] = "/dev/block/platform/soc.0/7824900.sdhci/by-name/system_a"
+ //
// Possible return values:
// - nullptr: any error when reading and verifying the metadata,
// e.g., I/O error, digest value mismatch, size mismatch, etc.
@@ -60,7 +73,8 @@
// - a valid unique_ptr with status kFsMgrAvbHandleSuccess: the metadata
// is verified and can be trusted.
//
- static FsManagerAvbUniquePtr Open(const std::string& device_file_by_name_prefix);
+ static FsManagerAvbUniquePtr Open(const fstab& fstab);
+ static FsManagerAvbUniquePtr Open(ByNameSymlinkMap&& by_name_symlink_map);
// Sets up dm-verity on the given fstab entry.
// The 'wait_for_verity_dev' parameter makes this function wait for the
@@ -87,10 +101,10 @@
}
};
- protected:
- FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleFail) {}
-
private:
+ FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleUninitialized) {}
+ static FsManagerAvbUniquePtr DoOpen(FsManagerAvbOps* avb_ops);
+
AvbSlotVerifyData* avb_slot_data_;
FsManagerAvbHandleStatus status_;
std::string avb_version_;
diff --git a/init/README.md b/init/README.md
index 9fc8d47..72b6c6b 100644
--- a/init/README.md
+++ b/init/README.md
@@ -356,9 +356,9 @@
Init halts executing commands until the forked process exits.
`exec_start <service>`
-> Start service a given service and halt processing of additional init commands
- until it returns. It functions similarly to the `exec` command, but uses an
- existing service definition instead of providing them as arguments.
+> Start a given service and halt the processing of additional init commands
+ until it returns. The command functions similarly to the `exec` command,
+ but uses an existing service definition in place of the exec argument vector.
`export <name> <value>`
> Set the environment variable _name_ equal to _value_ in the
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 1d98ef1..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) {
@@ -205,7 +215,7 @@
mode = std::strtoul(args[2].c_str(), 0, 8);
}
- ret = make_dir(args[1].c_str(), mode);
+ ret = make_dir(args[1].c_str(), mode, sehandle);
/* chmod in case the directory already exists */
if (ret == -1 && errno == EEXIST) {
ret = fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW);
@@ -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;
}
}
@@ -809,7 +847,7 @@
* Callback to make a directory from the ext4 code
*/
static int do_installkeys_ensure_dir_exists(const char* dir) {
- if (make_dir(dir, 0700) && errno != EEXIST) {
+ if (make_dir(dir, 0700, sehandle) && errno != EEXIST) {
return -1;
}
@@ -835,7 +873,9 @@
}
static int do_init_user0(const std::vector<std::string>& args) {
- return e4crypt_do_init_user0();
+ std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
+ "init_user0"};
+ return do_exec(exec_args);
}
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index bc6bc8d..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());
+ 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 11687f0..d8258cf 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -54,7 +54,11 @@
#include "ueventd.h"
#include "util.h"
-extern struct selabel_handle *sehandle;
+#ifdef _INIT_INIT_H
+#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
+#endif
+
+static selabel_handle* sehandle;
static android::base::unique_fd device_fd;
@@ -247,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);
}
}
@@ -554,7 +558,7 @@
}
static void make_link_init(const std::string& oldpath, const std::string& newpath) {
- if (mkdir_recursive(dirname(newpath.c_str()), 0755)) {
+ if (mkdir_recursive(dirname(newpath.c_str()), 0755, sehandle)) {
PLOG(ERROR) << "Failed to create directory " << dirname(newpath.c_str());
}
@@ -599,7 +603,7 @@
if (uevent->major < 0 || uevent->minor < 0) return;
const char* base = "/dev/block/";
- make_dir(base, 0755);
+ make_dir(base, 0755, sehandle);
std::string name = android::base::Basename(uevent->path);
std::string devpath = base + name;
@@ -641,7 +645,7 @@
devpath = "/dev/" + android::base::Basename(uevent->path);
}
- mkdir_recursive(android::base::Dirname(devpath), 0755);
+ mkdir_recursive(android::base::Dirname(devpath), 0755, sehandle);
auto links = get_character_device_symlinks(uevent);
diff --git a/init/init.cpp b/init/init.cpp
index 99ce5e6..878f164 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -21,6 +21,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <keyutils.h>
#include <libgen.h>
#include <paths.h>
#include <signal.h>
@@ -852,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();
}
@@ -863,25 +866,28 @@
}
}
-// The files and directories that were created before initial sepolicy load
-// need to have their security context restored to the proper value.
-// This must happen before /dev is populated by ueventd.
+// The files and directories that were created before initial sepolicy load or
+// files on ramdisk need to have their security context restored to the proper
+// 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);
+
+ selinux_android_restorecon("/sbin/mke2fs", 0);
+ selinux_android_restorecon("/sbin/e2fsdroid", 0);
}
// Set the UDC controller for the ConfigFS USB Gadgets.
@@ -990,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();
}
@@ -1015,6 +1021,11 @@
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
+ // Set up a session keyring that all processes will have access to. It
+ // will hold things like FBE encryption keys. No process should override
+ // its session keyring.
+ keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 1);
+
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
diff --git a/init/init.h b/init/init.h
index 6add75f..6725a70 100644
--- a/init/init.h
+++ b/init/init.h
@@ -19,6 +19,9 @@
#include <string>
+// Note: These globals are *only* valid in init, so they should not be used in ueventd,
+// watchdogd, or any files that may be included in those, such as devices.cpp and util.cpp.
+// TODO: Have an Init class and remove all globals.
extern const char *ENV[32];
extern std::string default_console;
extern struct selabel_handle *sehandle;
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 43f1c15..9d2a0d1 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -47,18 +47,22 @@
bool InitDevices();
protected:
- void InitRequiredDevices(std::set<std::string>* devices_partition_names);
+ void InitRequiredDevices();
void InitVerityDevice(const std::string& verity_device);
bool MountPartitions();
- virtual bool GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
- bool* out_need_dm_verity) = 0;
+ virtual coldboot_action_t ColdbootCallback(uevent* uevent);
+
+ // Pure virtual functions.
+ virtual bool GetRequiredDevices() = 0;
virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
+ bool need_dm_verity_;
// Device tree fstab entries.
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
// Eligible first stage mount candidates, only allow /system, /vendor and/or /odm.
std::vector<fstab_rec*> mount_fstab_recs_;
+ std::set<std::string> required_devices_partition_names_;
};
class FirstStageMountVBootV1 : public FirstStageMount {
@@ -67,27 +71,26 @@
~FirstStageMountVBootV1() override = default;
protected:
- bool GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
- bool* out_need_dm_verity) override;
+ bool GetRequiredDevices() override;
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
};
class FirstStageMountVBootV2 : public FirstStageMount {
public:
+ friend void SetInitAvbVersionInRecovery();
+
FirstStageMountVBootV2();
~FirstStageMountVBootV2() override = default;
- const std::string& by_name_prefix() const { return device_tree_by_name_prefix_; }
-
protected:
- bool GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
- bool* out_need_dm_verity) override;
+ coldboot_action_t ColdbootCallback(uevent* uevent) override;
+ bool GetRequiredDevices() override;
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
bool InitAvbHandle();
std::string device_tree_vbmeta_parts_;
- std::string device_tree_by_name_prefix_;
FsManagerAvbUniquePtr avb_handle_;
+ ByNameSymlinkMap by_name_symlink_map_;
};
// Static Functions
@@ -102,7 +105,8 @@
// Class Definitions
// -----------------
-FirstStageMount::FirstStageMount() : device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
+FirstStageMount::FirstStageMount()
+ : need_dm_verity_(false), device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
if (!device_tree_fstab_) {
LOG(ERROR) << "Failed to read fstab from device tree";
return;
@@ -136,69 +140,71 @@
}
bool FirstStageMount::InitDevices() {
- bool need_dm_verity;
- std::set<std::string> devices_partition_names;
+ if (!GetRequiredDevices()) return false;
- // The partition name in devices_partition_names MUST have A/B suffix when A/B is used.
- if (!GetRequiredDevices(&devices_partition_names, &need_dm_verity)) return false;
+ InitRequiredDevices();
- if (need_dm_verity) {
- device_init("/sys/devices/virtual/misc/device-mapper",
- [&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; });
- }
-
- bool success = false;
- InitRequiredDevices(&devices_partition_names);
-
- // InitRequiredDevices() will remove found partitions from devices_partition_names.
+ // InitRequiredDevices() will remove found partitions from required_devices_partition_names_.
// So if it isn't empty here, it means some partitions are not found.
- if (!devices_partition_names.empty()) {
+ if (!required_devices_partition_names_.empty()) {
LOG(ERROR) << __FUNCTION__ << "(): partition(s) not found: "
- << android::base::Join(devices_partition_names, ", ");
+ << android::base::Join(required_devices_partition_names_, ", ");
+ return false;
} else {
- success = true;
+ return true;
}
-
- device_close();
- return success;
}
-// Creates devices with uevent->partition_name matching one in the in/out
-// devices_partition_names. Found partitions will then be removed from the
-// devices_partition_names for the caller to check which devices are NOT created.
-void FirstStageMount::InitRequiredDevices(std::set<std::string>* devices_partition_names) {
- if (devices_partition_names->empty()) {
+// Creates devices with uevent->partition_name matching one in the member variable
+// required_devices_partition_names_. Found partitions will then be removed from it
+// for the subsequent member function to check which devices are NOT created.
+void FirstStageMount::InitRequiredDevices() {
+ if (required_devices_partition_names_.empty()) {
return;
}
- device_init(nullptr, [=](uevent* uevent) -> coldboot_action_t {
- // We need platform devices to create symlinks.
- if (uevent->subsystem == "platform") {
- return COLDBOOT_CREATE;
- }
- // Ignores everything that is not a block device.
- if (uevent->subsystem != "block") {
- return COLDBOOT_CONTINUE;
- }
+ if (need_dm_verity_) {
+ const std::string dm_path = "/devices/virtual/misc/device-mapper";
+ device_init(("/sys" + dm_path).c_str(), [&dm_path](uevent* uevent) -> coldboot_action_t {
+ if (uevent->path == dm_path) return COLDBOOT_STOP;
+ return COLDBOOT_CONTINUE; // dm_path not found, continue to find it.
+ });
+ }
- if (!uevent->partition_name.empty()) {
- // Matches partition name to create device nodes.
- // Both devices_partition_names and uevent->partition_name have A/B
- // suffix when A/B is used.
- auto iter = devices_partition_names->find(uevent->partition_name);
- if (iter != devices_partition_names->end()) {
- LOG(VERBOSE) << __FUNCTION__ << "(): found partition: " << *iter;
- devices_partition_names->erase(iter);
- if (devices_partition_names->empty()) {
- return COLDBOOT_STOP; // Found all partitions, stop coldboot.
- } else {
- return COLDBOOT_CREATE; // Creates this device and continue to find others.
- }
+ device_init(nullptr,
+ [this](uevent* uevent) -> coldboot_action_t { return ColdbootCallback(uevent); });
+
+ device_close();
+}
+
+coldboot_action_t FirstStageMount::ColdbootCallback(uevent* uevent) {
+ // We need platform devices to create symlinks.
+ if (uevent->subsystem == "platform") {
+ return COLDBOOT_CREATE;
+ }
+
+ // Ignores everything that is not a block device.
+ if (uevent->subsystem != "block") {
+ return COLDBOOT_CONTINUE;
+ }
+
+ if (!uevent->partition_name.empty()) {
+ // Matches partition name to create device nodes.
+ // Both required_devices_partition_names_ and uevent->partition_name have A/B
+ // suffix when A/B is used.
+ auto iter = required_devices_partition_names_.find(uevent->partition_name);
+ if (iter != required_devices_partition_names_.end()) {
+ LOG(VERBOSE) << __FUNCTION__ << "(): found partition: " << *iter;
+ required_devices_partition_names_.erase(iter);
+ if (required_devices_partition_names_.empty()) {
+ return COLDBOOT_STOP; // Found all partitions, stop coldboot.
+ } else {
+ return COLDBOOT_CREATE; // Creates this device and continue to find others.
}
}
- // Not found a partition or find an unneeded partition, continue to find others.
- return COLDBOOT_CONTINUE;
- });
+ }
+ // Not found a partition or find an unneeded partition, continue to find others.
+ return COLDBOOT_CONTINUE;
}
// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
@@ -230,10 +236,9 @@
return true;
}
-bool FirstStageMountVBootV1::GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
- bool* out_need_dm_verity) {
+bool FirstStageMountVBootV1::GetRequiredDevices() {
std::string verity_loc_device;
- *out_need_dm_verity = false;
+ need_dm_verity_ = false;
for (auto fstab_rec : mount_fstab_recs_) {
// Don't allow verifyatboot in the first stage.
@@ -243,7 +248,7 @@
}
// Checks for verified partitions.
if (fs_mgr_is_verified(fstab_rec)) {
- *out_need_dm_verity = true;
+ need_dm_verity_ = true;
}
// Checks if verity metadata is on a separate partition. Note that it is
// not partition specific, so there must be only one additional partition
@@ -262,11 +267,11 @@
// Includes the partition names of fstab records and verity_loc_device (if any).
// Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
for (auto fstab_rec : mount_fstab_recs_) {
- out_devices_partition_names->emplace(basename(fstab_rec->blk_device));
+ required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
}
if (!verity_loc_device.empty()) {
- out_devices_partition_names->emplace(basename(verity_loc_device.c_str()));
+ required_devices_partition_names_.emplace(basename(verity_loc_device.c_str()));
}
return true;
@@ -289,15 +294,13 @@
}
// FirstStageMountVBootV2 constructor.
-// Gets the vbmeta configurations from device tree.
-// Specifically, the 'parts' and 'by_name_prefix' below.
+// Gets the vbmeta partitions from device tree.
// /{
// firmware {
// android {
// vbmeta {
// compatible = "android,vbmeta";
// parts = "vbmeta,boot,system,vendor"
-// by_name_prefix = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/"
// };
// };
// };
@@ -307,31 +310,24 @@
PLOG(ERROR) << "Failed to read vbmeta/parts from device tree";
return;
}
-
- // TODO: removes by_name_prefix to allow partitions on different block devices.
- if (!read_android_dt_file("vbmeta/by_name_prefix", &device_tree_by_name_prefix_)) {
- PLOG(ERROR) << "Failed to read vbmeta/by_name_prefix from dt";
- return;
- }
}
-bool FirstStageMountVBootV2::GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
- bool* out_need_dm_verity) {
- *out_need_dm_verity = false;
+bool FirstStageMountVBootV2::GetRequiredDevices() {
+ need_dm_verity_ = false;
// fstab_rec->blk_device has A/B suffix.
for (auto fstab_rec : mount_fstab_recs_) {
if (fs_mgr_is_avb(fstab_rec)) {
- *out_need_dm_verity = true;
+ need_dm_verity_ = true;
}
- out_devices_partition_names->emplace(basename(fstab_rec->blk_device));
+ required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
}
// libavb verifies AVB metadata on all verified partitions at once.
// e.g., The device_tree_vbmeta_parts_ will be "vbmeta,boot,system,vendor"
// for libavb to verify metadata, even if there is only /vendor in the
// above mount_fstab_recs_.
- if (*out_need_dm_verity) {
+ if (need_dm_verity_) {
if (device_tree_vbmeta_parts_.empty()) {
LOG(ERROR) << "Missing vbmeta parts in device tree";
return false;
@@ -339,16 +335,45 @@
std::vector<std::string> partitions = android::base::Split(device_tree_vbmeta_parts_, ",");
std::string ab_suffix = fs_mgr_get_slot_suffix();
for (const auto& partition : partitions) {
- // out_devices_partition_names is of type std::set so it's not an issue to emplace
- // a partition twice. e.g., /vendor might be in both places:
+ // required_devices_partition_names_ is of type std::set so it's not an issue
+ // to emplace a partition twice. e.g., /vendor might be in both places:
// - device_tree_vbmeta_parts_ = "vbmeta,boot,system,vendor"
// - mount_fstab_recs_: /vendor_a
- out_devices_partition_names->emplace(partition + ab_suffix);
+ required_devices_partition_names_.emplace(partition + ab_suffix);
}
}
return true;
}
+coldboot_action_t FirstStageMountVBootV2::ColdbootCallback(uevent* uevent) {
+ // Invokes the parent function to see if any desired partition has been found.
+ // If yes, record the by-name symlink for creating FsManagerAvbHandle later.
+ coldboot_action_t parent_callback_ret = FirstStageMount::ColdbootCallback(uevent);
+
+ // Skips the uevent if the parent function returns COLDBOOT_CONTINUE (meaning
+ // that the uevent was skipped) or there is no uevent->partition_name to
+ // create the by-name symlink.
+ if (parent_callback_ret != COLDBOOT_CONTINUE && !uevent->partition_name.empty()) {
+ // get_block_device_symlinks() will return three symlinks at most, depending on
+ // the content of uevent. by-name symlink will be at [0] if uevent->partition_name
+ // is not empty. e.g.,
+ // - /dev/block/platform/soc.0/f9824900.sdhci/by-name/modem
+ // - /dev/block/platform/soc.0/f9824900.sdhci/by-num/p1
+ // - /dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1
+ std::vector<std::string> links = get_block_device_symlinks(uevent);
+ if (!links.empty()) {
+ auto[it, inserted] = by_name_symlink_map_.emplace(uevent->partition_name, links[0]);
+ if (!inserted) {
+ LOG(ERROR) << "Partition '" << uevent->partition_name
+ << "' already existed in the by-name symlink map with a value of '"
+ << it->second << "', new value '" << links[0] << "' will be ignored.";
+ }
+ }
+ }
+
+ return parent_callback_ret;
+}
+
bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
if (fs_mgr_is_avb(fstab_rec)) {
if (!InitAvbHandle()) return false;
@@ -368,7 +393,14 @@
bool FirstStageMountVBootV2::InitAvbHandle() {
if (avb_handle_) return true; // Returns true if the handle is already initialized.
- avb_handle_ = FsManagerAvbHandle::Open(device_tree_by_name_prefix_);
+ if (by_name_symlink_map_.empty()) {
+ LOG(ERROR) << "by_name_symlink_map_ is empty";
+ return false;
+ }
+
+ avb_handle_ = FsManagerAvbHandle::Open(std::move(by_name_symlink_map_));
+ by_name_symlink_map_.clear(); // Removes all elements after the above std::move().
+
if (!avb_handle_) {
PLOG(ERROR) << "Failed to open FsManagerAvbHandle";
return false;
@@ -424,7 +456,8 @@
return;
}
- FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open(avb_first_mount.by_name_prefix());
+ FsManagerAvbUniquePtr avb_handle =
+ FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
if (!avb_handle) {
PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
return;
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 620367a..1b31cf2 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -110,7 +110,9 @@
LOG(INFO) << "Parsing file " << path << "...";
Timer t;
std::string data;
- if (!read_file(path, &data)) {
+ std::string err;
+ if (!ReadFile(path, &data, &err)) {
+ LOG(ERROR) << err;
return false;
}
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
index d8fd2ba..86d60d0 100644
--- a/init/init_parser_test.cpp
+++ b/init/init_parser_test.cpp
@@ -86,19 +86,29 @@
ASSERT_EQ("", svc->seclabel());
}
if (uid) {
- ASSERT_EQ(decode_uid("log"), svc->uid());
+ uid_t decoded_uid;
+ std::string err;
+ ASSERT_TRUE(DecodeUid("log", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->uid());
} else {
ASSERT_EQ(0U, svc->uid());
}
if (gid) {
- ASSERT_EQ(decode_uid("shell"), svc->gid());
+ uid_t decoded_uid;
+ std::string err;
+ ASSERT_TRUE(DecodeUid("shell", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->gid());
} else {
ASSERT_EQ(0U, svc->gid());
}
if (supplementary_gids) {
ASSERT_EQ(2U, svc->supp_gids().size());
- ASSERT_EQ(decode_uid("system"), svc->supp_gids()[0]);
- ASSERT_EQ(decode_uid("adb"), svc->supp_gids()[1]);
+ uid_t decoded_uid;
+ std::string err;
+ ASSERT_TRUE(DecodeUid("system", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->supp_gids()[0]);
+ ASSERT_TRUE(DecodeUid("adb", &decoded_uid, &err));
+ ASSERT_EQ(decoded_uid, svc->supp_gids()[1]);
} else {
ASSERT_EQ(0U, svc->supp_gids().size());
}
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 3da14b5..7093ba9 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -152,10 +152,11 @@
"on boot\n"
"execute 3";
// clang-format on
- // write_file() ensures the right mode is set
- ASSERT_TRUE(write_file(std::string(dir.path) + "/a.rc", dir_a_script));
+ // WriteFile() ensures the right mode is set
+ std::string err;
+ ASSERT_TRUE(WriteFile(std::string(dir.path) + "/a.rc", dir_a_script, &err));
- ASSERT_TRUE(write_file(std::string(dir.path) + "/b.rc", "on boot\nexecute 5"));
+ ASSERT_TRUE(WriteFile(std::string(dir.path) + "/b.rc", "on boot\nexecute 5", &err));
// clang-format off
std::string start_script = "import " + std::string(first_import.path) + "\n"
diff --git a/init/keyutils.h b/init/keyutils.h
new file mode 100644
index 0000000..de01beb
--- /dev/null
+++ b/init/keyutils.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/* Miniature version of a header-only keyutils.h (no library required) */
+
+#ifndef _INIT_KEYUTILS_H_
+#define _INIT_KEYUTILS_H_
+
+#ifndef KEYUTILS_H /* walk away if the _real_ one exists */
+
+#include <linux/keyctl.h>
+#include <stdarg.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static inline long keyctl(int cmd, ...) {
+ va_list va;
+ unsigned long arg2, arg3, arg4, arg5;
+
+ va_start(va, cmd);
+ arg2 = va_arg(va, unsigned long);
+ arg3 = va_arg(va, unsigned long);
+ arg4 = va_arg(va, unsigned long);
+ arg5 = va_arg(va, unsigned long);
+ va_end(va);
+ return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
+}
+
+#endif
+
+#endif
diff --git a/init/property_service.cpp b/init/property_service.cpp
index aa47976..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, NULL);
+ 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 a101ce5..75f81b9 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -40,56 +40,51 @@
#include <cutils/android_reboot.h>
#include <cutils/sockets.h>
#include <selinux/android.h>
-#include <selinux/label.h>
-#include "init.h"
#include "reboot.h"
+#ifdef _INIT_INIT_H
+#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
+#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)
-{
+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";
@@ -123,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;
@@ -156,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;
}
@@ -169,42 +174,48 @@
// 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) {
+int mkdir_recursive(const std::string& path, mode_t mode, selabel_handle* sehandle) {
std::string::size_type slash = 0;
while ((slash = path.find('/', slash + 1)) != std::string::npos) {
auto directory = path.substr(0, slash);
struct stat info;
if (stat(directory.c_str(), &info) != 0) {
- auto ret = make_dir(directory.c_str(), mode);
+ auto ret = make_dir(directory.c_str(), mode, sehandle);
if (ret && errno != EEXIST) return ret;
}
}
- auto ret = make_dir(path.c_str(), mode);
+ auto ret = make_dir(path.c_str(), mode, sehandle);
if (ret && errno != EEXIST) return ret;
return 0;
}
@@ -233,8 +244,7 @@
}
}
-int make_dir(const char *path, mode_t mode)
-{
+int make_dir(const char* path, mode_t mode, selabel_handle* sehandle) {
int rc;
char *secontext = NULL;
@@ -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 92b3a1d..1ad6b77 100644
--- a/init/util.h
+++ b/init/util.h
@@ -26,6 +26,7 @@
#include <string>
#include <android-base/chrono_utils.h>
+#include <selinux/label.h>
#define COLDBOOT_DONE "/dev/.coldboot_done"
@@ -34,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);
+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:
@@ -60,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);
+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);
-int restorecon(const char *pathname, int flags = 0);
+int make_dir(const char* path, mode_t mode, selabel_handle* sehandle);
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 b8b409a..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) {
@@ -128,15 +164,10 @@
EXPECT_FALSE(is_dir(tf.path));
}
-// sehandle is needed for make_dir()
-// TODO: Remove once sehandle is encapsulated
-#include <selinux/label.h>
-selabel_handle* sehandle;
-
TEST(util, mkdir_recursive) {
TemporaryDir test_dir;
std::string path = android::base::StringPrintf("%s/three/directories/deep", test_dir.path);
- EXPECT_EQ(0, mkdir_recursive(path, 0755));
+ EXPECT_EQ(0, mkdir_recursive(path, 0755, nullptr));
std::string path1 = android::base::StringPrintf("%s/three", test_dir.path);
EXPECT_TRUE(is_dir(path1.c_str()));
std::string path2 = android::base::StringPrintf("%s/three/directories", test_dir.path);
@@ -148,7 +179,7 @@
TEST(util, mkdir_recursive_extra_slashes) {
TemporaryDir test_dir;
std::string path = android::base::StringPrintf("%s/three////directories/deep//", test_dir.path);
- EXPECT_EQ(0, mkdir_recursive(path, 0755));
+ EXPECT_EQ(0, mkdir_recursive(path, 0755, nullptr));
std::string path1 = android::base::StringPrintf("%s/three", test_dir.path);
EXPECT_TRUE(is_dir(path1.c_str()));
std::string path2 = android::base::StringPrintf("%s/three/directories", test_dir.path);
diff --git a/init/watchdogd.cpp b/init/watchdogd.cpp
index 21c1e5b..7baa487 100644
--- a/init/watchdogd.cpp
+++ b/init/watchdogd.cpp
@@ -24,7 +24,10 @@
#include <android-base/logging.h>
#include "log.h"
-#include "util.h"
+
+#ifdef _INIT_INIT_H
+#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
+#endif
#define DEV_NAME "/dev/watchdog"
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 285aa6e..7dd9227 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -110,7 +110,7 @@
"libunwind",
],
- static_libs: ["libcutils"],
+ static_libs: ["libasync_safe", "libcutils"],
},
},
}
diff --git a/libbacktrace/BacktraceAsyncSafeLog.h b/libbacktrace/BacktraceAsyncSafeLog.h
new file mode 100644
index 0000000..14f51be
--- /dev/null
+++ b/libbacktrace/BacktraceAsyncSafeLog.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_BACKTRACE_ASYNC_SAFE_LOG_H
+#define _LIBBACKTRACE_BACKTRACE_ASYNC_SAFE_LOG_H
+
+#if defined(__ANDROID__)
+
+#include <async_safe/log.h>
+
+// Logging macros for use in signal handler, only available on target.
+#define BACK_ASYNC_SAFE_LOGW(format, ...) \
+ async_safe_format_log(ANDROID_LOG_WARN, "libbacktrace", "%s: " format, __PRETTY_FUNCTION__, \
+ ##__VA_ARGS__)
+
+#define BACK_ASYNC_SAFE_LOGE(format, ...) \
+ async_safe_format_log(ANDROID_LOG_ERROR, "libbacktrace", "%s: " format, __PRETTY_FUNCTION__, \
+ ##__VA_ARGS__)
+
+#else
+
+#define BACK_ASYNC_SAFE_LOGW(format, ...)
+
+#define BACK_ASYNC_SAFE_LOGE(format, ...)
+
+#endif
+
+#endif // _LIBBACKTRACE_BACKTRACE_ASYNC_SAFE_LOG_H
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index d7a3b01..fb76b85 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -31,8 +31,8 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
+#include "BacktraceAsyncSafeLog.h"
#include "BacktraceCurrent.h"
-#include "BacktraceLog.h"
#include "ThreadEntry.h"
#include "thread_utils.h"
@@ -47,7 +47,7 @@
*out_value = *reinterpret_cast<word_t*>(ptr);
return true;
} else {
- BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
+ BACK_ASYNC_SAFE_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
*out_value = static_cast<word_t>(-1);
return false;
}
@@ -114,7 +114,8 @@
static void SignalLogOnly(int, siginfo_t*, void*) {
ErrnoRestorer restore;
- BACK_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(), gettid(), THREAD_SIGNAL);
+ BACK_ASYNC_SAFE_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(), gettid(),
+ THREAD_SIGNAL);
}
static void SignalHandler(int, siginfo_t*, void* sigcontext) {
@@ -122,7 +123,7 @@
ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
if (!entry) {
- BACK_LOGE("pid %d, tid %d entry not found", getpid(), gettid());
+ BACK_ASYNC_SAFE_LOGE("pid %d, tid %d entry not found", getpid(), gettid());
return;
}
@@ -141,7 +142,7 @@
entry->Wake();
} else {
// At this point, it is possible that entry has been freed, so just exit.
- BACK_LOGE("Timed out waiting for unwind thread to indicate it completed.");
+ BACK_ASYNC_SAFE_LOGE("Timed out waiting for unwind thread to indicate it completed.");
}
}
@@ -159,7 +160,7 @@
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&act.sa_mask);
if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
- BACK_LOGE("sigaction failed: %s", strerror(errno));
+ BACK_ASYNC_SAFE_LOGE("sigaction failed: %s", strerror(errno));
ThreadEntry::Remove(entry);
pthread_mutex_unlock(&g_sigaction_mutex);
error_ = BACKTRACE_UNWIND_ERROR_INTERNAL;
@@ -212,7 +213,7 @@
// Wait for the thread to indicate it is done with the ThreadEntry.
if (!entry->Wait(3)) {
// Send a warning, but do not mark as a failure to unwind.
- BACK_LOGW("Timed out waiting for signal handler to indicate it finished.");
+ BACK_ASYNC_SAFE_LOGW("Timed out waiting for signal handler to indicate it finished.");
}
} else {
// Check to see if the thread has disappeared.
@@ -220,7 +221,7 @@
error_ = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST;
} else {
error_ = BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT;
- BACK_LOGE("Timed out waiting for signal handler to get ucontext data.");
+ BACK_ASYNC_SAFE_LOGE("Timed out waiting for signal handler to get ucontext data.");
}
}
diff --git a/libbacktrace/ThreadEntry.cpp b/libbacktrace/ThreadEntry.cpp
index 084c1aa..9bd59e4 100644
--- a/libbacktrace/ThreadEntry.cpp
+++ b/libbacktrace/ThreadEntry.cpp
@@ -21,7 +21,7 @@
#include <time.h>
#include <ucontext.h>
-#include "BacktraceLog.h"
+#include "BacktraceAsyncSafeLog.h"
#include "ThreadEntry.h"
// Initialize static member variables.
@@ -106,7 +106,7 @@
while (wait_value_ != value) {
int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
if (ret != 0) {
- BACK_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret));
+ BACK_ASYNC_SAFE_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret));
wait_completed = false;
break;
}
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 58170ec..245deb1 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -53,7 +53,7 @@
host_supported: true,
srcs: [
"config_utils.c",
- "fs_config.c",
+ "fs_config.cpp",
"canned_fs_config.c",
"hashmap.c",
"iosched_policy.c",
@@ -94,6 +94,9 @@
shared: {
enabled: false,
},
+ cflags: [
+ "-D_GNU_SOURCE",
+ ],
},
android: {
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.cpp
similarity index 86%
rename from libcutils/fs_config.c
rename to libcutils/fs_config.cpp
index e4541f7..2b3443f 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.cpp
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-/* This file is used to define the properties of the filesystem
-** images generated by build tools (mkbootfs and mkyaffs2image) and
-** by the device side of adb.
-*/
+// This file is used to define the properties of the filesystem
+// images generated by build tools (mkbootfs and mkyaffs2image) and
+// by the device side of adb.
#define LOG_TAG "fs_config"
-#define _GNU_SOURCE
-
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
@@ -42,8 +39,10 @@
#define O_BINARY 0
#endif
-/* My kingdom for <endian.h> */
-static inline uint16_t get2LE(const uint8_t* src) { return src[0] | (src[1] << 8); }
+// My kingdom for <endian.h>
+static inline uint16_t get2LE(const uint8_t* src) {
+ return src[0] | (src[1] << 8);
+}
static inline uint64_t get8LE(const uint8_t* src) {
uint32_t low, high;
@@ -55,14 +54,13 @@
#define ALIGN(x, alignment) (((x) + ((alignment)-1)) & ~((alignment)-1))
-/* Rules for directories.
-** These rules are applied based on "first match", so they
-** should start with the most specific path and work their
-** way up to the root.
-*/
+// Rules for directories.
+// These rules are applied based on "first match", so they
+// should start with the most specific path and work their
+// way up to the root.
static const struct fs_path_config android_dirs[] = {
- /* clang-format off */
+ // clang-format off
{ 00770, AID_SYSTEM, AID_CACHE, 0, "cache" },
{ 00500, AID_ROOT, AID_ROOT, 0, "config" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
@@ -92,25 +90,26 @@
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor" },
{ 00755, AID_ROOT, AID_ROOT, 0, 0 },
- /* clang-format on */
+ // clang-format on
};
+#ifndef __ANDROID_VNDK__
+auto __for_testing_only__android_dirs = android_dirs;
+#endif
-/* Rules for files.
-** These rules are applied based on "first match", so they
-** should start with the most specific path and work their
-** way up to the root. Prefixes ending in * denotes wildcard
-** and will allow partial matches.
-*/
+// Rules for files.
+// These rules are applied based on "first match", so they
+// should start with the most specific path and work their
+// way up to the root. Prefixes ending in * denotes wildcard
+// and will allow partial matches.
static const char sys_conf_dir[] = "/system/etc/fs_config_dirs";
static const char sys_conf_file[] = "/system/etc/fs_config_files";
-/* No restrictions are placed on the vendor and oem file-system config files,
- * although the developer is advised to restrict the scope to the /vendor or
- * oem/ file-system since the intent is to provide support for customized
- * portions of a separate vendor.img or oem.img. Has to remain open so that
- * customization can also land on /system/vendor, /system/oem or /system/odm.
- * We expect build-time checking or filtering when constructing the associated
- * fs_config_* files (see build/tools/fs_config/fs_config_generate.c)
- */
+// No restrictions are placed on the vendor and oem file-system config files,
+// although the developer is advised to restrict the scope to the /vendor or
+// oem/ file-system since the intent is to provide support for customized
+// portions of a separate vendor.img or oem.img. Has to remain open so that
+// customization can also land on /system/vendor, /system/oem or /system/odm.
+// We expect build-time checking or filtering when constructing the associated
+// fs_config_* files (see build/tools/fs_config/fs_config_generate.c)
static const char ven_conf_dir[] = "/vendor/etc/fs_config_dirs";
static const char ven_conf_file[] = "/vendor/etc/fs_config_files";
static const char oem_conf_dir[] = "/oem/etc/fs_config_dirs";
@@ -125,7 +124,7 @@
};
static const struct fs_path_config android_files[] = {
- /* clang-format off */
+ // clang-format off
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" },
@@ -173,13 +172,13 @@
{ 00444, AID_ROOT, AID_ROOT, 0, ven_conf_dir + 1 },
{ 00444, AID_ROOT, AID_ROOT, 0, ven_conf_file + 1 },
- /* the following two files are INTENTIONALLY set-uid, but they
- * are NOT included on user builds. */
+ // the following two files are INTENTIONALLY set-uid, but they
+ // are NOT included on user builds.
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
{ 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" },
- /* the following files have enhanced capabilities and ARE included
- * in user builds. */
+ // the following files have enhanced capabilities and ARE included
+ // in user builds.
{ 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND),
"system/bin/inputflinger" },
{ 00550, AID_LOGD, AID_LOGD, CAP_MASK_LONG(CAP_SYSLOG) |
@@ -190,17 +189,17 @@
CAP_MASK_LONG(CAP_SETGID),
"system/bin/run-as" },
- /* Support FIFO scheduling mode in SurfaceFlinger. */
+ // Support FIFO scheduling mode in SurfaceFlinger.
{ 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE),
"system/bin/surfaceflinger" },
- /* Support hostapd administering a network interface. */
+ // Support hostapd administering a network interface.
{ 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
CAP_MASK_LONG(CAP_NET_RAW),
"system/bin/hostapd" },
- /* Support Bluetooth legacy hal accessing /sys/class/rfkill
- * Support RT scheduling in Bluetooth */
+ // Support Bluetooth legacy hal accessing /sys/class/rfkill
+ // Support RT scheduling in Bluetooth
{ 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN) |
CAP_MASK_LONG(CAP_SYS_NICE),
"system/vendor/bin/hw/android.hardware.bluetooth@1.0-service" },
@@ -208,7 +207,7 @@
CAP_MASK_LONG(CAP_SYS_NICE),
"vendor/bin/hw/android.hardware.bluetooth@1.0-service" },
- /* Support wifi_hal_legacy administering a network interface. */
+ // Support wifi_hal_legacy administering a network interface.
{ 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
CAP_MASK_LONG(CAP_NET_RAW),
"system/vendor/bin/hw/android.hardware.wifi@1.0-service" },
@@ -216,8 +215,7 @@
CAP_MASK_LONG(CAP_NET_RAW),
"vendor/bin/hw/android.hardware.wifi@1.0-service" },
- /* A non-privileged zygote that spawns
- * isolated processes for web rendering. */
+ // A non-privileged zygote that spawns isolated processes for web rendering.
{ 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) |
CAP_MASK_LONG(CAP_SETGID) |
CAP_MASK_LONG(CAP_SETPCAP),
@@ -227,7 +225,7 @@
CAP_MASK_LONG(CAP_SETPCAP),
"system/bin/webview_zygote64" },
- /* generic defaults */
+ // generic defaults
{ 00755, AID_ROOT, AID_ROOT, 0, "bin/*" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "init*" },
@@ -241,8 +239,11 @@
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/xbin/*" },
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
- /* clang-format on */
+ // clang-format on
};
+#ifndef __ANDROID_VNDK__
+auto __for_testing_only__android_files = android_files;
+#endif
static size_t strip(const char* path, size_t len, const char suffix[]) {
if (len < strlen(suffix)) return len;
@@ -254,9 +255,9 @@
int fd = -1;
if (target_out_path && *target_out_path) {
- /* target_out_path is the path to the directory holding content of
- * system partition but as we cannot guarantee it ends with '/system'
- * or with or without a trailing slash, need to strip them carefully. */
+ // target_out_path is the path to the directory holding content of
+ // system partition but as we cannot guarantee it ends with '/system'
+ // or with or without a trailing slash, need to strip them carefully.
char* name = NULL;
size_t len = strlen(target_out_path);
len = strip(target_out_path, len, "/");
@@ -278,7 +279,7 @@
return false;
}
} else {
- /* If name ends in * then allow partial matches. */
+ // If name ends in * then allow partial matches.
if (prefix[len - 1] == '*') {
return !strncmp(prefix, path, len - 1);
}
@@ -314,7 +315,7 @@
ALOGE("%s len is corrupted", conf[which][dir]);
break;
}
- prefix = calloc(1, remainder);
+ prefix = static_cast<char*>(calloc(1, remainder));
if (!prefix) {
ALOGE("%s out of memory", conf[which][dir]);
break;
@@ -325,7 +326,7 @@
break;
}
len = strnlen(prefix, remainder);
- if (len >= remainder) { /* missing a terminating null */
+ if (len >= remainder) { // missing a terminating null
free(prefix);
ALOGE("%s is corrupted", conf[which][dir]);
break;
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index bbba853..fdead23 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -53,7 +53,7 @@
#include <sys/cdefs.h>
#include <sys/types.h>
-#if defined(__ANDROID__)
+#if defined(__BIONIC__)
#include <linux/capability.h>
#else
#include "android_filesystem_capability.h"
diff --git a/libcutils/native_handle.c b/libcutils/native_handle.c
index 9f4840a..95bbc41 100644
--- a/libcutils/native_handle.c
+++ b/libcutils/native_handle.c
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "NativeHandle"
+#include <cutils/native_handle.h>
#include <errno.h>
#include <stdint.h>
@@ -22,15 +22,12 @@
#include <string.h>
#include <unistd.h>
-#include <android/log.h>
-#include <cutils/native_handle.h>
-
static const int kMaxNativeFds = 1024;
static const int kMaxNativeInts = 1024;
-native_handle_t* native_handle_init(char* storage, int numFds, int numInts)
-{
+native_handle_t* native_handle_init(char* storage, int numFds, int numInts) {
if ((uintptr_t) storage % alignof(native_handle_t)) {
+ errno = EINVAL;
return NULL;
}
@@ -38,13 +35,12 @@
handle->version = sizeof(native_handle_t);
handle->numFds = numFds;
handle->numInts = numInts;
-
return handle;
}
-native_handle_t* native_handle_create(int numFds, int numInts)
-{
+native_handle_t* native_handle_create(int numFds, int numInts) {
if (numFds < 0 || numInts < 0 || numFds > kMaxNativeFds || numInts > kMaxNativeInts) {
+ errno = EINVAL;
return NULL;
}
@@ -58,14 +54,13 @@
return h;
}
-native_handle_t* native_handle_clone(const native_handle_t* handle)
-{
+native_handle_t* native_handle_clone(const native_handle_t* handle) {
native_handle_t* clone = native_handle_create(handle->numFds, handle->numInts);
- int i;
+ if (clone == NULL) return NULL;
- for (i = 0; i < handle->numFds; i++) {
+ for (int i = 0; i < handle->numFds; i++) {
clone->data[i] = dup(handle->data[i]);
- if (clone->data[i] < 0) {
+ if (clone->data[i] == -1) {
clone->numFds = i;
native_handle_close(clone);
native_handle_delete(clone);
@@ -74,30 +69,27 @@
}
memcpy(&clone->data[handle->numFds], &handle->data[handle->numFds],
- sizeof(int) * handle->numInts);
+ sizeof(int) * handle->numInts);
return clone;
}
-int native_handle_delete(native_handle_t* h)
-{
+int native_handle_delete(native_handle_t* h) {
if (h) {
- if (h->version != sizeof(native_handle_t))
- return -EINVAL;
+ if (h->version != sizeof(native_handle_t)) return -EINVAL;
free(h);
}
return 0;
}
-int native_handle_close(const native_handle_t* h)
-{
- if (h->version != sizeof(native_handle_t))
- return -EINVAL;
+int native_handle_close(const native_handle_t* h) {
+ if (h->version != sizeof(native_handle_t)) return -EINVAL;
+ int saved_errno = errno;
const int numFds = h->numFds;
- int i;
- for (i=0 ; i<numFds ; i++) {
+ for (int i = 0; i < numFds; ++i) {
close(h->data[i]);
}
+ errno = saved_errno;
return 0;
}
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index a0b1d7b..7884190 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -27,7 +27,8 @@
"test_str_parms.cpp",
"android_get_control_socket_test.cpp",
"android_get_control_file_test.cpp",
- "multiuser_test.cpp"
+ "multiuser_test.cpp",
+ "fs_config.cpp",
],
},
diff --git a/libcutils/tests/AshmemTest.cpp b/libcutils/tests/AshmemTest.cpp
index 51c679f..a87e23e 100644
--- a/libcutils/tests/AshmemTest.cpp
+++ b/libcutils/tests/AshmemTest.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-#include <sys/mman.h>
+#include <android-base/unique_fd.h>
#include <cutils/ashmem.h>
#include <gtest/gtest.h>
-#include <android-base/unique_fd.h>
+#include <linux/fs.h>
+#include <sys/mman.h>
using android::base::unique_fd;
@@ -29,8 +30,8 @@
ASSERT_EQ(0, ashmem_set_prot_region(fd, prot));
}
-void TestMmap(const unique_fd &fd, size_t size, int prot, void **region) {
- *region = mmap(nullptr, size, prot, MAP_SHARED, fd, 0);
+void TestMmap(const unique_fd& fd, size_t size, int prot, void** region, off_t off = 0) {
+ *region = mmap(nullptr, size, prot, MAP_SHARED, fd, off);
ASSERT_NE(MAP_FAILED, *region);
}
@@ -38,6 +39,10 @@
EXPECT_EQ(MAP_FAILED, mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
}
+void TestProtIs(const unique_fd& fd, int prot) {
+ EXPECT_EQ(prot, ioctl(fd, ASHMEM_GET_PROT_MASK));
+}
+
void FillData(uint8_t* data, size_t dataLen) {
for (size_t i = 0; i < dataLen; i++) {
data[i] = i & 0xFF;
@@ -101,6 +106,63 @@
EXPECT_EQ(0, munmap(region2, size));
}
+TEST(AshmemTest, FileOperationsTest) {
+ unique_fd fd;
+ void* region;
+
+ // Allocate a 4-page buffer, but leave page-sized holes on either side
+ constexpr size_t size = PAGE_SIZE * 4;
+ constexpr size_t dataSize = PAGE_SIZE * 2;
+ constexpr size_t holeSize = PAGE_SIZE;
+ ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
+ ASSERT_NO_FATAL_FAILURE(TestMmap(fd, dataSize, PROT_READ | PROT_WRITE, ®ion, holeSize));
+
+ uint8_t data[dataSize];
+ FillData(data, dataSize);
+ memcpy(region, data, dataSize);
+
+ constexpr off_t dataStart = holeSize;
+ constexpr off_t dataEnd = dataStart + dataSize;
+
+ // The sequence of seeks below looks something like this:
+ //
+ // [ ][data][data][ ]
+ // --^ lseek(99, SEEK_SET)
+ // ------^ lseek(dataStart, SEEK_CUR)
+ // ------^ lseek(0, SEEK_DATA)
+ // ------------^ lseek(dataStart, SEEK_HOLE)
+ // ^-- lseek(-99, SEEK_END)
+ // ^------ lseek(-dataStart, SEEK_CUR)
+ const struct {
+ // lseek() parameters
+ off_t offset;
+ int whence;
+ // Expected lseek() return value
+ off_t ret;
+ } seeks[] = {
+ {99, SEEK_SET, 99}, {dataStart, SEEK_CUR, dataStart + 99},
+ {0, SEEK_DATA, dataStart}, {dataStart, SEEK_HOLE, dataEnd},
+ {-99, SEEK_END, size - 99}, {-dataStart, SEEK_CUR, dataEnd - 99},
+ };
+ for (const auto& cfg : seeks) {
+ errno = 0;
+ auto off = lseek(fd, cfg.offset, cfg.whence);
+ ASSERT_EQ(cfg.ret, off) << "lseek(" << cfg.offset << ", " << cfg.whence << ") failed"
+ << (errno ? ": " : "") << (errno ? strerror(errno) : "");
+
+ if (off >= dataStart && off < dataEnd) {
+ off_t dataOff = off - dataStart;
+ ssize_t readSize = dataSize - dataOff;
+ uint8_t buf[readSize];
+
+ ASSERT_EQ(readSize, TEMP_FAILURE_RETRY(read(fd, buf, readSize)));
+ EXPECT_EQ(0, memcmp(buf, data + dataOff, readSize));
+ }
+ }
+
+ EXPECT_EQ(0, munmap(region, dataSize));
+}
+
TEST(AshmemTest, ProtTest) {
unique_fd fd;
constexpr size_t size = PAGE_SIZE;
@@ -108,13 +170,25 @@
ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ));
TestProtDenied(fd, size, PROT_WRITE);
+ TestProtIs(fd, PROT_READ);
ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ, ®ion));
EXPECT_EQ(0, munmap(region, size));
ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_WRITE));
TestProtDenied(fd, size, PROT_READ);
+ TestProtIs(fd, PROT_WRITE);
ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_WRITE, ®ion));
EXPECT_EQ(0, munmap(region, size));
+
+ ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
+ TestProtIs(fd, PROT_READ | PROT_WRITE);
+ ASSERT_EQ(0, ashmem_set_prot_region(fd, PROT_READ));
+ errno = 0;
+ ASSERT_EQ(-1, ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE))
+ << "kernel shouldn't allow adding protection bits";
+ EXPECT_EQ(EINVAL, errno);
+ TestProtIs(fd, PROT_READ);
+ TestProtDenied(fd, size, PROT_WRITE);
}
TEST(AshmemTest, ForkProtTest) {
diff --git a/libcutils/tests/fs_config.cpp b/libcutils/tests/fs_config.cpp
new file mode 100644
index 0000000..3917a0b
--- /dev/null
+++ b/libcutils/tests/fs_config.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <android-base/strings.h>
+
+#include <private/android_filesystem_config.h>
+
+extern const struct fs_path_config* __for_testing_only__android_dirs;
+extern const struct fs_path_config* __for_testing_only__android_files;
+
+static void check_one(const struct fs_path_config* paths, const std::string& prefix,
+ const std::string& alternate) {
+ for (size_t idx = 0; paths[idx].prefix; ++idx) {
+ std::string path(paths[idx].prefix);
+ if (android::base::StartsWith(path, prefix.c_str())) {
+ path = alternate + path.substr(prefix.length());
+ size_t second;
+ for (second = 0; paths[second].prefix; ++second) {
+ if (path == paths[second].prefix) break;
+ }
+ if (!paths[second].prefix) {
+ // guaranteed to fail expectations, trigger test failure with
+ // a message that reports the violation as an inequality.
+ EXPECT_STREQ((prefix + path.substr(alternate.length())).c_str(), path.c_str());
+ }
+ }
+ }
+}
+
+static void check_two(const struct fs_path_config* paths, const std::string& prefix) {
+ ASSERT_FALSE(paths == nullptr);
+ std::string alternate = "system/" + prefix;
+ check_one(paths, prefix, alternate);
+ check_one(paths, alternate, prefix);
+}
+
+TEST(fs_config, vendor_dirs_alias) {
+ check_two(__for_testing_only__android_dirs, "vendor/");
+}
+
+TEST(fs_config, vendor_files_alias) {
+ check_two(__for_testing_only__android_files, "vendor/");
+}
+
+TEST(fs_config, oem_dirs_alias) {
+ check_two(__for_testing_only__android_dirs, "oem/");
+}
+
+TEST(fs_config, oem_files_alias) {
+ check_two(__for_testing_only__android_files, "oem/");
+}
+
+TEST(fs_config, odm_dirs_alias) {
+ check_two(__for_testing_only__android_dirs, "odm/");
+}
+
+TEST(fs_config, odm_files_alias) {
+ check_two(__for_testing_only__android_files, "odm/");
+}
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/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 0e6432c..ab96429 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -55,6 +55,7 @@
-fno-builtin \
test_src_files := \
+ libc_test.cpp \
liblog_test_default.cpp \
liblog_test_local.cpp \
liblog_test_stderr.cpp \
@@ -65,14 +66,6 @@
log_system_test.cpp \
log_time_test.cpp
-# to prevent breaking the build if bionic not relatively visible to us
-ifneq ($(wildcard $(LOCAL_PATH)/../../../../bionic/libc/bionic/libc_logging.cpp),)
-
-test_src_files += \
- libc_test.cpp
-
-endif
-
# Build tests for the device (with .so). Run with:
# adb shell /data/nativetest/liblog-unit-tests/liblog-unit-tests
include $(CLEAR_VARS)
diff --git a/libmemunreachable/.clang-format b/libmemunreachable/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libmemunreachable/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 4662368..cdac76b 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -9,8 +9,16 @@
clang: true,
shared_libs: [
"libbase",
- "liblog",
],
+
+ target: {
+ android: {
+ static_libs: ["libasync_safe"],
+ },
+ host: {
+ shared_libs: ["liblog"],
+ }
+ },
}
cc_library_shared {
@@ -30,7 +38,6 @@
static_libs: [
"libc_malloc_debug_backtrace",
- "libc_logging",
],
// Only need this for arm since libc++ uses its own unwind code that
// doesn't mix with the other default unwind code.
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 62366f2..c365ae5 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -42,11 +42,9 @@
} else {
Range overlap = inserted.first->first;
if (overlap != range) {
- ALOGE("range %p-%p overlaps with existing range %p-%p",
- reinterpret_cast<void*>(begin),
- reinterpret_cast<void*>(end),
- reinterpret_cast<void*>(overlap.begin),
- reinterpret_cast<void*>(overlap.end));
+ MEM_ALOGE("range %p-%p overlaps with existing range %p-%p", reinterpret_cast<void*>(begin),
+ reinterpret_cast<void*>(end), reinterpret_cast<void*>(overlap.begin),
+ reinterpret_cast<void*>(overlap.end));
}
return false;
}
@@ -154,7 +152,7 @@
void* ret = mmap(page, page_size, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
if (ret == MAP_FAILED) {
- ALOGE("failed to map page at %p: %s", page, strerror(errno));
+ MEM_ALOGE("failed to map page at %p: %s", page, strerror(errno));
return false;
}
@@ -167,7 +165,7 @@
handler.reset();
return;
}
- ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+ MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
if (!MapOverPage(si->si_addr)) {
handler.reset();
}
diff --git a/libmemunreachable/LeakPipe.cpp b/libmemunreachable/LeakPipe.cpp
index 080f8a7..78117e2 100644
--- a/libmemunreachable/LeakPipe.cpp
+++ b/libmemunreachable/LeakPipe.cpp
@@ -44,11 +44,11 @@
int ret = sendmsg(sock, &hdr, 0);
if (ret < 0) {
- ALOGE("failed to send fd: %s", strerror(errno));
+ MEM_ALOGE("failed to send fd: %s", strerror(errno));
return false;
}
if (ret == 0) {
- ALOGE("eof when sending fd");
+ MEM_ALOGE("eof when sending fd");
return false;
}
@@ -71,17 +71,17 @@
int ret = recvmsg(sock, &hdr, 0);
if (ret < 0) {
- ALOGE("failed to receive fd: %s", strerror(errno));
+ MEM_ALOGE("failed to receive fd: %s", strerror(errno));
return -1;
}
if (ret == 0) {
- ALOGE("eof when receiving fd");
+ MEM_ALOGE("eof when receiving fd");
return -1;
}
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
- ALOGE("missing fd while receiving fd");
+ MEM_ALOGE("missing fd while receiving fd");
return -1;
}
diff --git a/libmemunreachable/LeakPipe.h b/libmemunreachable/LeakPipe.h
index 3f4e0b7..3ea2d8f 100644
--- a/libmemunreachable/LeakPipe.h
+++ b/libmemunreachable/LeakPipe.h
@@ -36,7 +36,7 @@
LeakPipe() {
int ret = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv_);
if (ret < 0) {
- LOG_ALWAYS_FATAL("failed to create socketpair: %s", strerror(errno));
+ MEM_LOG_ALWAYS_FATAL("failed to create socketpair: %s", strerror(errno));
}
}
@@ -105,10 +105,10 @@
bool Send(const T& value) {
ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, &value, sizeof(T)));
if (ret < 0) {
- ALOGE("failed to send value: %s", strerror(errno));
+ MEM_ALOGE("failed to send value: %s", strerror(errno));
return false;
} else if (static_cast<size_t>(ret) != sizeof(T)) {
- ALOGE("eof while writing value");
+ MEM_ALOGE("eof while writing value");
return false;
}
@@ -124,10 +124,10 @@
ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, vector.data(), size));
if (ret < 0) {
- ALOGE("failed to send vector: %s", strerror(errno));
+ MEM_ALOGE("failed to send vector: %s", strerror(errno));
return false;
} else if (static_cast<size_t>(ret) != size) {
- ALOGE("eof while writing vector");
+ MEM_ALOGE("eof while writing vector");
return false;
}
@@ -143,10 +143,10 @@
bool Receive(T* value) {
ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, reinterpret_cast<void*>(value), sizeof(T)));
if (ret < 0) {
- ALOGE("failed to receive value: %s", strerror(errno));
+ MEM_ALOGE("failed to receive value: %s", strerror(errno));
return false;
} else if (static_cast<size_t>(ret) != sizeof(T)) {
- ALOGE("eof while receiving value");
+ MEM_ALOGE("eof while receiving value");
return false;
}
@@ -166,10 +166,10 @@
while (size > 0) {
ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, ptr, size));
if (ret < 0) {
- ALOGE("failed to send vector: %s", strerror(errno));
+ MEM_ALOGE("failed to send vector: %s", strerror(errno));
return false;
} else if (ret == 0) {
- ALOGE("eof while reading vector");
+ MEM_ALOGE("eof while reading vector");
return false;
}
size -= ret;
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index ac19a66..e7c0beb 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -78,51 +78,49 @@
bool MemUnreachable::CollectAllocations(const allocator::vector<ThreadInfo>& threads,
const allocator::vector<Mapping>& mappings) {
- ALOGI("searching process %d for allocations", pid_);
+ MEM_ALOGI("searching process %d for allocations", pid_);
allocator::vector<Mapping> heap_mappings{mappings};
allocator::vector<Mapping> anon_mappings{mappings};
allocator::vector<Mapping> globals_mappings{mappings};
allocator::vector<Mapping> stack_mappings{mappings};
- if (!ClassifyMappings(mappings, heap_mappings, anon_mappings,
- globals_mappings, stack_mappings)) {
+ if (!ClassifyMappings(mappings, heap_mappings, anon_mappings, globals_mappings, stack_mappings)) {
return false;
}
for (auto it = heap_mappings.begin(); it != heap_mappings.end(); it++) {
- ALOGV("Heap mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
- HeapIterate(*it, [&](uintptr_t base, size_t size) {
- heap_walker_.Allocation(base, base + size);
- });
+ MEM_ALOGV("Heap mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
+ HeapIterate(*it,
+ [&](uintptr_t base, size_t size) { heap_walker_.Allocation(base, base + size); });
}
for (auto it = anon_mappings.begin(); it != anon_mappings.end(); it++) {
- ALOGV("Anon mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
+ MEM_ALOGV("Anon mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
heap_walker_.Allocation(it->begin, it->end);
}
for (auto it = globals_mappings.begin(); it != globals_mappings.end(); it++) {
- ALOGV("Globals mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
+ MEM_ALOGV("Globals mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
heap_walker_.Root(it->begin, it->end);
}
for (auto thread_it = threads.begin(); thread_it != threads.end(); thread_it++) {
for (auto it = stack_mappings.begin(); it != stack_mappings.end(); it++) {
if (thread_it->stack.first >= it->begin && thread_it->stack.first <= it->end) {
- ALOGV("Stack %" PRIxPTR "-%" PRIxPTR " %s", thread_it->stack.first, it->end, it->name);
+ MEM_ALOGV("Stack %" PRIxPTR "-%" PRIxPTR " %s", thread_it->stack.first, it->end, it->name);
heap_walker_.Root(thread_it->stack.first, it->end);
}
}
heap_walker_.Root(thread_it->regs);
}
- ALOGI("searching done");
+ MEM_ALOGI("searching done");
return true;
}
bool MemUnreachable::GetUnreachableMemory(allocator::vector<Leak>& leaks,
size_t limit, size_t* num_leaks, size_t* leak_bytes) {
- ALOGI("sweeping process %d for unreachable memory", pid_);
+ MEM_ALOGI("sweeping process %d for unreachable memory", pid_);
leaks.clear();
if (!heap_walker_.DetectLeaks()) {
@@ -133,9 +131,9 @@
allocator::vector<Range> leaked1{allocator_};
heap_walker_.Leaked(leaked1, 0, num_leaks, leak_bytes);
- ALOGI("sweeping done");
+ MEM_ALOGI("sweeping done");
- ALOGI("folding related leaks");
+ MEM_ALOGI("folding related leaks");
LeakFolding folding(allocator_, heap_walker_);
if (!folding.FoldLeaks()) {
@@ -188,7 +186,7 @@
std::min(leak->size, Leak::contents_length));
}
- ALOGI("folding done");
+ MEM_ALOGI("folding done");
std::sort(leaks.begin(), leaks.end(), [](const Leak& a, const Leak& b) {
return a.total_size > b.total_size;
@@ -276,7 +274,7 @@
/////////////////////////////////////////////
// Collection thread
/////////////////////////////////////////////
- ALOGI("collecting thread info for process %d...", parent_pid);
+ MEM_ALOGI("collecting thread info for process %d...", parent_pid);
ThreadCapture thread_capture(parent_pid, heap);
allocator::vector<ThreadInfo> thread_info(heap);
@@ -351,7 +349,7 @@
} else {
// Nothing left to do in the collection thread, return immediately,
// releasing all the captured threads.
- ALOGI("collection thread done");
+ MEM_ALOGI("collection thread done");
return 0;
}
}};
@@ -397,10 +395,10 @@
return false;
}
- ALOGI("unreachable memory detection done");
- ALOGE("%zu bytes in %zu allocation%s unreachable out of %zu bytes in %zu allocation%s",
- info.leak_bytes, info.num_leaks, plural(info.num_leaks),
- info.allocation_bytes, info.num_allocations, plural(info.num_allocations));
+ MEM_ALOGI("unreachable memory detection done");
+ MEM_ALOGE("%zu bytes in %zu allocation%s unreachable out of %zu bytes in %zu allocation%s",
+ info.leak_bytes, info.num_leaks, plural(info.num_leaks), info.allocation_bytes,
+ info.num_allocations, plural(info.num_allocations));
return true;
}
@@ -517,7 +515,7 @@
}
for (auto it = info.leaks.begin(); it != info.leaks.end(); it++) {
- ALOGE("%s", it->ToString(log_contents).c_str());
+ MEM_ALOGE("%s", it->ToString(log_contents).c_str());
}
return true;
}
diff --git a/libmemunreachable/PtracerThread.cpp b/libmemunreachable/PtracerThread.cpp
index 4e3c41e..73b0493 100644
--- a/libmemunreachable/PtracerThread.cpp
+++ b/libmemunreachable/PtracerThread.cpp
@@ -70,7 +70,7 @@
child_pid_(0) {
stack_ = std::make_unique<Stack>(PTHREAD_STACK_MIN);
if (stack_->top() == nullptr) {
- LOG_ALWAYS_FATAL("failed to mmap child stack: %s", strerror(errno));
+ MEM_LOG_ALWAYS_FATAL("failed to mmap child stack: %s", strerror(errno));
}
func_ = std::function<int()>{[&, func]() -> int {
@@ -102,7 +102,7 @@
CLONE_VM|CLONE_FS|CLONE_FILES/*|CLONE_UNTRACED*/,
reinterpret_cast<void*>(&func_));
if (child_pid_ < 0) {
- ALOGE("failed to clone child: %s", strerror(errno));
+ MEM_ALOGE("failed to clone child: %s", strerror(errno));
return false;
}
@@ -120,7 +120,7 @@
int status;
int ret = TEMP_FAILURE_RETRY(waitpid(child_pid_, &status, __WALL));
if (ret < 0) {
- ALOGE("waitpid %d failed: %s", child_pid_, strerror(errno));
+ MEM_ALOGE("waitpid %d failed: %s", child_pid_, strerror(errno));
return -1;
}
@@ -131,7 +131,7 @@
} else if (WIFSIGNALED(status)) {
return -WTERMSIG(status);
} else {
- ALOGE("unexpected status %x", status);
+ MEM_ALOGE("unexpected status %x", status);
return -1;
}
}
diff --git a/libmemunreachable/ScopedPipe.h b/libmemunreachable/ScopedPipe.h
index 9beef9a..7f44953 100644
--- a/libmemunreachable/ScopedPipe.h
+++ b/libmemunreachable/ScopedPipe.h
@@ -26,7 +26,7 @@
ScopedPipe() : pipefd_{-1, -1} {
int ret = pipe2(pipefd_, O_CLOEXEC);
if (ret < 0) {
- LOG_ALWAYS_FATAL("failed to open pipe");
+ MEM_LOG_ALWAYS_FATAL("failed to open pipe");
}
}
~ScopedPipe() {
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index 1fd9d4d..ada2ae4 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -37,22 +37,18 @@
template <class F>
void install(int signal, F&& f) {
- LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
+ MEM_LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
handler_ = SignalFn(std::allocator_arg, allocator_,
- [=](int signal, siginfo_t* si, void* uctx) {
- f(*this, signal, si, uctx);
- });
+ [=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
- struct sigaction act{};
- act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) {
- handler_(signal, si, uctx);
- };
+ struct sigaction act {};
+ act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) { handler_(signal, si, uctx); };
act.sa_flags = SA_SIGINFO;
int ret = sigaction(signal, &act, &old_act_);
if (ret < 0) {
- LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
+ MEM_LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
}
signal_ = signal;
@@ -62,7 +58,7 @@
if (signal_ != -1) {
int ret = sigaction(signal_, &old_act_, NULL);
if (ret < 0) {
- ALOGE("failed to uninstall segfault handler");
+ MEM_ALOGE("failed to uninstall segfault handler");
}
handler_ = SignalFn{};
signal_ = -1;
diff --git a/libmemunreachable/ThreadCapture.cpp b/libmemunreachable/ThreadCapture.cpp
index 9155c29..3891f2d 100644
--- a/libmemunreachable/ThreadCapture.cpp
+++ b/libmemunreachable/ThreadCapture.cpp
@@ -110,7 +110,7 @@
android::base::unique_fd fd(open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
if (fd == -1) {
- ALOGE("failed to open %s: %s", path, strerror(errno));
+ MEM_ALOGE("failed to open %s: %s", path, strerror(errno));
return false;
}
@@ -126,7 +126,7 @@
do {
nread = syscall(SYS_getdents64, fd.get(), dirent_buf, sizeof(dirent_buf));
if (nread < 0) {
- ALOGE("failed to get directory entries from %s: %s", path, strerror(errno));
+ MEM_ALOGE("failed to get directory entries from %s: %s", path, strerror(errno));
return false;
} else if (nread > 0) {
ssize_t off = 0;
@@ -177,8 +177,7 @@
void ThreadCaptureImpl::PtraceDetach(pid_t tid, unsigned int signal) {
void* sig_ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(signal));
if (ptrace(PTRACE_DETACH, tid, NULL, sig_ptr) < 0 && errno != ESRCH) {
- ALOGE("failed to detach from thread %d of process %d: %s", tid, pid_,
- strerror(errno));
+ MEM_ALOGE("failed to detach from thread %d of process %d: %s", tid, pid_, strerror(errno));
}
}
@@ -187,8 +186,7 @@
int ThreadCaptureImpl::PtraceAttach(pid_t tid) {
int ret = ptrace(PTRACE_SEIZE, tid, NULL, NULL);
if (ret < 0) {
- ALOGE("failed to attach to thread %d of process %d: %s", tid, pid_,
- strerror(errno));
+ MEM_ALOGE("failed to attach to thread %d of process %d: %s", tid, pid_, strerror(errno));
return -1;
}
@@ -200,8 +198,7 @@
if (errno == ESRCH) {
return 0;
} else {
- ALOGE("failed to interrupt thread %d of process %d: %s", tid, pid_,
- strerror(errno));
+ MEM_ALOGE("failed to interrupt thread %d of process %d: %s", tid, pid_, strerror(errno));
PtraceDetach(tid, 0);
return -1;
}
@@ -219,8 +216,7 @@
iovec.iov_len = sizeof(regs);
if (ptrace(PTRACE_GETREGSET, tid, reinterpret_cast<void*>(NT_PRSTATUS), &iovec)) {
- ALOGE("ptrace getregset for thread %d of process %d failed: %s",
- tid, pid_, strerror(errno));
+ MEM_ALOGE("ptrace getregset for thread %d of process %d failed: %s", tid, pid_, strerror(errno));
return false;
}
@@ -258,15 +254,13 @@
int status = 0;
if (TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL)) < 0) {
- ALOGE("failed to wait for pause of thread %d of process %d: %s", tid, pid_,
- strerror(errno));
+ MEM_ALOGE("failed to wait for pause of thread %d of process %d: %s", tid, pid_, strerror(errno));
PtraceDetach(tid, 0);
return -1;
}
if (!WIFSTOPPED(status)) {
- ALOGE("thread %d of process %d was not paused after waitpid, killed?",
- tid, pid_);
+ MEM_ALOGE("thread %d of process %d was not paused after waitpid, killed?", tid, pid_);
return 0;
}
@@ -285,8 +279,8 @@
// normal ptrace interrupt stop
break;
default:
- ALOGE("unexpected signal %d with PTRACE_EVENT_STOP for thread %d of process %d",
- signal, tid, pid_);
+ MEM_ALOGE("unexpected signal %d with PTRACE_EVENT_STOP for thread %d of process %d", signal,
+ tid, pid_);
return -1;
}
} else {
diff --git a/libmemunreachable/log.h b/libmemunreachable/log.h
index cdfbfd9..1725c53 100644
--- a/libmemunreachable/log.h
+++ b/libmemunreachable/log.h
@@ -19,6 +19,32 @@
#define LOG_TAG "libmemunreachable"
+#if defined(__ANDROID__)
+
+#include <async_safe/log.h>
+
+#define MEM_ALOGE(...) async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, ##__VA_ARGS__)
+#define MEM_ALOGW(...) async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, ##__VA_ARGS__)
+#define MEM_ALOGI(...) async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, ##__VA_ARGS__)
+#define MEM_ALOGV(...) async_safe_format_log(ANDROID_LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+
+#define MEM_LOG_ALWAYS_FATAL(...) async_safe_fatal(__VA_ARGS__)
+
+#define MEM_LOG_ALWAYS_FATAL_IF(cond, ...) \
+ ((__predict_false(cond)) ? async_safe_fatal(__VA_ARGS__) : (void)0)
+
+#else
+
#include <log/log.h>
+#define MEM_ALOGW ALOGW
+#define MEM_ALOGE ALOGE
+#define MEM_ALOGV ALOGV
+#define MEM_ALOGI ALOGI
+
+#define MEM_LOG_ALWAYS_FATAL LOG_ALWAYS_FATAL
+#define MEM_LOG_ALWAYS_FATAL_IF LOG_ALWAYS_FATAL_IF
+
+#endif
+
#endif // LIBMEMUNREACHABLE_LOG_H_
diff --git a/libmemunreachable/tests/DisableMalloc_test.cpp b/libmemunreachable/tests/DisableMalloc_test.cpp
index ea5c22c..4e6155b 100644
--- a/libmemunreachable/tests/DisableMalloc_test.cpp
+++ b/libmemunreachable/tests/DisableMalloc_test.cpp
@@ -74,7 +74,7 @@
{
alarm(100ms);
ScopedDisableMalloc disable_malloc;
- char* ptr = new(char);
+ char* ptr = new (std::nothrow)(char);
ASSERT_NE(ptr, nullptr);
delete(ptr);
}
@@ -89,6 +89,8 @@
alarm(250ms);
ScopedDisableMalloc disable_malloc;
delete(ptr);
+ // Force ptr usage or this code gets optimized away by the arm64 compiler.
+ ASSERT_NE(ptr, nullptr);
}
}, "");
}
diff --git a/libmemunreachable/tests/MemUnreachable_test.cpp b/libmemunreachable/tests/MemUnreachable_test.cpp
index 2ae3db8..71da365 100644
--- a/libmemunreachable/tests/MemUnreachable_test.cpp
+++ b/libmemunreachable/tests/MemUnreachable_test.cpp
@@ -23,8 +23,6 @@
#include <memunreachable/memunreachable.h>
-void* ptr;
-
class HiddenPointer {
public:
explicit HiddenPointer(size_t size = 256) {
@@ -92,10 +90,12 @@
}
}
+void* g_ptr;
+
TEST(MemunreachableTest, global) {
HiddenPointer hidden_ptr;
- ptr = hidden_ptr.Get();
+ g_ptr = hidden_ptr.Get();
{
UnreachableMemoryInfo info;
@@ -104,7 +104,7 @@
ASSERT_EQ(0U, info.leaks.size());
}
- ptr = NULL;
+ g_ptr = nullptr;
{
UnreachableMemoryInfo info;
@@ -126,7 +126,7 @@
TEST(MemunreachableTest, tls) {
HiddenPointer hidden_ptr;
pthread_key_t key;
- pthread_key_create(&key, NULL);
+ pthread_key_create(&key, nullptr);
pthread_setspecific(key, hidden_ptr.Get());
diff --git a/libmemunreachable/tests/ThreadCapture_test.cpp b/libmemunreachable/tests/ThreadCapture_test.cpp
index 41ed84e..44aabd7 100644
--- a/libmemunreachable/tests/ThreadCapture_test.cpp
+++ b/libmemunreachable/tests/ThreadCapture_test.cpp
@@ -55,7 +55,7 @@
threads_.reserve(threads);
tids_.reserve(threads);
for (unsigned int i = 0; i < threads; i++) {
- threads_.emplace_back([&, i, threads, this]() {
+ threads_.emplace_back([&, threads, this]() {
{
std::lock_guard<std::mutex> lk(m_);
tids_.push_back(gettid());
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 5fb56f2..377b7dd 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -22,3 +22,5 @@
},
},
}
+
+subdirs = ["tests"]
\ No newline at end of file
diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp
new file mode 100644
index 0000000..efd3978
--- /dev/null
+++ b/libnativebridge/tests/Android.bp
@@ -0,0 +1,53 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+ name: "libnativebridge-dummy-defaults",
+
+ host_supported: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ cppflags: ["-fvisibility=protected"],
+ target: {
+ android: {
+ shared_libs: ["libdl"],
+ },
+ host: {
+ host_ldlibs: ["-ldl"],
+ },
+ },
+}
+
+cc_library_shared {
+ name: "libnativebridge-dummy",
+ srcs: ["DummyNativeBridge.cpp"],
+ defaults: ["libnativebridge-dummy-defaults"],
+}
+
+cc_library_shared {
+ name: "libnativebridge2-dummy",
+ srcs: ["DummyNativeBridge2.cpp"],
+ defaults: ["libnativebridge-dummy-defaults"],
+}
+
+cc_library_shared {
+ name: "libnativebridge3-dummy",
+ srcs: ["DummyNativeBridge3.cpp"],
+ defaults: ["libnativebridge-dummy-defaults"],
+}
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index c9468f0..70b3fcc 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -1,8 +1,6 @@
# Build the unit tests.
LOCAL_PATH := $(call my-dir)
-include $(LOCAL_PATH)/Android.nativebridge-dummy.mk
-
include $(CLEAR_VARS)
# Build the unit tests.
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
deleted file mode 100644
index 2d78be0..0000000
--- a/libnativebridge/tests/Android.nativebridge-dummy.mk
+++ /dev/null
@@ -1,108 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-NATIVE_BRIDGE_COMMON_SRC_FILES := \
- DummyNativeBridge.cpp
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_SHARED_LIBRARIES := libdl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-# v2.
-
-NATIVE_BRIDGE2_COMMON_SRC_FILES := \
- DummyNativeBridge2.cpp
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge2-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_SHARED_LIBRARIES := libdl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge2-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-# v3.
-
-NATIVE_BRIDGE3_COMMON_SRC_FILES := \
- DummyNativeBridge3.cpp
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge3-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge3-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
diff --git a/libnativeloader/include/nativeloader/dlext_namespaces.h b/libnativeloader/include/nativeloader/dlext_namespaces.h
index ac64f71..9121277 100644
--- a/libnativeloader/include/nativeloader/dlext_namespaces.h
+++ b/libnativeloader/include/nativeloader/dlext_namespaces.h
@@ -55,6 +55,12 @@
* permitted_path from the caller's namespace.
*/
ANDROID_NAMESPACE_TYPE_SHARED = 2,
+
+ /* This flag instructs linker to enable grey-list workaround for the namespace.
+ * See http://b/26394120 for details.
+ */
+ ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000,
+
ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
ANDROID_NAMESPACE_TYPE_ISOLATED,
};
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index f3391d1..d9cb90d 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -99,6 +99,7 @@
LibraryNamespaces() : initialized_(false) { }
bool Create(JNIEnv* env,
+ uint32_t target_sdk_version,
jobject class_loader,
bool is_shared,
jstring java_library_path,
@@ -141,6 +142,10 @@
namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
}
+ if (target_sdk_version < 24) {
+ namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
+ }
+
NativeLoaderNamespace parent_ns;
bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
@@ -397,12 +402,12 @@
jstring library_path,
jstring permitted_path) {
#if defined(__ANDROID__)
- UNUSED(target_sdk_version);
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
std::string error_msg;
NativeLoaderNamespace ns;
bool success = g_namespaces->Create(env,
+ target_sdk_version,
class_loader,
is_shared,
library_path,
@@ -439,7 +444,14 @@
if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
- if (!g_namespaces->Create(env, class_loader, false, library_path, nullptr, &ns, error_msg)) {
+ if (!g_namespaces->Create(env,
+ target_sdk_version,
+ class_loader,
+ false,
+ library_path,
+ nullptr,
+ &ns,
+ error_msg)) {
return nullptr;
}
}
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 47f6ff3..f0c3795 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -22,8 +22,13 @@
__BEGIN_DECLS
+// Return 0 and removes the cgroup if there are no longer any processes in it.
+// Returns -1 in the case of an error occurring or if there are processes still running
+// even after retrying for up to 200ms.
int killProcessGroup(uid_t uid, int initialPid, int signal);
+// Returns the same as killProcessGroup(), however it does not retry, which means
+// that it only returns 0 in the case that the cgroup exists and it contains no processes.
int killProcessGroupOnce(uid_t uid, int initialPid, int signal);
int createProcessGroup(uid_t uid, int initialPid);
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 1572cb3..27b4065 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -34,6 +34,7 @@
#include <thread>
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include <private/android_filesystem_config.h>
#include <processgroup/processgroup.h>
@@ -64,12 +65,27 @@
std::once_flag init_path_flag;
-struct ctx {
- bool initialized;
- int fd;
- char buf[128];
- char *buf_ptr;
- size_t buf_len;
+class ProcessGroup {
+ public:
+ ProcessGroup() : buf_ptr_(buf_), buf_len_(0) {}
+
+ bool Open(uid_t uid, int pid);
+
+ // Return positive number and sets *pid = next pid in process cgroup on success
+ // Returns 0 if there are no pids left in the process cgroup
+ // Returns -errno if an error was encountered
+ int GetOneAppProcess(pid_t* pid);
+
+ private:
+ // Returns positive number of bytes filled on success
+ // Returns 0 if there was nothing to read
+ // Returns -errno if an error was encountered
+ int RefillBuffer();
+
+ android::base::unique_fd fd_;
+ char buf_[128];
+ char* buf_ptr_;
+ size_t buf_len_;
};
static const char* getCgroupRootPath() {
@@ -105,87 +121,67 @@
pid);
}
-static int initCtx(uid_t uid, int pid, struct ctx *ctx)
-{
- int ret;
+bool ProcessGroup::Open(uid_t uid, int pid) {
char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
convertUidPidToPath(path, sizeof(path), uid, pid);
strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
int fd = open(path, O_RDONLY);
- if (fd < 0) {
- ret = -errno;
- PLOG(WARNING) << "failed to open " << path;
- return ret;
- }
+ if (fd < 0) return false;
- ctx->fd = fd;
- ctx->buf_ptr = ctx->buf;
- ctx->buf_len = 0;
- ctx->initialized = true;
+ fd_.reset(fd);
LOG(VERBOSE) << "Initialized context for " << path;
- return 0;
+ return true;
}
-static int refillBuffer(struct ctx *ctx)
-{
- memmove(ctx->buf, ctx->buf_ptr, ctx->buf_len);
- ctx->buf_ptr = ctx->buf;
+int ProcessGroup::RefillBuffer() {
+ memmove(buf_, buf_ptr_, buf_len_);
+ buf_ptr_ = buf_;
- ssize_t ret = read(ctx->fd, ctx->buf_ptr + ctx->buf_len,
- sizeof(ctx->buf) - ctx->buf_len - 1);
+ ssize_t ret = read(fd_, buf_ptr_ + buf_len_, sizeof(buf_) - buf_len_ - 1);
if (ret < 0) {
return -errno;
} else if (ret == 0) {
return 0;
}
- ctx->buf_len += ret;
- ctx->buf[ctx->buf_len] = 0;
- LOG(VERBOSE) << "Read " << ret << " to buffer: " << ctx->buf;
+ buf_len_ += ret;
+ buf_[buf_len_] = 0;
+ LOG(VERBOSE) << "Read " << ret << " to buffer: " << buf_;
- assert(ctx->buf_len <= sizeof(ctx->buf));
+ assert(buf_len_ <= sizeof(buf_));
return ret;
}
-static pid_t getOneAppProcess(uid_t uid, int appProcessPid, struct ctx *ctx)
-{
- if (!ctx->initialized) {
- int ret = initCtx(uid, appProcessPid, ctx);
- if (ret < 0) {
- return ret;
- }
- }
+int ProcessGroup::GetOneAppProcess(pid_t* out_pid) {
+ *out_pid = 0;
- char *eptr;
- while ((eptr = (char *)memchr(ctx->buf_ptr, '\n', ctx->buf_len)) == NULL) {
- int ret = refillBuffer(ctx);
- if (ret == 0) {
- return -ERANGE;
- }
- if (ret < 0) {
- return ret;
- }
+ char* eptr;
+ while ((eptr = static_cast<char*>(memchr(buf_ptr_, '\n', buf_len_))) == nullptr) {
+ int ret = RefillBuffer();
+ if (ret <= 0) return ret;
}
*eptr = '\0';
- char *pid_eptr = NULL;
+ char* pid_eptr = nullptr;
errno = 0;
- long pid = strtol(ctx->buf_ptr, &pid_eptr, 10);
+ long pid = strtol(buf_ptr_, &pid_eptr, 10);
if (errno != 0) {
return -errno;
}
if (pid_eptr != eptr) {
- return -EINVAL;
+ errno = EINVAL;
+ return -errno;
}
- ctx->buf_len -= (eptr - ctx->buf_ptr) + 1;
- ctx->buf_ptr = eptr + 1;
+ buf_len_ -= (eptr - buf_ptr_) + 1;
+ buf_ptr_ = eptr + 1;
- return (pid_t)pid;
+ *out_pid = static_cast<pid_t>(pid);
+ return 1;
}
static int removeProcessGroup(uid_t uid, int pid)
@@ -219,8 +215,8 @@
}
snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
- LOG(VERBOSE) << "removing " << path;
- if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << path;
+ LOG(VERBOSE) << "Removing " << path;
+ if (rmdir(path) == -1) PLOG(WARNING) << "Failed to remove " << path;
}
}
}
@@ -231,7 +227,7 @@
const char* cgroup_root_path = getCgroupRootPath();
std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path), closedir);
if (root == NULL) {
- PLOG(ERROR) << "failed to open " << cgroup_root_path;
+ PLOG(ERROR) << "Failed to open " << cgroup_root_path;
} else {
dirent* dir;
while ((dir = readdir(root.get())) != nullptr) {
@@ -246,20 +242,26 @@
snprintf(path, sizeof(path), "%s/%s", cgroup_root_path, dir->d_name);
removeUidProcessGroups(path);
- LOG(VERBOSE) << "removing " << path;
- if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << path;
+ LOG(VERBOSE) << "Removing " << path;
+ if (rmdir(path) == -1) PLOG(WARNING) << "Failed to remove " << path;
}
}
}
+// Returns number of processes killed on success
+// Returns 0 if there are no processes in the process cgroup left to kill
+// Returns -errno on error
static int doKillProcessGroupOnce(uid_t uid, int initialPid, int signal) {
- int processes = 0;
- struct ctx ctx;
+ ProcessGroup process_group;
+ if (!process_group.Open(uid, initialPid)) {
+ PLOG(WARNING) << "Failed to open process cgroup uid " << uid << " pid " << initialPid;
+ return -errno;
+ }
+
+ int ret;
pid_t pid;
-
- ctx.initialized = false;
-
- while ((pid = getOneAppProcess(uid, initialPid, &ctx)) >= 0) {
+ int processes = 0;
+ while ((ret = process_group.GetOneAppProcess(&pid)) > 0 && pid >= 0) {
processes++;
if (pid == 0) {
// Should never happen... but if it does, trying to kill this
@@ -267,55 +269,68 @@
LOG(WARNING) << "Yikes, we've been told to kill pid 0! How about we don't do that?";
continue;
}
- LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid
- << " as part of process group " << initialPid;
+ LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid << " as part of process cgroup "
+ << initialPid;
if (kill(pid, signal) == -1) {
PLOG(WARNING) << "kill(" << pid << ", " << signal << ") failed";
}
}
- if (ctx.initialized) {
- close(ctx.fd);
- }
-
- return processes;
+ return ret >= 0 ? processes : ret;
}
-static int killProcessGroup(uid_t uid, int initialPid, int signal, int retry) {
+static int killProcessGroup(uid_t uid, int initialPid, int signal, int retries) {
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
+ int retry = retries;
int processes;
while ((processes = doKillProcessGroupOnce(uid, initialPid, signal)) > 0) {
- LOG(VERBOSE) << "killed " << processes << " processes for processgroup " << initialPid;
+ LOG(VERBOSE) << "Killed " << processes << " processes for processgroup " << initialPid;
if (retry > 0) {
std::this_thread::sleep_for(5ms);
--retry;
} else {
- LOG(ERROR) << "failed to kill " << processes << " processes for processgroup "
- << initialPid;
break;
}
}
- std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
+ if (processes < 0) {
+ PLOG(ERROR) << "Error encountered killing process cgroup uid " << uid << " pid "
+ << initialPid;
+ return -1;
+ }
+ std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
- LOG(VERBOSE) << "Killed process group uid " << uid << " pid " << initialPid << " in "
- << static_cast<int>(ms) << "ms, " << processes << " procs remain";
+
+ // We only calculate the number of 'processes' when killing the processes.
+ // In the retries == 0 case, we only kill the processes once and therefore
+ // will not have waited then recalculated how many processes are remaining
+ // after the first signals have been sent.
+ // Logging anything regarding the number of 'processes' here does not make sense.
if (processes == 0) {
+ if (retries > 0) {
+ LOG(INFO) << "Successfully killed process cgroup uid " << uid << " pid " << initialPid
+ << " in " << static_cast<int>(ms) << "ms";
+ }
return removeProcessGroup(uid, initialPid);
} else {
+ if (retries > 0) {
+ LOG(ERROR) << "Failed to kill process cgroup uid " << uid << " pid " << initialPid
+ << " in " << static_cast<int>(ms) << "ms, " << processes
+ << " processes remain";
+ }
return -1;
}
}
int killProcessGroup(uid_t uid, int initialPid, int signal) {
- return killProcessGroup(uid, initialPid, signal, 40 /*maxRetry*/);
+ return killProcessGroup(uid, initialPid, signal, 40 /*retries*/);
}
int killProcessGroupOnce(uid_t uid, int initialPid, int signal) {
- return killProcessGroup(uid, initialPid, signal, 0 /*maxRetry*/);
+ return killProcessGroup(uid, initialPid, signal, 0 /*retries*/);
}
static bool mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
@@ -341,14 +356,14 @@
convertUidToPath(path, sizeof(path), uid);
if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
- PLOG(ERROR) << "failed to make and chown " << path;
+ PLOG(ERROR) << "Failed to make and chown " << path;
return -errno;
}
convertUidPidToPath(path, sizeof(path), uid, initialPid);
if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
- PLOG(ERROR) << "failed to make and chown " << path;
+ PLOG(ERROR) << "Failed to make and chown " << path;
return -errno;
}
@@ -357,7 +372,7 @@
int fd = open(path, O_WRONLY);
if (fd == -1) {
int ret = -errno;
- PLOG(ERROR) << "failed to open " << path;
+ PLOG(ERROR) << "Failed to open " << path;
return ret;
}
@@ -367,7 +382,7 @@
int ret = 0;
if (write(fd, pid, len) < 0) {
ret = -errno;
- PLOG(ERROR) << "failed to write '" << pid << "' to " << path;
+ PLOG(ERROR) << "Failed to write '" << pid << "' to " << path;
}
close(fd);
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 709646e..3c0d08d 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -119,14 +119,14 @@
static const char socketName[] = "logdw";
int sock = android_get_control_socket(socketName);
- if (sock < 0) {
+ if (sock < 0) { // logd started up in init.sh
sock = socket_local_server(
socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
- }
- int on = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
- return -1;
+ int on = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
+ return -1;
+ }
}
return sock;
}
diff --git a/logd/logd.rc b/logd/logd.rc
index ee89b83..8804246 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -1,11 +1,11 @@
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
- group logd system readproc
+ group logd system package_info readproc
writepid /dev/cpuset/system-background/tasks
service logd-reinit /system/bin/logd --reinit
diff --git a/logd/main.cpp b/logd/main.cpp
index 18029eb..c8183f0 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -240,23 +240,36 @@
set_sched_policy(0, SP_BACKGROUND);
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
+ // We should drop to AID_LOGD, if we are anything else, we have
+ // even lesser privileges and accept our fate.
+ gid_t groups[] = {
+ AID_SYSTEM, // search access to /data/system path
+ AID_PACKAGE_INFO, // readonly access to /data/system/packages.list
+ };
+ if (setgroups(arraysize(groups), groups) == -1) {
+ android::prdebug(
+ "logd.daemon: failed to set AID_SYSTEM AID_PACKAGE_INFO groups");
+ }
+ if (setgid(AID_LOGD) != 0) {
+ android::prdebug("logd.daemon: failed to set AID_LOGD gid");
+ }
+ if (setuid(AID_LOGD) != 0) {
+ android::prdebug("logd.daemon: failed to set AID_LOGD uid");
+ }
+
cap_t caps = cap_init();
(void)cap_clear(caps);
(void)cap_set_proc(caps);
(void)cap_free(caps);
- // If we are AID_ROOT, we should drop to AID_LOGD+AID_SYSTEM, if we are
- // anything else, we have even lesser privileges and accept our fate. Not
- // worth checking for error returns setting this thread's privileges.
- (void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
- (void)setuid(AID_LOGD); // access to everything logd, eg /data/misc/logd
-
while (reinit_running && !sem_wait(&reinit) && reinit_running) {
// uidToName Privileged Worker
if (uid) {
name = nullptr;
- packagelist_parse(package_list_parser_cb, nullptr);
+ // if we got the perms wrong above, this would spam if we reported
+ // problems with acquisition of an uid name from the packages.
+ (void)packagelist_parse(package_list_parser_cb, nullptr);
uid = 0;
sem_post(&uidName);
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index bd9fa93..f90c9fb 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <ctype.h>
#include <fcntl.h>
#include <inttypes.h>
#include <poll.h>
@@ -26,6 +27,7 @@
#include <string>
+#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <cutils/sockets.h>
@@ -85,7 +87,7 @@
size_t ret = atol(buf) + 1;
if (ret < 4) {
delete[] buf;
- buf = NULL;
+ buf = nullptr;
break;
}
bool check = ret <= len;
@@ -107,7 +109,7 @@
// UID PACKAGE BYTES LINES
// 0 root 54164 147569
//
- char* benchmark = NULL;
+ char* benchmark = nullptr;
do {
static const char signature[] = "\n0 root ";
@@ -122,7 +124,7 @@
benchmark = cp;
#ifdef DEBUG
char* end = strstr(benchmark, "\n");
- if (end == NULL) {
+ if (end == nullptr) {
end = benchmark + strlen(benchmark);
}
fprintf(stderr, "parse for spam counter in \"%.*s\"\n",
@@ -154,7 +156,7 @@
if (value > 10UL) {
break;
}
- benchmark = NULL;
+ benchmark = nullptr;
} while (*cp);
return benchmark;
}
@@ -165,9 +167,14 @@
size_t len;
char* buf;
+ // Drop cache so that any access problems can be discovered.
+ if (!android::base::WriteStringToFile("3\n", "/proc/sys/vm/drop_caches")) {
+ GTEST_LOG_(INFO) << "Could not open trigger dropping inode cache";
+ }
+
alloc_statistics(&buf, &len);
- ASSERT_TRUE(NULL != buf);
+ ASSERT_TRUE(nullptr != buf);
// remove trailing FF
char* cp = buf + len - 1;
@@ -192,19 +199,38 @@
EXPECT_EQ(0, truncated);
char* main_logs = strstr(cp, "\nChattiest UIDs in main ");
- EXPECT_TRUE(NULL != main_logs);
+ EXPECT_TRUE(nullptr != main_logs);
char* radio_logs = strstr(cp, "\nChattiest UIDs in radio ");
if (!radio_logs)
- GTEST_LOG_(INFO) << "Value of: NULL != radio_logs\n"
+ GTEST_LOG_(INFO) << "Value of: nullptr != radio_logs\n"
"Actual: false\n"
"Expected: false\n";
char* system_logs = strstr(cp, "\nChattiest UIDs in system ");
- EXPECT_TRUE(NULL != system_logs);
+ EXPECT_TRUE(nullptr != system_logs);
char* events_logs = strstr(cp, "\nChattiest UIDs in events ");
- EXPECT_TRUE(NULL != events_logs);
+ EXPECT_TRUE(nullptr != events_logs);
+
+ // Check if there is any " u0_a#### " as this means packagelistparser broken
+ char* used_getpwuid = nullptr;
+ int used_getpwuid_len;
+ char* uid_name = cp;
+ static const char getpwuid_prefix[] = " u0_a";
+ while ((uid_name = strstr(uid_name, getpwuid_prefix)) != nullptr) {
+ used_getpwuid = uid_name + 1;
+ uid_name += strlen(getpwuid_prefix);
+ while (isdigit(*uid_name)) ++uid_name;
+ used_getpwuid_len = uid_name - used_getpwuid;
+ if (isspace(*uid_name)) break;
+ used_getpwuid = nullptr;
+ }
+ EXPECT_TRUE(nullptr == used_getpwuid);
+ if (used_getpwuid) {
+ fprintf(stderr, "libpackagelistparser failed to pick up %.*s\n",
+ used_getpwuid_len, used_getpwuid);
+ }
delete[] buf;
#else
@@ -352,7 +378,7 @@
}
alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, NULL);
+ sigaction(SIGALRM, &old_sigaction, nullptr);
close(fd);
}
@@ -434,7 +460,7 @@
// Introduce some extreme spam for the worst UID filter
ASSERT_TRUE(
- NULL !=
+ nullptr !=
(fp = popen("/data/nativetest/liblog-benchmarks/liblog-benchmarks"
" BM_log_maximum_retry"
" BM_log_maximum"
@@ -505,10 +531,10 @@
bool collected_statistics = !!buf;
EXPECT_EQ(true, collected_statistics);
- ASSERT_TRUE(NULL != buf);
+ ASSERT_TRUE(nullptr != buf);
char* benchmark_statistics_found = find_benchmark_spam(buf);
- ASSERT_TRUE(benchmark_statistics_found != NULL);
+ ASSERT_TRUE(benchmark_statistics_found != nullptr);
// Check how effective the SPAM filter is, parse out Now size.
// 0 root 54164 147569
@@ -603,7 +629,7 @@
written = write(fd, ask.c_str(), len) == (ssize_t)len;
if (!written) {
alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, NULL);
+ sigaction(SIGALRM, &old_sigaction, nullptr);
close(fd);
continue;
}
@@ -625,7 +651,7 @@
: (old_alarm > (1 + 3 - alarm_wrap))
? old_alarm - 3 + alarm_wrap
: 2);
- sigaction(SIGALRM, &old_sigaction, NULL);
+ sigaction(SIGALRM, &old_sigaction, nullptr);
close(fd);
@@ -648,7 +674,7 @@
EXPECT_TRUE(content_timeout);
EXPECT_NE(0U, alarm_timeout);
#else
- command = NULL;
+ command = nullptr;
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
@@ -713,7 +739,7 @@
written = write(fd, ask.c_str(), len) == (ssize_t)len;
if (!written) {
alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, NULL);
+ sigaction(SIGALRM, &old_sigaction, nullptr);
close(fd);
continue;
}
@@ -735,7 +761,7 @@
: (old_alarm > (1 + 3 - alarm_wrap))
? old_alarm - 3 + alarm_wrap
: 2);
- sigaction(SIGALRM, &old_sigaction, NULL);
+ sigaction(SIGALRM, &old_sigaction, nullptr);
close(fd);
@@ -837,7 +863,7 @@
int save_errno = (recv_ret < 0) ? errno : 0;
EXPECT_NE(0U, alarm(old_alarm));
- sigaction(SIGALRM, &old_sigaction, NULL);
+ sigaction(SIGALRM, &old_sigaction, nullptr);
EXPECT_EQ(0, recv_ret);
if (recv_ret > 0) {
@@ -876,8 +902,8 @@
char* cp;
long ret = strtol(buffer, &cp, 10);
EXPECT_GT(ret, 16);
- EXPECT_TRUE(strstr(buffer, "\t(to life the universe etc|3)") != NULL);
- EXPECT_TRUE(strstr(buffer, "answer") != NULL);
+ EXPECT_TRUE(strstr(buffer, "\t(to life the universe etc|3)") != nullptr);
+ EXPECT_TRUE(strstr(buffer, "answer") != nullptr);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
@@ -897,8 +923,8 @@
char* cp;
long ret = strtol(buffer, &cp, 10);
EXPECT_GT(ret, 16);
- EXPECT_TRUE(strstr(buffer, "\t(new|1)") != NULL);
- EXPECT_TRUE(strstr(buffer, name) != NULL);
+ EXPECT_TRUE(strstr(buffer, "\t(new|1)") != nullptr);
+ EXPECT_TRUE(strstr(buffer, name) != nullptr);
// ToDo: also look for this in /data/misc/logd/event-log-tags and
// /dev/event-log-tags.
#else
@@ -942,7 +968,7 @@
ASSERT_EQ(0, info.si_status);
struct logger_list* logger_list;
- ASSERT_TRUE(NULL !=
+ ASSERT_TRUE(nullptr !=
(logger_list = android_logger_list_open(
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
0, pid)));
diff --git a/platform_tools_tool_version.mk b/platform_tools_tool_version.mk
new file mode 100644
index 0000000..73229e6
--- /dev/null
+++ b/platform_tools_tool_version.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2017 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# We rewrite ${PLATFORM_SDK_VERSION} with 0 rather than $(PLATFORM_SDK_VERSION)
+# because on the actual platform tools release branches the file contains a
+# literal instead. Using 0 lets us easily distinguish non-canonical builds.
+platform_tools_version := $(shell sed \
+ 's/$${PLATFORM_SDK_VERSION}/0/ ; s/^Pkg.Revision=\(.*\)/\1/p ; d' \
+ $(ANDROID_BUILD_TOP)/development/sdk/plat_tools_source.prop_template \
+ )
+tool_version := $(platform_tools_version)-$(BUILD_NUMBER_FROM_FILE)
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index aa755ed..d6ead1a 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -95,13 +95,3 @@
LOCAL_MODULE := grep
LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,egrep fgrep,ln -sf grep $(TARGET_OUT)/bin/$(t);)
include $(BUILD_EXECUTABLE)
-
-
-# We build gzip separately, so it can provide gunzip and zcat too.
-include $(CLEAR_VARS)
-LOCAL_MODULE := gzip
-LOCAL_SRC_FILES := gzip.c
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_SHARED_LIBRARIES += libz
-LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,gunzip zcat,ln -sf gzip $(TARGET_OUT)/bin/$(t);)
-include $(BUILD_EXECUTABLE)
diff --git a/toolbox/gzip.c b/toolbox/gzip.c
deleted file mode 100644
index 62c4518..0000000
--- a/toolbox/gzip.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/* gzip.c - gzip/gunzip/zcat tools for gzip data
- *
- * Copyright 2017 The Android Open Source Project
- *
- * GZIP RFC: http://www.ietf.org/rfc/rfc1952.txt
-
-TODO: port to toybox.
-
-*/
-
-#define _GNU_SOURCE
-
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include <zlib.h>
-
-// toybox-style flags/globals.
-#define FLAG_c 1
-#define FLAG_d 2
-#define FLAG_f 4
-#define FLAG_k 8
-static struct {
- int optflags;
-} toys;
-static struct {
- int level;
-} TT;
-
-static void xstat(const char *path, struct stat *sb)
-{
- if (stat(path, sb)) error(1, errno, "stat %s", path);
-}
-
-static void fix_time(const char *path, struct stat *sb)
-{
- struct timespec times[] = { sb->st_atim, sb->st_mtim };
-
- if (utimensat(AT_FDCWD, path, times, 0)) error(1, errno, "utimes");
-}
-
-static FILE *xfdopen(const char *name, int flags, mode_t open_mode,
- const char *mode)
-{
- FILE *fp;
- int fd;
-
- if (!strcmp(name, "-")) fd = dup((*mode == 'r') ? 0 : 1);
- else fd = open(name, flags, open_mode);
-
- if (fd == -1) error(1, errno, "open %s (%s)", name, mode);
- fp = fdopen(fd, mode);
- if (fp == NULL) error(1, errno, "fopen %s (%s)", name, mode);
- return fp;
-}
-
-static gzFile xgzopen(const char *name, int flags, mode_t open_mode,
- const char *mode)
-{
- gzFile f;
- int fd;
-
- if (!strcmp(name, "-")) fd = dup((*mode == 'r') ? 0 : 1);
- else fd = open(name, flags, open_mode);
-
- if (fd == -1) error(1, errno, "open %s (%s)", name, mode);
- f = gzdopen(fd, mode);
- if (f == NULL) error(1, errno, "gzdopen %s (%s)", name, mode);
- return f;
-}
-
-static void gzfatal(gzFile f, char *what)
-{
- int err;
- const char *msg = gzerror(f, &err);
-
- error(1, (err == Z_ERRNO) ? errno : 0, "%s: %s", what, msg);
-}
-
-static void gunzip(char *arg)
-{
- struct stat sb;
- char buf[BUFSIZ];
- int len, both_files;
- char *in_name, *out_name;
- gzFile in;
- FILE *out;
-
- // "gunzip x.gz" will decompress "x.gz" to "x".
- len = strlen(arg);
- if (len > 3 && !strcmp(arg+len-3, ".gz")) {
- in_name = strdup(arg);
- out_name = strdup(arg);
- out_name[len-3] = '\0';
- } else if (!strcmp(arg, "-")) {
- // "-" means stdin; assume output to stdout.
- // TODO: require -f to read compressed data from tty?
- in_name = strdup("-");
- out_name = strdup("-");
- } else error(1, 0, "unknown suffix");
-
- if (toys.optflags&FLAG_c) {
- free(out_name);
- out_name = strdup("-");
- }
-
- both_files = strcmp(in_name, "-") && strcmp(out_name, "-");
- if (both_files) xstat(in_name, &sb);
-
- in = xgzopen(in_name, O_RDONLY, 0, "r");
- out = xfdopen(out_name, O_CREAT|O_WRONLY|((toys.optflags&FLAG_f)?0:O_EXCL),
- both_files?sb.st_mode:0666, "w");
-
- while ((len = gzread(in, buf, sizeof(buf))) > 0) {
- if (fwrite(buf, 1, len, out) != (size_t) len) error(1, errno, "fwrite");
- }
- if (len < 0) gzfatal(in, "gzread");
- if (fclose(out)) error(1, errno, "fclose");
- if (gzclose(in) != Z_OK) error(1, 0, "gzclose");
-
- if (both_files) fix_time(out_name, &sb);
- if (!(toys.optflags&(FLAG_c|FLAG_k))) unlink(in_name);
- free(in_name);
- free(out_name);
-}
-
-static void gzip(char *in_name)
-{
- char buf[BUFSIZ];
- size_t len;
- char *out_name;
- FILE *in;
- gzFile out;
- struct stat sb;
- int both_files;
-
- if (toys.optflags&FLAG_c) {
- out_name = strdup("-");
- } else {
- if (asprintf(&out_name, "%s.gz", in_name) == -1) {
- error(1, errno, "asprintf");
- }
- }
-
- both_files = strcmp(in_name, "-") && strcmp(out_name, "-");
- if (both_files) xstat(in_name, &sb);
-
- snprintf(buf, sizeof(buf), "w%d", TT.level);
- in = xfdopen(in_name, O_RDONLY, 0, "r");
- out = xgzopen(out_name, O_CREAT|O_WRONLY|((toys.optflags&FLAG_f)?0:O_EXCL),
- both_files?sb.st_mode:0, buf);
-
- while ((len = fread(buf, 1, sizeof(buf), in)) > 0) {
- if (gzwrite(out, buf, len) != (int) len) gzfatal(out, "gzwrite");
- }
- if (ferror(in)) error(1, errno, "fread");
- if (fclose(in)) error(1, errno, "fclose");
- if (gzclose(out) != Z_OK) error(1, 0, "gzclose");
-
- if (both_files) fix_time(out_name, &sb);
- if (!(toys.optflags&(FLAG_c|FLAG_k))) unlink(in_name);
- free(out_name);
-}
-
-static void do_file(char *arg)
-{
- if (toys.optflags&FLAG_d) gunzip(arg);
- else gzip(arg);
-}
-
-static void usage()
-{
- char *cmd = basename(getprogname());
-
- printf("usage: %s [-c] [-d] [-f] [-#] [FILE...]\n", cmd);
- printf("\n");
- if (!strcmp(cmd, "zcat")) {
- printf("Decompress files to stdout. Like `gzip -dc`.\n");
- printf("\n");
- printf("-c\tOutput to stdout\n");
- printf("-f\tForce: allow read from tty\n");
- } else if (!strcmp(cmd, "gunzip")) {
- printf("Decompress files. With no files, decompresses stdin to stdout.\n");
- printf("On success, the input files are removed and replaced by new\n");
- printf("files without the .gz suffix.\n");
- printf("\n");
- printf("-c\tOutput to stdout\n");
- printf("-f\tForce: allow read from tty\n");
- printf("-k\tKeep input files (don't remove)\n");
- } else { // gzip
- printf("Compress files. With no files, compresses stdin to stdout.\n");
- printf("On success, the input files are removed and replaced by new\n");
- printf("files with the .gz suffix.\n");
- printf("\n");
- printf("-c\tOutput to stdout\n");
- printf("-d\tDecompress (act as gunzip)\n");
- printf("-f\tForce: allow overwrite of output file\n");
- printf("-k\tKeep input files (don't remove)\n");
- printf("-#\tCompression level 1-9 (1:fastest, 6:default, 9:best)\n");
- }
- printf("\n");
-}
-
-int main(int argc, char *argv[])
-{
- char *cmd = basename(argv[0]);
- int opt_ch;
-
- toys.optflags = 0;
- TT.level = 6;
-
- if (!strcmp(cmd, "gunzip")) {
- // gunzip == gzip -d
- toys.optflags = FLAG_d;
- } else if (!strcmp(cmd, "zcat")) {
- // zcat == gzip -dc
- toys.optflags = (FLAG_c|FLAG_d);
- }
-
- while ((opt_ch = getopt(argc, argv, "cdfhk123456789")) != -1) {
- switch (opt_ch) {
- case 'c': toys.optflags |= FLAG_c; break;
- case 'd': toys.optflags |= FLAG_d; break;
- case 'f': toys.optflags |= FLAG_f; break;
- case 'k': toys.optflags |= FLAG_k; break;
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- TT.level = opt_ch - '0';
- break;
-
- default:
- usage();
- return 1;
- }
- }
-
- if (optind == argc) {
- // With no arguments, we go from stdin to stdout.
- toys.optflags |= FLAG_c;
- do_file("-");
- return 0;
- }
-
- // Otherwise process each file in turn.
- while (optind < argc) do_file(argv[optind++]);
- return 0;
-}
diff --git a/trusty/Android.bp b/trusty/Android.bp
index 1b2e2c7..386fbe6 100644
--- a/trusty/Android.bp
+++ b/trusty/Android.bp
@@ -1,3 +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)
diff --git a/trusty/storage/interface/Android.bp b/trusty/storage/interface/Android.bp
new file mode 100644
index 0000000..a551c37
--- /dev/null
+++ b/trusty/storage/interface/Android.bp
@@ -0,0 +1,20 @@
+//
+// 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.
+//
+
+cc_library_static {
+ name: "libtrustystorageinterface",
+ export_include_dirs: ["include"],
+}
diff --git a/trusty/storage/interface/Android.mk b/trusty/storage/interface/Android.mk
deleted file mode 100644
index 15cb6f3..0000000
--- a/trusty/storage/interface/Android.mk
+++ /dev/null
@@ -1,25 +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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libtrustystorageinterface
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/trusty/storage/lib/Android.bp b/trusty/storage/lib/Android.bp
new file mode 100644
index 0000000..5eb3f07
--- /dev/null
+++ b/trusty/storage/lib/Android.bp
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+
+cc_library_static {
+ name: "libtrustystorage",
+
+ srcs: ["storage.c"],
+
+ export_include_dirs: ["include"],
+
+ static_libs: [
+ "liblog",
+ "libtrusty",
+ "libtrustystorageinterface",
+ ],
+
+ cflags: [
+ "-fvisibility=hidden",
+ "-Wall",
+ "-Werror",
+ ]
+}
diff --git a/trusty/storage/lib/Android.mk b/trusty/storage/lib/Android.mk
deleted file mode 100644
index 7e0fc9d..0000000
--- a/trusty/storage/lib/Android.mk
+++ /dev/null
@@ -1,37 +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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libtrustystorage
-
-LOCAL_SRC_FILES := \
- storage.c \
-
-LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-
-LOCAL_STATIC_LIBRARIES := \
- liblog \
- libtrusty \
- libtrustystorageinterface
-
-include $(BUILD_STATIC_LIBRARY)
-
diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp
new file mode 100644
index 0000000..eb34df0
--- /dev/null
+++ b/trusty/storage/proxy/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+
+cc_binary {
+ name: "storageproxyd",
+
+ srcs: [
+ "ipc.c",
+ "rpmb.c",
+ "storage.c",
+ "proxy.c",
+ ],
+
+ shared_libs: ["liblog"],
+
+ static_libs: [
+ "libtrustystorageinterface",
+ "libtrusty",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ]
+}
diff --git a/trusty/storage/proxy/Android.mk b/trusty/storage/proxy/Android.mk
deleted file mode 100644
index 745e302..0000000
--- a/trusty/storage/proxy/Android.mk
+++ /dev/null
@@ -1,41 +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)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := storageproxyd
-
-LOCAL_C_INCLUDES += bionic/libc/kernel/uapi
-
-LOCAL_SRC_FILES := \
- ipc.c \
- rpmb.c \
- storage.c \
- proxy.c
-
-LOCAL_CLFAGS = -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
-
-LOCAL_STATIC_LIBRARIES := \
- libtrustystorageinterface \
- libtrusty
-
-include $(BUILD_EXECUTABLE)
-
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index d645ac0..27e5891 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -229,7 +229,6 @@
int main(int argc, char *argv[])
{
int rc;
- uint retry_cnt;
/* drop privileges */
if (drop_privs() < 0)
diff --git a/trusty/storage/tests/Android.bp b/trusty/storage/tests/Android.bp
new file mode 100644
index 0000000..3eff3f2
--- /dev/null
+++ b/trusty/storage/tests/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "secure-storage-unit-test",
+
+ cflags: [
+ "-g",
+ "-Wall",
+ "-Werror",
+ "-std=gnu++11",
+ "-Wno-missing-field-initializers",
+ ],
+
+ static_libs: [
+ "libtrustystorageinterface",
+ "libtrustystorage",
+ "libtrusty",
+ "liblog",
+ ],
+
+ srcs: ["main.cpp"],
+}
diff --git a/trusty/storage/tests/Android.mk b/trusty/storage/tests/Android.mk
deleted file mode 100644
index 71c904d..0000000
--- a/trusty/storage/tests/Android.mk
+++ /dev/null
@@ -1,29 +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)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := secure-storage-unit-test
-LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
-LOCAL_STATIC_LIBRARIES := \
- libtrustystorageinterface \
- libtrustystorage \
- libtrusty \
- liblog
-LOCAL_SRC_FILES := main.cpp
-include $(BUILD_NATIVE_TEST)
-