Merge "init: move killing of process groups to libprocessgroup"
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 20c63b3..11c0ec9 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -74,13 +74,18 @@
template <typename Fn>
void PopAll(Fn fn) {
- std::unique_lock<std::mutex> lock(mutex);
- cv.wait(lock, [this]() { return !queue.empty(); });
+ std::vector<T> popped;
- for (const T& t : queue) {
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ cv.wait(lock, [this]() { return !queue.empty(); });
+ popped = std::move(queue);
+ queue.clear();
+ }
+
+ for (const T& t : popped) {
fn(t);
}
- queue.clear();
}
};
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 7e77b5e..e7f44c6 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -180,10 +180,6 @@
if (port_count < 0) return "";
return StringPrintf("/dev/bus/usb/%03u/%03u", libusb_get_bus_number(device), ports[0]);
}
-
-static bool is_device_accessible(libusb_device* device) {
- return access(get_device_dev_path(device).c_str(), R_OK | W_OK) == 0;
-}
#endif
static bool endpoint_is_output(uint8_t endpoint) {
@@ -377,9 +373,10 @@
{
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);
+ register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(),
+ writable);
+ }
LOG(INFO) << "registered new usb device '" << device_serial << "'";
}
@@ -388,18 +385,12 @@
static void device_connected(libusb_device* device) {
#if defined(__linux__)
// Android's host linux libusb uses netlink instead of udev for device hotplug notification,
- // which means we can get hotplug notifications before udev has updated ownership/perms on
- // the device. Since we're not going to be able to link against the system's libudev any
- // time soon, hack around this by checking for accessibility in a loop.
+ // which means we can get hotplug notifications before udev has updated ownership/perms on the
+ // device. Since we're not going to be able to link against the system's libudev any time soon,
+ // hack around this by inserting a sleep.
auto thread = std::thread([device]() {
std::string device_path = get_device_dev_path(device);
- auto start = std::chrono::steady_clock::now();
- while (std::chrono::steady_clock::now() - start < 500ms) {
- if (is_device_accessible(device)) {
- break;
- }
- std::this_thread::sleep_for(10ms);
- }
+ std::this_thread::sleep_for(1s);
process_device(device);
if (--connecting_devices == 0) {
@@ -422,8 +413,10 @@
if (!it->second->device_handle) {
// If the handle is null, we were never able to open the device.
unregister_usb_transport(it->second.get());
+ usb_handles.erase(it);
+ } else {
+ // Closure of the transport will erase the usb_handle.
}
- usb_handles.erase(it);
}
}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 308ee8d..2bbbefd 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -603,15 +603,15 @@
static void transport_unref(atransport* t) {
CHECK(t != nullptr);
- std::lock_guard<std::mutex> lock(transport_lock);
- CHECK_GT(t->ref_count, 0u);
- t->ref_count--;
- if (t->ref_count == 0) {
+ size_t old_refcount = t->ref_count--;
+ CHECK_GT(old_refcount, 0u);
+
+ if (old_refcount == 1u) {
D("transport: %s unref (kicking and closing)", t->serial);
t->close(t);
remove_transport(t);
} else {
- D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
+ D("transport: %s unref (count=%zu)", t->serial, old_refcount - 1);
}
}
diff --git a/adb/transport.h b/adb/transport.h
index 57fc988..4a89ed9 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -61,7 +61,7 @@
// class in one go is a very large change. Given how bad our testing is,
// it's better to do this piece by piece.
- atransport(ConnectionState state = kCsOffline) : connection_state_(state) {
+ atransport(ConnectionState state = kCsOffline) : ref_count(0), connection_state_(state) {
transport_fde = {};
protocol_version = A_VERSION;
max_payload = MAX_PAYLOAD;
@@ -88,7 +88,7 @@
int fd = -1;
int transport_socket = -1;
fdevent transport_fde;
- size_t ref_count = 0;
+ std::atomic<size_t> ref_count;
uint32_t sync_token = 0;
bool online = false;
TransportType type = kTransportAny;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index a9e583f..6cedd92 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -388,6 +388,25 @@
D("transport: qemu_socket_thread() exiting");
return;
}
+
+// If adbd is running inside the emulator, it will normally use QEMUD pipe (aka
+// goldfish) as the transport. This can either be explicitly set by the
+// service.adb.transport property, or be inferred from ro.kernel.qemu that is
+// set to "1" for ranchu/goldfish.
+static bool use_qemu_goldfish() {
+ // Legacy way to detect if adbd should use the goldfish pipe is to check for
+ // ro.kernel.qemu, keep that behaviour for backward compatibility.
+ if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
+ return true;
+ }
+ // If service.adb.transport is present and is set to "goldfish", use the
+ // QEMUD pipe.
+ if (android::base::GetProperty("service.adb.transport", "") == "goldfish") {
+ return true;
+ }
+ return false;
+}
+
#endif // !ADB_HOST
void local_init(int port)
@@ -401,13 +420,7 @@
#else
// For the adbd daemon in the system image we need to distinguish
// between the device, and the emulator.
- if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
- // Running inside the emulator: use QEMUD pipe as the transport.
- func = qemu_socket_thread;
- } else {
- // Running inside the device: use TCP socket as the transport.
- func = server_socket_thread;
- }
+ func = use_qemu_goldfish() ? qemu_socket_thread : server_socket_thread;
debug_name = "server";
#endif // !ADB_HOST
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 558bc72..df7201d 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -44,6 +44,9 @@
#include <private/android_filesystem_config.h>
#include <procinfo/process.h>
+#define ATRACE_TAG ATRACE_TAG_BIONIC
+#include <utils/Trace.h>
+
#include "backtrace.h"
#include "tombstone.h"
#include "utility.h"
@@ -101,6 +104,7 @@
}
static bool activity_manager_notify(pid_t pid, int signal, const std::string& amfd_data) {
+ ATRACE_CALL();
android::base::unique_fd amfd(socket_local_client(
"/data/system/ndebugsocket", ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM));
if (amfd.get() == -1) {
@@ -176,6 +180,7 @@
}
static void drop_capabilities() {
+ ATRACE_CALL();
__user_cap_header_struct capheader;
memset(&capheader, 0, sizeof(capheader));
capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -194,6 +199,8 @@
}
int main(int argc, char** argv) {
+ atrace_begin(ATRACE_TAG, "before reparent");
+
pid_t target = getppid();
bool tombstoned_connected = false;
unique_fd tombstoned_socket;
@@ -261,6 +268,8 @@
PLOG(FATAL) << "parent died";
}
+ atrace_end(ATRACE_TAG);
+
// Reparent ourselves to init, so that the signal handler can waitpid on the
// original process to avoid leaving a zombie for non-fatal dumps.
pid_t forkpid = fork();
@@ -270,47 +279,60 @@
exit(0);
}
+ ATRACE_NAME("after reparent");
+
// Die if we take too long.
alarm(2);
std::string attach_error;
- // Seize the main thread.
- if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) {
- LOG(FATAL) << attach_error;
- }
-
- // Seize the siblings.
std::map<pid_t, std::string> threads;
+
{
- std::set<pid_t> siblings;
- if (!android::procinfo::GetProcessTids(target, &siblings)) {
- PLOG(FATAL) << "failed to get process siblings";
+ ATRACE_NAME("ptrace");
+ // Seize the main thread.
+ if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) {
+ LOG(FATAL) << attach_error;
}
- // but not the already attached main thread.
- siblings.erase(main_tid);
- // or the handler pseudothread.
- siblings.erase(pseudothread_tid);
+ // Seize the siblings.
+ {
+ std::set<pid_t> siblings;
+ if (!android::procinfo::GetProcessTids(target, &siblings)) {
+ PLOG(FATAL) << "failed to get process siblings";
+ }
- for (pid_t sibling_tid : siblings) {
- if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
- LOG(WARNING) << attach_error;
- } else {
- threads.emplace(sibling_tid, get_thread_name(sibling_tid));
+ // but not the already attached main thread.
+ siblings.erase(main_tid);
+ // or the handler pseudothread.
+ siblings.erase(pseudothread_tid);
+
+ for (pid_t sibling_tid : siblings) {
+ if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
+ LOG(WARNING) << attach_error;
+ } else {
+ threads.emplace(sibling_tid, get_thread_name(sibling_tid));
+ }
}
}
}
// Collect the backtrace map, open files, and process/thread names, while we still have caps.
- std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
- if (!backtrace_map) {
- LOG(FATAL) << "failed to create backtrace map";
+ std::unique_ptr<BacktraceMap> backtrace_map;
+ {
+ ATRACE_NAME("backtrace map");
+ backtrace_map.reset(BacktraceMap::Create(main_tid));
+ if (!backtrace_map) {
+ LOG(FATAL) << "failed to create backtrace map";
+ }
}
// Collect the list of open files.
OpenFilesList open_files;
- populate_open_files_list(target, &open_files);
+ {
+ ATRACE_NAME("open files");
+ populate_open_files_list(target, &open_files);
+ }
std::string process_name = get_process_name(main_tid);
threads.emplace(main_tid, get_thread_name(main_tid));
@@ -318,9 +340,12 @@
// Drop our capabilities now that we've attached to the threads we care about.
drop_capabilities();
- const DebuggerdDumpType dump_type_enum = static_cast<DebuggerdDumpType>(dump_type);
- LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type_enum;
- tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd, dump_type_enum);
+ {
+ ATRACE_NAME("tombstoned_connect");
+ const DebuggerdDumpType dump_type_enum = static_cast<DebuggerdDumpType>(dump_type);
+ LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type_enum;
+ tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd, dump_type_enum);
+ }
// Write a '\1' to stdout to tell the crashing process to resume.
// It also restores the value of PR_SET_DUMPABLE at this point.
@@ -349,9 +374,12 @@
}
siginfo_t siginfo = {};
- if (!wait_for_signal(main_tid, &siginfo)) {
- printf("failed to wait for signal in tid %d: %s\n", main_tid, strerror(errno));
- exit(1);
+ {
+ ATRACE_NAME("wait_for_signal");
+ if (!wait_for_signal(main_tid, &siginfo)) {
+ printf("failed to wait for signal in tid %d: %s\n", main_tid, strerror(errno));
+ exit(1);
+ }
}
int signo = siginfo.si_signo;
@@ -373,8 +401,10 @@
std::string amfd_data;
if (backtrace) {
+ ATRACE_NAME("dump_backtrace");
dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, process_name, threads, 0);
} else {
+ ATRACE_NAME("engrave_tombstone");
engrave_tombstone(output_fd.get(), backtrace_map.get(), &open_files, target, main_tid,
process_name, threads, abort_address, fatal_signal ? &amfd_data : nullptr);
}
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 9008b95..da8ad37 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -89,7 +89,7 @@
} while (0)
static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
- DebuggerdDumpType intercept_type) {
+ InterceptStatus* status, DebuggerdDumpType intercept_type) {
intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
if (intercept_fd->get() == -1) {
@@ -136,7 +136,7 @@
<< ", received " << rc;
}
- ASSERT_EQ(InterceptStatus::kRegistered, response.status);
+ *status = response.status;
}
class CrasherTest : public ::testing::Test {
@@ -180,7 +180,9 @@
FAIL() << "crasher hasn't been started";
}
- tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, intercept_type);
+ InterceptStatus status;
+ tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
+ ASSERT_EQ(InterceptStatus::kRegistered, status);
}
void CrasherTest::FinishIntercept(int* result) {
@@ -598,7 +600,9 @@
pid_t pid = 123'456'789 + i;
unique_fd intercept_fd, output_fd;
- tombstoned_intercept(pid, &intercept_fd, &output_fd, kDebuggerdTombstone);
+ InterceptStatus status;
+ tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
+ ASSERT_EQ(InterceptStatus::kRegistered, status);
{
unique_fd tombstoned_socket, input_fd;
@@ -630,7 +634,9 @@
pid_t pid = pid_base + dump;
unique_fd intercept_fd, output_fd;
- tombstoned_intercept(pid, &intercept_fd, &output_fd, kDebuggerdTombstone);
+ InterceptStatus status;
+ tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
+ ASSERT_EQ(InterceptStatus::kRegistered, status);
// Pretend to crash, and then immediately close the socket.
unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
@@ -661,7 +667,9 @@
pid_t pid = pid_base + dump;
unique_fd intercept_fd, output_fd;
- tombstoned_intercept(pid, &intercept_fd, &output_fd, kDebuggerdTombstone);
+ InterceptStatus status;
+ tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
+ ASSERT_EQ(InterceptStatus::kRegistered, status);
{
unique_fd tombstoned_socket, input_fd;
@@ -685,3 +693,65 @@
thread.join();
}
}
+
+TEST(tombstoned, java_trace_intercept_smoke) {
+ // Using a "real" PID is a little dangerous here - if the test fails
+ // or crashes, we might end up getting a bogus / unreliable stack
+ // trace.
+ const pid_t self = getpid();
+
+ unique_fd intercept_fd, output_fd;
+ InterceptStatus status;
+ tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
+ ASSERT_EQ(InterceptStatus::kRegistered, status);
+
+ // First connect to tombstoned requesting a native backtrace. This
+ // should result in a "regular" FD and not the installed intercept.
+ const char native[] = "native";
+ unique_fd tombstoned_socket, input_fd;
+ ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdNativeBacktrace));
+ ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
+ tombstoned_notify_completion(tombstoned_socket.get());
+
+ // Then, connect to tombstoned asking for a java backtrace. This *should*
+ // trigger the intercept.
+ const char java[] = "java";
+ ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
+ ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
+ tombstoned_notify_completion(tombstoned_socket.get());
+
+ char outbuf[sizeof(java)];
+ ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
+ ASSERT_STREQ("java", outbuf);
+}
+
+TEST(tombstoned, multiple_intercepts) {
+ const pid_t fake_pid = 1'234'567;
+ unique_fd intercept_fd, output_fd;
+ InterceptStatus status;
+ tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
+ ASSERT_EQ(InterceptStatus::kRegistered, status);
+
+ unique_fd intercept_fd_2, output_fd_2;
+ tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
+ ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
+}
+
+TEST(tombstoned, intercept_any) {
+ const pid_t fake_pid = 1'234'567;
+
+ unique_fd intercept_fd, output_fd;
+ InterceptStatus status;
+ tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
+ ASSERT_EQ(InterceptStatus::kRegistered, status);
+
+ const char any[] = "any";
+ unique_fd tombstoned_socket, input_fd;
+ ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
+ ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
+ tombstoned_notify_completion(tombstoned_socket.get());
+
+ char outbuf[sizeof(any)];
+ ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
+ ASSERT_STREQ("any", outbuf);
+}
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 0a9f000..b920ebc 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -23,7 +23,9 @@
#include <array>
#include <deque>
+#include <string>
#include <unordered_map>
+#include <utility>
#include <event2/event.h>
#include <event2/listener.h>
@@ -75,23 +77,24 @@
find_oldest_artifact();
}
- unique_fd get_output_fd() {
+ std::pair<unique_fd, std::string> get_output() {
unique_fd result;
- char buf[PATH_MAX];
- snprintf(buf, sizeof(buf), "%s%02d", file_name_prefix_.c_str(), next_artifact_);
+ std::string file_name = StringPrintf("%s%02d", file_name_prefix_.c_str(), next_artifact_);
+
// Unlink and create the file, instead of using O_TRUNC, to avoid two processes
// interleaving their output in case we ever get into that situation.
- if (unlinkat(dir_fd_, buf, 0) != 0 && errno != ENOENT) {
- PLOG(FATAL) << "failed to unlink tombstone at " << dir_path_ << buf;
+ if (unlinkat(dir_fd_, file_name.c_str(), 0) != 0 && errno != ENOENT) {
+ PLOG(FATAL) << "failed to unlink tombstone at " << dir_path_ << "/" << file_name;
}
- result.reset(openat(dir_fd_, buf, O_CREAT | O_EXCL | O_WRONLY | O_APPEND | O_CLOEXEC, 0640));
+ result.reset(openat(dir_fd_, file_name.c_str(),
+ O_CREAT | O_EXCL | O_WRONLY | O_APPEND | O_CLOEXEC, 0640));
if (result == -1) {
- PLOG(FATAL) << "failed to create tombstone at " << dir_path_ << buf;
+ PLOG(FATAL) << "failed to create tombstone at " << dir_path_ << "/" << file_name;
}
next_artifact_ = (next_artifact_ + 1) % max_artifacts_;
- return result;
+ return {std::move(result), dir_path_ + "/" + file_name};
}
bool maybe_enqueue_crash(Crash* crash) {
@@ -124,8 +127,7 @@
time_t oldest_time = std::numeric_limits<time_t>::max();
for (size_t i = 0; i < max_artifacts_; ++i) {
- std::string path = android::base::StringPrintf("%s/%s%02zu", dir_path_.c_str(),
- file_name_prefix_.c_str(), i);
+ std::string path = StringPrintf("%s/%s%02zu", dir_path_.c_str(), file_name_prefix_.c_str(), i);
struct stat st;
if (stat(path.c_str(), &st) != 0) {
if (errno == ENOENT) {
@@ -163,7 +165,7 @@
};
// Whether java trace dumps are produced via tombstoned.
-static constexpr bool kJavaTraceDumpsEnabled = false;
+static constexpr bool kJavaTraceDumpsEnabled = true;
/* static */ CrashQueue* const CrashQueue::tombstone =
new CrashQueue("/data/tombstones", "tombstone_" /* file_name_prefix */, 10 /* max_artifacts */,
@@ -183,6 +185,7 @@
unique_fd crash_fd;
pid_t crash_pid;
event* crash_event = nullptr;
+ std::string crash_path;
DebuggerdDumpType crash_type;
};
@@ -203,7 +206,7 @@
static void perform_request(Crash* crash) {
unique_fd output_fd;
if (!intercept_manager->GetIntercept(crash->crash_pid, crash->crash_type, &output_fd)) {
- output_fd = get_crash_queue(crash)->get_output_fd();
+ std::tie(output_fd, crash->crash_path) = get_crash_queue(crash)->get_output();
}
TombstonedCrashPacket response = {
@@ -341,6 +344,10 @@
goto fail;
}
+ if (!crash->crash_path.empty()) {
+ LOG(ERROR) << "Tombstone written to: " << crash->crash_path;
+ }
+
fail:
CrashQueue* queue = get_crash_queue(crash);
delete crash;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 70cd608..7a41b14 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -337,16 +337,8 @@
dirent* dp;
while ((dp = readdir(fstabdir.get())) != NULL) {
- // skip over name and compatible
- if (dp->d_type != DT_DIR) {
- continue;
- }
-
- // skip if its not 'vendor', 'odm' or 'system'
- if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
- strcmp(dp->d_name, "vendor")) {
- continue;
- }
+ // skip over name, compatible and .
+ if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
// create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
std::vector<std::string> fstab_entry;
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 5fa10bc..0177fdf 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -689,27 +689,55 @@
return read_verity_state(fstab->verity_loc, offset, mode);
}
-static void update_verity_table_blk_device(char *blk_device, char **table)
-{
- std::string result, word;
+// Update the verity table using the actual block device path.
+// Two cases:
+// Case-1: verity table is shared for devices with different by-name prefix.
+// Example:
+// verity table token: /dev/block/bootdevice/by-name/vendor
+// blk_device-1 (non-A/B): /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
+// blk_device-2 (A/B): /dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor_a
+//
+// Case-2: append A/B suffix in the verity table.
+// Example:
+// verity table token: /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
+// blk_device: /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor_a
+static void update_verity_table_blk_device(const std::string& blk_device, char** table,
+ bool slot_select) {
+ bool updated = false;
+ std::string result, ab_suffix;
auto tokens = android::base::Split(*table, " ");
+ // If slot_select is set, it means blk_device is already updated with ab_suffix.
+ if (slot_select) ab_suffix = fs_mgr_get_slot_suffix();
+
for (const auto& token : tokens) {
- if (android::base::StartsWith(token, "/dev/block/") &&
- android::base::StartsWith(blk_device, token.c_str())) {
- word = blk_device;
+ std::string new_token;
+ if (android::base::StartsWith(token, "/dev/block/")) {
+ if (token == blk_device) return; // no need to update if they're already the same.
+ std::size_t found1 = blk_device.find("by-name");
+ std::size_t found2 = token.find("by-name");
+ if (found1 != std::string::npos && found2 != std::string::npos &&
+ blk_device.substr(found1) == token.substr(found2) + ab_suffix) {
+ new_token = blk_device;
+ }
+ }
+
+ if (!new_token.empty()) {
+ updated = true;
+ LINFO << "Verity table: updated block device from '" << token << "' to '" << new_token
+ << "'";
} else {
- word = token;
+ new_token = token;
}
if (result.empty()) {
- result = word;
+ result = new_token;
} else {
- result += " " + word;
+ result += " " + new_token;
}
}
- if (result.empty()) {
+ if (!updated) {
return;
}
@@ -825,10 +853,9 @@
LINFO << "Enabling dm-verity for " << mount_point.c_str()
<< " (mode " << params.mode << ")";
- if (fstab->fs_mgr_flags & MF_SLOTSELECT) {
- // Update the verity params using the actual block device path
- update_verity_table_blk_device(fstab->blk_device, ¶ms.table);
- }
+ // Update the verity params using the actual block device path
+ update_verity_table_blk_device(fstab->blk_device, ¶ms.table,
+ fstab->fs_mgr_flags & MF_SLOTSELECT);
// load the verity mapping table
if (load_verity_table(io, mount_point, verity.data_size, fd, ¶ms,
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 8a7d9a2..0f2b1f3 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -60,9 +60,8 @@
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_;
DeviceHandler device_handler_;
@@ -115,12 +114,10 @@
LOG(ERROR) << "Failed to read fstab from device tree";
return;
}
- for (auto mount_point : {"/system", "/vendor", "/odm"}) {
- fstab_rec* fstab_rec =
- fs_mgr_get_entry_for_mount_point(device_tree_fstab_.get(), mount_point);
- if (fstab_rec != nullptr) {
- mount_fstab_recs_.push_back(fstab_rec);
- }
+ // Stores device_tree_fstab_->recs[] into mount_fstab_recs_ (vector<fstab_rec*>)
+ // for easier manipulation later, e.g., range-base for loop.
+ for (int i = 0; i < device_tree_fstab_->num_entries; i++) {
+ mount_fstab_recs_.push_back(&device_tree_fstab_->recs[i]);
}
}
@@ -420,7 +417,7 @@
// Public functions
// ----------------
-// Mounts /system, /vendor, and/or /odm if they are present in the fstab provided by device tree.
+// Mounts partitions specified by fstab in device tree.
bool DoFirstStageMount() {
// Skips first stage mount if we're in recovery mode.
if (IsRecoveryMode()) {
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index e29a844..7e38535 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -340,7 +340,7 @@
return 0;
}
-static void set_timerslack_ns(int tid, unsigned long long slack) {
+static void set_timerslack_ns(int tid, unsigned long slack) {
// v4.6+ kernels support the /proc/<tid>/timerslack_ns interface.
// TODO: once we've backported this, log if the open(2) fails.
if (__sys_supports_timerslack) {
@@ -348,7 +348,7 @@
snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", tid);
int fd = open(buf, O_WRONLY | O_CLOEXEC);
if (fd != -1) {
- int len = snprintf(buf, sizeof(buf), "%llu", slack);
+ int len = snprintf(buf, sizeof(buf), "%lu", slack);
if (write(fd, buf, len) != len) {
SLOGE("set_timerslack_ns write failed: %s\n", strerror(errno));
}
diff --git a/libpixelflinger/codeflinger/mips64_disassem.c b/libpixelflinger/codeflinger/mips64_disassem.c
index f28d726..1856e5c 100644
--- a/libpixelflinger/codeflinger/mips64_disassem.c
+++ b/libpixelflinger/codeflinger/mips64_disassem.c
@@ -555,6 +555,7 @@
} else {
vprintf(fmt, argp);
}
+ va_end(argp);
}
/*
diff --git a/libpixelflinger/codeflinger/mips_disassem.c b/libpixelflinger/codeflinger/mips_disassem.c
index 3007b15..83a9740 100644
--- a/libpixelflinger/codeflinger/mips_disassem.c
+++ b/libpixelflinger/codeflinger/mips_disassem.c
@@ -562,6 +562,7 @@
} else {
vprintf(fmt, argp);
}
+ va_end(argp);
}
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
index 98cd2c6..84af293 100644
--- a/libutils/Printer.cpp
+++ b/libutils/Printer.cpp
@@ -47,9 +47,11 @@
#ifndef _WIN32
if (vasprintf(&formattedString, format, arglist) < 0) { // returns -1 on error
ALOGE("%s: Failed to format string", __FUNCTION__);
+ va_end(arglist);
return;
}
#else
+ va_end(arglist);
return;
#endif
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 246575f..eca3ffe 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -48,6 +48,10 @@
using android::base::get_unaligned;
+// Used to turn on crc checks - verify that the content CRC matches the values
+// specified in the local file header and the central directory.
+static const bool kCrcChecksEnabled = false;
+
// This is for windows. If we don't open a file in binary mode, weird
// things will happen.
#ifndef O_BINARY
@@ -483,8 +487,7 @@
delete archive;
}
-static int32_t UpdateEntryFromDataDescriptor(MappedZipFile& mapped_zip,
- ZipEntry *entry) {
+static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, ZipEntry* entry) {
uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) {
return kIoError;
@@ -494,9 +497,17 @@
const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
- entry->crc32 = descriptor->crc32;
- entry->compressed_length = descriptor->compressed_size;
- entry->uncompressed_length = descriptor->uncompressed_size;
+ // Validate that the values in the data descriptor match those in the central
+ // directory.
+ if (entry->compressed_length != descriptor->compressed_size ||
+ entry->uncompressed_length != descriptor->uncompressed_size ||
+ entry->crc32 != descriptor->crc32) {
+ ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32 ", %" PRIx32
+ "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
+ entry->compressed_length, entry->uncompressed_length, entry->crc32,
+ descriptor->compressed_size, descriptor->uncompressed_size, descriptor->crc32);
+ return kInconsistentInformation;
+ }
return 0;
}
@@ -564,12 +575,22 @@
// Paranoia: Match the values specified in the local file header
// to those specified in the central directory.
- // Verify that the central directory and local file header agree on the use of a trailing
- // Data Descriptor.
+ // Warn if central directory and local file header don't agree on the use
+ // of a trailing Data Descriptor. The reference implementation is inconsistent
+ // and appears to use the LFH value during extraction (unzip) but the CD value
+ // while displayng information about archives (zipinfo). The spec remains
+ // silent on this inconsistency as well.
+ //
+ // For now, always use the version from the LFH but make sure that the values
+ // specified in the central directory match those in the data descriptor.
+ //
+ // NOTE: It's also worth noting that unzip *does* warn about inconsistencies in
+ // bit 11 (EFS: The language encoding flag, marking that filename and comment are
+ // encoded using UTF-8). This implementation does not check for the presence of
+ // that flag and always enforces that entry names are valid UTF-8.
if ((lfh->gpb_flags & kGPBDDFlagMask) != (cdr->gpb_flags & kGPBDDFlagMask)) {
- ALOGW("Zip: gpb flag mismatch. expected {%04" PRIx16 "}, was {%04" PRIx16 "}",
+ ALOGW("Zip: gpb flag mismatch at bit 3. expected {%04" PRIx16 "}, was {%04" PRIx16 "}",
cdr->gpb_flags, lfh->gpb_flags);
- return kInconsistentInformation;
}
// If there is no trailing data descriptor, verify that the central directory and local file
@@ -932,6 +953,7 @@
const uint32_t uncompressed_length = entry->uncompressed_length;
+ uint64_t crc = 0;
uint32_t compressed_length = entry->compressed_length;
do {
/* read as much as we can */
@@ -964,6 +986,8 @@
if (!writer->Append(&write_buf[0], write_size)) {
// The file might have declared a bogus length.
return kInconsistentInformation;
+ } else {
+ crc = crc32(crc, &write_buf[0], write_size);
}
zstream.next_out = &write_buf[0];
@@ -973,8 +997,13 @@
assert(zerr == Z_STREAM_END); /* other errors should've been caught */
- // stream.adler holds the crc32 value for such streams.
- *crc_out = zstream.adler;
+ // NOTE: zstream.adler is always set to 0, because we're using the -MAX_WBITS
+ // "feature" of zlib to tell it there won't be a zlib file header. zlib
+ // doesn't bother calculating the checksum in that scenario. We just do
+ // it ourselves above because there are no additional gains to be made by
+ // having zlib calculate it for us, since they do it by calling crc32 in
+ // the same manner that we have above.
+ *crc_out = crc;
if (zstream.total_out != uncompressed_length || compressed_length != 0) {
ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
@@ -1037,15 +1066,14 @@
}
if (!return_value && entry->has_data_descriptor) {
- return_value = UpdateEntryFromDataDescriptor(archive->mapped_zip, entry);
+ return_value = ValidateDataDescriptor(archive->mapped_zip, entry);
if (return_value) {
return return_value;
}
}
- // TODO: Fix this check by passing the right flags to inflate2 so that
- // it calculates the CRC for us.
- if (entry->crc32 != crc && false) {
+ // Validate that the CRC matches the calculated value.
+ if (kCrcChecksEnabled && (entry->crc32 != static_cast<uint32_t>(crc))) {
ALOGW("Zip: crc mismatch: expected %" PRIu32 ", was %" PRIu64, entry->crc32, crc);
return kInconsistentInformation;
}
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 9dd6cc0..42167dd 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -632,6 +632,96 @@
CloseArchive(handle);
}
+// Generated using the following Java program:
+// public static void main(String[] foo) throws Exception {
+// FileOutputStream fos = new
+// FileOutputStream("/tmp/data_descriptor.zip");
+// ZipOutputStream zos = new ZipOutputStream(fos);
+// ZipEntry ze = new ZipEntry("name");
+// ze.setMethod(ZipEntry.DEFLATED);
+// zos.putNextEntry(ze);
+// zos.write("abdcdefghijk".getBytes());
+// zos.closeEntry();
+// zos.close();
+// }
+//
+// cat /tmp/data_descriptor.zip | xxd -i
+//
+static const std::vector<uint8_t> kDataDescriptorZipFile{
+ 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6e, 0x61,
+ 0x6d, 0x65, 0x4b, 0x4c, 0x4a, 0x49, 0x4e, 0x49, 0x4d, 0x4b, 0xcf, 0xc8, 0xcc, 0xca, 0x06, 0x00,
+ //[sig---------------], [crc32---------------], [csize---------------], [size----------------]
+ 0x50, 0x4b, 0x07, 0x08, 0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a,
+ 0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x61,
+ 0x6d, 0x65, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+// The offsets of the data descriptor in this file, so we can mess with
+// them later in the test.
+static constexpr uint32_t kDataDescriptorOffset = 48;
+static constexpr uint32_t kCSizeOffset = kDataDescriptorOffset + 8;
+static constexpr uint32_t kSizeOffset = kCSizeOffset + 4;
+
+static void ExtractEntryToMemory(const std::vector<uint8_t>& zip_data,
+ std::vector<uint8_t>* entry_out, int32_t* error_code_out) {
+ TemporaryFile tmp_file;
+ ASSERT_NE(-1, tmp_file.fd);
+ ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &zip_data[0], zip_data.size()));
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "ExtractEntryToMemory", &handle));
+
+ // This function expects a variant of kDataDescriptorZipFile, for look for
+ // an entry whose name is "name" and whose size is 12 (contents =
+ // "abdcdefghijk").
+ ZipEntry entry;
+ ZipString empty_name;
+ SetZipString(&empty_name, "name");
+
+ ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
+ ASSERT_EQ(static_cast<uint32_t>(12), entry.uncompressed_length);
+
+ entry_out->resize(12);
+ (*error_code_out) = ExtractToMemory(handle, &entry, &((*entry_out)[0]), 12);
+
+ CloseArchive(handle);
+}
+
+TEST(ziparchive, ValidDataDescriptors) {
+ std::vector<uint8_t> entry;
+ int32_t error_code = 0;
+ ExtractEntryToMemory(kDataDescriptorZipFile, &entry, &error_code);
+
+ ASSERT_EQ(0, error_code);
+ ASSERT_EQ(12u, entry.size());
+ ASSERT_EQ('a', entry[0]);
+ ASSERT_EQ('k', entry[11]);
+}
+
+TEST(ziparchive, InvalidDataDescriptors) {
+ std::vector<uint8_t> invalid_csize = kDataDescriptorZipFile;
+ invalid_csize[kCSizeOffset] = 0xfe;
+
+ std::vector<uint8_t> entry;
+ int32_t error_code = 0;
+ ExtractEntryToMemory(invalid_csize, &entry, &error_code);
+
+ ASSERT_GT(0, error_code);
+ ASSERT_STREQ("Inconsistent information", ErrorCodeString(error_code));
+
+ std::vector<uint8_t> invalid_size = kDataDescriptorZipFile;
+ invalid_csize[kSizeOffset] = 0xfe;
+
+ error_code = 0;
+ entry.clear();
+ ExtractEntryToMemory(invalid_csize, &entry, &error_code);
+
+ ASSERT_GT(0, error_code);
+ ASSERT_STREQ("Inconsistent information", ErrorCodeString(error_code));
+}
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/toolbox/upstream-netbsd/include/sys/mtio.h b/toolbox/upstream-netbsd/include/sys/mtio.h
deleted file mode 100644
index 8fb5655..0000000
--- a/toolbox/upstream-netbsd/include/sys/mtio.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <linux/mtio.h>