Merge changes Ie2f531bd,I7e418ffe
* changes:
libsnapshot: Remove OnlineKernelSnapshotWriter.
libsnapshot: Remove unused SupportsCopyOperation.
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index c9e097e..bd1e91d 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -276,6 +276,13 @@
return false;
}
+ // WARNING: It's not possible to replace the below with a splice call.
+ // Due to the way debuggerd does many small writes across the pipe,
+ // this would cause splice to copy a page for each write. The second
+ // pipe fills up based on the number of pages being copied, even
+ // though there is not much data being transferred per page. When
+ // the second pipe is full, everything stops since there is nothing
+ // reading the second pipe to clear it.
char buf[1024];
rc = TEMP_FAILURE_RETRY(read(pipe_read.get(), buf, sizeof(buf)));
if (rc == 0) {
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index e20e8d9..26726cf 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -41,22 +41,6 @@
_exit(exit_code);
}
-static std::thread spawn_redirect_thread(unique_fd fd) {
- return std::thread([fd{ std::move(fd) }]() {
- while (true) {
- char buf[BUFSIZ];
- ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, sizeof(buf)));
- if (rc <= 0) {
- return;
- }
-
- if (!android::base::WriteFully(STDOUT_FILENO, buf, rc)) {
- return;
- }
- }
- });
-}
-
int main(int argc, char* argv[]) {
if (argc <= 1) usage(0);
if (argc > 3) usage(1);
@@ -107,14 +91,11 @@
}
}
- unique_fd piperead, pipewrite;
- if (!Pipe(&piperead, &pipewrite)) {
- err(1, "failed to create pipe");
+ unique_fd output_fd(fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0));
+ if (output_fd.get() == -1) {
+ err(1, "failed to fcntl dup stdout");
}
-
- std::thread redirect_thread = spawn_redirect_thread(std::move(piperead));
- if (!debuggerd_trigger_dump(proc_info.pid, dump_type, 0, std::move(pipewrite))) {
- redirect_thread.join();
+ if (!debuggerd_trigger_dump(proc_info.pid, dump_type, 0, std::move(output_fd))) {
if (pid == proc_info.pid) {
errx(1, "failed to dump process %d", pid);
} else {
@@ -122,6 +103,5 @@
}
}
- redirect_thread.join();
return 0;
}
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 39d7fff..4cd6193 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -2759,3 +2759,48 @@
ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
ASSERT_NOT_MATCH(result, kLogMessage);
}
+
+// Disable this test since there is a high liklihood that this would
+// be flaky since it requires 500 messages being in the log.
+TEST_F(CrasherTest, DISABLED_max_log_messages) {
+ StartProcess([]() {
+ for (size_t i = 0; i < 600; i++) {
+ LOG(INFO) << "Message number " << i;
+ }
+ abort();
+ });
+
+ unique_fd output_fd;
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGABRT);
+ int intercept_result;
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_NOT_MATCH(result, "Message number 99");
+ ASSERT_MATCH(result, "Message number 100");
+ ASSERT_MATCH(result, "Message number 599");
+}
+
+TEST_F(CrasherTest, log_with_newline) {
+ StartProcess([]() {
+ LOG(INFO) << "This line has a newline.\nThis is on the next line.";
+ abort();
+ });
+
+ unique_fd output_fd;
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGABRT);
+ int intercept_result;
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_MATCH(result, ":\\s*This line has a newline.");
+ ASSERT_MATCH(result, ":\\s*This is on the next line.");
+}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index baa5bfb..c6a535a 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -566,20 +566,23 @@
process_info = g_callbacks.get_process_info();
}
- // GWP-ASan catches use-after-free and heap-buffer-overflow by using PROT_NONE
- // guard pages, which lead to SEGV. Normally, debuggerd prints a bug report
- // and the process terminates, but in some cases, we actually want to print
- // the bug report and let the signal handler return, and restart the process.
- // In order to do that, we need to disable GWP-ASan's guard pages. The
- // following callbacks handle this case.
- gwp_asan_callbacks_t gwp_asan_callbacks = g_callbacks.get_gwp_asan_callbacks();
- if (signal_number == SIGSEGV && signal_has_si_addr(info) &&
- gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery &&
- gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report &&
- gwp_asan_callbacks.debuggerd_gwp_asan_post_crash_report &&
- gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery(info->si_addr)) {
- gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report(info->si_addr);
- process_info.recoverable_gwp_asan_crash = true;
+ gwp_asan_callbacks_t gwp_asan_callbacks = {};
+ if (g_callbacks.get_gwp_asan_callbacks != nullptr) {
+ // GWP-ASan catches use-after-free and heap-buffer-overflow by using PROT_NONE
+ // guard pages, which lead to SEGV. Normally, debuggerd prints a bug report
+ // and the process terminates, but in some cases, we actually want to print
+ // the bug report and let the signal handler return, and restart the process.
+ // In order to do that, we need to disable GWP-ASan's guard pages. The
+ // following callbacks handle this case.
+ gwp_asan_callbacks = g_callbacks.get_gwp_asan_callbacks();
+ if (signal_number == SIGSEGV && signal_has_si_addr(info) &&
+ gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery &&
+ gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report &&
+ gwp_asan_callbacks.debuggerd_gwp_asan_post_crash_report &&
+ gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery(info->si_addr)) {
+ gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report(info->si_addr);
+ process_info.recoverable_gwp_asan_crash = true;
+ }
}
// If sival_int is ~0, it means that the fallback handler has been called
@@ -764,6 +767,7 @@
bool debuggerd_handle_signal(int signal_number, siginfo_t* info, void* context) {
if (signal_number != SIGSEGV || !signal_has_si_addr(info)) return false;
+ if (g_callbacks.get_gwp_asan_callbacks == nullptr) return false;
gwp_asan_callbacks_t gwp_asan_callbacks = g_callbacks.get_gwp_asan_callbacks();
if (gwp_asan_callbacks.debuggerd_needs_gwp_asan_recovery == nullptr ||
gwp_asan_callbacks.debuggerd_gwp_asan_pre_crash_report == nullptr ||
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index acd814e..7b2e068 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -70,6 +70,9 @@
using android::base::StringPrintf;
+// The maximum number of messages to save in the protobuf per file.
+static constexpr size_t kMaxLogMessages = 500;
+
// Use the demangler from libc++.
extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status);
@@ -491,8 +494,8 @@
}
static void dump_log_file(Tombstone* tombstone, const char* logger, pid_t pid) {
- logger_list* logger_list =
- android_logger_list_open(android_name_to_log_id(logger), ANDROID_LOG_NONBLOCK, 0, pid);
+ logger_list* logger_list = android_logger_list_open(android_name_to_log_id(logger),
+ ANDROID_LOG_NONBLOCK, kMaxLogMessages, pid);
LogBuffer buffer;
diff --git a/debuggerd/seccomp_policy/crash_dump.riscv64.policy b/debuggerd/seccomp_policy/crash_dump.riscv64.policy
index 21887ab..281e231 100644
--- a/debuggerd/seccomp_policy/crash_dump.riscv64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.riscv64.policy
@@ -19,12 +19,13 @@
faccessat: 1
recvmsg: 1
recvfrom: 1
+sysinfo: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
rt_sigaction: 1
rt_tgsigqueueinfo: 1
-prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
mprotect: arg2 in 0x1|0x2
munmap: 1
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index f09616a..7994065 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -396,7 +396,7 @@
ConnectedDevicesStorage storage;
std::set<std::string> devices;
- {
+ if (storage.Exists()) {
FileLock lock = storage.Lock();
devices = storage.ReadDevices(lock);
}
@@ -775,7 +775,7 @@
#endif
-static unique_fd unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
+static unique_fd UnzipToFile(ZipArchiveHandle zip, const char* entry_name) {
unique_fd fd(make_temporary_fd(entry_name));
ZipEntry64 zip_entry;
@@ -1487,13 +1487,20 @@
return partition;
}
-void do_flash(const char* pname, const char* fname, const bool apply_vbmeta) {
+void do_flash(const char* pname, const char* fname, const bool apply_vbmeta,
+ const FlashingPlan* fp) {
verbose("Do flash %s %s", pname, fname);
struct fastboot_buffer buf;
- if (!load_buf(fname, &buf)) {
+ if (fp->source) {
+ unique_fd fd = fp->source->OpenFile(fname);
+ if (fd < 0 || !load_buf_fd(std::move(fd), &buf)) {
+ die("could not load '%s': %s", fname, strerror(errno));
+ }
+ } else if (!load_buf(fname, &buf)) {
die("cannot load '%s': %s", fname, strerror(errno));
}
+
if (is_logical(pname)) {
fb->ResizePartition(pname, std::to_string(buf.image_size));
}
@@ -1592,7 +1599,7 @@
if (img_name.empty()) {
img_name = partition + ".img";
}
- return std::make_unique<FlashTask>(slot, partition, img_name, apply_vbmeta);
+ return std::make_unique<FlashTask>(slot, partition, img_name, apply_vbmeta, fp);
}
std::unique_ptr<RebootTask> ParseRebootCommand(const FlashingPlan* fp,
@@ -1639,14 +1646,22 @@
return task;
}
-void AddResizeTasks(const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>* tasks) {
+bool AddResizeTasks(const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>* tasks) {
// expands "resize-partitions" into individual commands : resize {os_partition_1}, resize
// {os_partition_2}, etc.
std::vector<std::unique_ptr<Task>> resize_tasks;
std::optional<size_t> loc;
+ std::vector<char> contents;
+ if (!fp->source->ReadFile("super_empty.img", &contents)) {
+ return false;
+ }
+ auto metadata = android::fs_mgr::ReadFromImageBlob(contents.data(), contents.size());
+ if (!metadata) {
+ return false;
+ }
for (size_t i = 0; i < tasks->size(); i++) {
if (auto flash_task = tasks->at(i)->AsFlashTask()) {
- if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) {
+ if (should_flash_in_userspace(*metadata.get(), flash_task->GetPartitionAndSlot())) {
if (!loc) {
loc = i;
}
@@ -1658,15 +1673,15 @@
// if no logical partitions (although should never happen since system will always need to be
// flashed)
if (!loc) {
- return;
+ return false;
}
tasks->insert(tasks->begin() + loc.value(), std::make_move_iterator(resize_tasks.begin()),
std::make_move_iterator(resize_tasks.end()));
- return;
+ return true;
}
static bool IsIgnore(const std::vector<std::string>& command) {
- if (command[0][0] == '#') {
+ if (command.size() == 0 || command[0][0] == '#') {
return true;
}
return false;
@@ -1743,21 +1758,13 @@
}
tasks.insert(it, std::move(flash_super_task));
} else {
- AddResizeTasks(fp, &tasks);
+ if (!AddResizeTasks(fp, &tasks)) {
+ LOG(WARNING) << "Failed to add resize tasks";
+ };
}
return tasks;
}
-std::vector<std::unique_ptr<Task>> ParseFastbootInfo(const FlashingPlan* fp, std::ifstream& fs) {
- std::string text;
- std::vector<std::string> file;
- // Get os_partitions that need to be resized
- while (std::getline(fs, text)) {
- file.emplace_back(text);
- }
- return ParseFastbootInfo(fp, file);
-}
-
FlashAllTool::FlashAllTool(FlashingPlan* fp) : fp_(fp) {}
void FlashAllTool::Flash() {
@@ -1777,27 +1784,8 @@
CancelSnapshotIfNeeded();
- std::string path = find_item_given_name("fastboot-info.txt");
- std::ifstream stream(path);
- if (!stream || stream.eof()) {
- LOG(VERBOSE) << "Flashing from hardcoded images. fastboot-info.txt is empty or does not "
- "exist";
- HardcodedFlash();
- return;
- }
-
- std::vector<std::unique_ptr<Task>> tasks = ParseFastbootInfo(fp_, stream);
- if (tasks.empty()) {
- LOG(FATAL) << "Invalid fastboot-info.txt file.";
- }
- LOG(VERBOSE) << "Flashing from fastboot-info.txt";
- for (auto& task : tasks) {
- task->Run();
- }
- if (fp_->wants_wipe) {
- // avoid adding duplicate wipe tasks in fastboot main code.
- fp_->wants_wipe = false;
- }
+ HardcodedFlash();
+ return;
}
void FlashAllTool::CheckRequirements() {
@@ -1930,7 +1918,7 @@
}
unique_fd ZipImageSource::OpenFile(const std::string& name) const {
- return unzip_to_file(zip_, name.c_str());
+ return UnzipToFile(zip_, name.c_str());
}
static void do_update(const char* filename, FlashingPlan* fp) {
@@ -2115,7 +2103,7 @@
}
static bool wipe_super(const android::fs_mgr::LpMetadata& metadata, const std::string& slot,
- std::string* message) {
+ std::string* message, const FlashingPlan* fp) {
auto super_device = GetMetadataSuperBlockDevice(metadata);
auto block_size = metadata.geometry.logical_block_size;
auto super_bdev_name = android::fs_mgr::GetBlockDevicePartitionName(*super_device);
@@ -2155,7 +2143,7 @@
auto image_path = temp_dir.path + "/"s + image_name;
auto flash = [&](const std::string& partition_name) {
- do_flash(partition_name.c_str(), image_path.c_str(), false);
+ do_flash(partition_name.c_str(), image_path.c_str(), false, fp);
};
do_for_partitions(partition, slot, flash, force_slot);
@@ -2164,7 +2152,8 @@
return true;
}
-static void do_wipe_super(const std::string& image, const std::string& slot_override) {
+static void do_wipe_super(const std::string& image, const std::string& slot_override,
+ const FlashingPlan* fp) {
if (access(image.c_str(), R_OK) != 0) {
die("Could not read image: %s", image.c_str());
}
@@ -2179,7 +2168,7 @@
}
std::string message;
- if (!wipe_super(*metadata.get(), slot, &message)) {
+ if (!wipe_super(*metadata.get(), slot, &message, fp)) {
die(message);
}
}
@@ -2476,7 +2465,7 @@
}
if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str());
- FlashTask task(fp->slot_override, pname, fname, is_vbmeta_partition(pname));
+ FlashTask task(fp->slot_override, pname, fname, is_vbmeta_partition(pname), fp.get());
task.Run();
} else if (command == "flash:raw") {
std::string partition = next_arg(&args);
@@ -2571,7 +2560,7 @@
} else {
image = next_arg(&args);
}
- do_wipe_super(image, fp->slot_override);
+ do_wipe_super(image, fp->slot_override, fp.get());
} else if (command == "snapshot-update") {
std::string arg;
if (!args.empty()) {
@@ -2594,10 +2583,13 @@
if (fp->force_flash) {
CancelSnapshotIfNeeded();
}
+ std::vector<std::unique_ptr<Task>> wipe_tasks;
std::vector<std::string> partitions = {"userdata", "cache", "metadata"};
for (const auto& partition : partitions) {
- tasks.emplace_back(std::make_unique<WipeTask>(fp.get(), partition));
+ wipe_tasks.emplace_back(std::make_unique<WipeTask>(fp.get(), partition));
}
+ tasks.insert(tasks.begin(), std::make_move_iterator(wipe_tasks.begin()),
+ std::make_move_iterator(wipe_tasks.end()));
}
if (fp->wants_set_active) {
fb->SetActive(next_active);
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 80b77a0..abdf636 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -124,7 +124,8 @@
bool should_flash_in_userspace(const std::string& partition_name);
bool is_userspace_fastboot();
-void do_flash(const char* pname, const char* fname, const bool apply_vbmeta);
+void do_flash(const char* pname, const char* fname, const bool apply_vbmeta,
+ const FlashingPlan* fp);
void do_for_partitions(const std::string& part, const std::string& slot,
const std::function<void(const std::string&)>& func, bool force_slot);
std::string find_item(const std::string& item);
@@ -143,7 +144,7 @@
const std::vector<std::string>& parts);
std::unique_ptr<Task> ParseFastbootInfoLine(const FlashingPlan* fp,
const std::vector<std::string>& command);
-void AddResizeTasks(const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>& tasks);
+bool AddResizeTasks(const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>& tasks);
std::vector<std::unique_ptr<Task>> ParseFastbootInfo(const FlashingPlan* fp,
const std::vector<std::string>& file);
diff --git a/fastboot/filesystem.h b/fastboot/filesystem.h
index 5f41fbc..c5f9c94 100644
--- a/fastboot/filesystem.h
+++ b/fastboot/filesystem.h
@@ -31,6 +31,7 @@
#endif
std::string GetHomeDirPath();
+bool FileExists(const std::string& path);
bool EnsureDirectoryExists(const std::string& directory_path);
class FileLock {
diff --git a/fastboot/storage.cpp b/fastboot/storage.cpp
index d6e00cf..dc733b9 100644
--- a/fastboot/storage.cpp
+++ b/fastboot/storage.cpp
@@ -23,24 +23,19 @@
#include "util.h"
ConnectedDevicesStorage::ConnectedDevicesStorage() {
- const std::string home_path = GetHomeDirPath();
- if (home_path.empty()) {
- return;
- }
-
- const std::string home_fastboot_path = home_path + kPathSeparator + ".fastboot";
-
- if (!EnsureDirectoryExists(home_fastboot_path)) {
- LOG(FATAL) << "Cannot create directory: " << home_fastboot_path;
- }
+ home_fastboot_path_ = GetHomeDirPath() + kPathSeparator + ".fastboot";
+ devices_path_ = home_fastboot_path_ + kPathSeparator + "devices";
// We're using a separate file for locking because the Windows LockFileEx does not
// permit opening a file stream for the locked file, even within the same process. So,
// we have to use fd or handle API to manipulate the storage files, which makes it
// nearly impossible to fully rewrite a file content without having to recreate it.
// Unfortunately, this is not an option during holding a lock.
- devices_path_ = home_fastboot_path + kPathSeparator + "devices";
- devices_lock_path_ = home_fastboot_path + kPathSeparator + "devices.lock";
+ devices_lock_path_ = home_fastboot_path_ + kPathSeparator + "devices.lock";
+}
+
+bool ConnectedDevicesStorage::Exists() const {
+ return FileExists(devices_path_);
}
void ConnectedDevicesStorage::WriteDevices(const FileLock&, const std::set<std::string>& devices) {
@@ -63,5 +58,8 @@
}
FileLock ConnectedDevicesStorage::Lock() const {
+ if (!EnsureDirectoryExists(home_fastboot_path_)) {
+ LOG(FATAL) << "Cannot create directory: " << home_fastboot_path_;
+ }
return FileLock(devices_lock_path_);
}
\ No newline at end of file
diff --git a/fastboot/storage.h b/fastboot/storage.h
index 0cc3d86..ae9d846 100644
--- a/fastboot/storage.h
+++ b/fastboot/storage.h
@@ -24,13 +24,15 @@
class ConnectedDevicesStorage {
public:
ConnectedDevicesStorage();
+
+ bool Exists() const;
void WriteDevices(const FileLock&, const std::set<std::string>& devices);
std::set<std::string> ReadDevices(const FileLock&);
void Clear(const FileLock&);
-
FileLock Lock() const;
private:
+ std::string home_fastboot_path_;
std::string devices_path_;
std::string devices_lock_path_;
};
\ No newline at end of file
diff --git a/fastboot/task.cpp b/fastboot/task.cpp
index ce46e91..03f9b89 100644
--- a/fastboot/task.cpp
+++ b/fastboot/task.cpp
@@ -26,9 +26,9 @@
#include "util.h"
using namespace std::string_literals;
-FlashTask::FlashTask(const std::string& _slot, const std::string& _pname, const std::string& _fname,
- const bool apply_vbmeta)
- : pname_(_pname), fname_(_fname), slot_(_slot), apply_vbmeta_(apply_vbmeta) {}
+FlashTask::FlashTask(const std::string& slot, const std::string& pname, const std::string& fname,
+ const bool apply_vbmeta, const FlashingPlan* fp)
+ : pname_(pname), fname_(fname), slot_(slot), apply_vbmeta_(apply_vbmeta), fp_(fp) {}
void FlashTask::Run() {
auto flash = [&](const std::string& partition) {
@@ -41,11 +41,19 @@
"And try again. If you are intentionally trying to "
"overwrite a fixed partition, use --force.");
}
- do_flash(partition.c_str(), fname_.c_str(), apply_vbmeta_);
+ do_flash(partition.c_str(), fname_.c_str(), apply_vbmeta_, fp_);
};
do_for_partitions(pname_, slot_, flash, true);
}
+std::string FlashTask::ToString() {
+ std::string apply_vbmeta_string = "";
+ if (apply_vbmeta_) {
+ apply_vbmeta_string = " --apply_vbmeta";
+ }
+ return "flash" + apply_vbmeta_string + " " + pname_ + " " + fname_;
+}
+
std::string FlashTask::GetPartitionAndSlot() {
auto slot = slot_;
if (slot.empty()) {
@@ -84,6 +92,10 @@
}
}
+std::string RebootTask::ToString() {
+ return "reboot " + reboot_target_;
+}
+
FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name,
std::unique_ptr<SuperFlashHelper> helper,
SparsePtr sparse_layout, uint64_t super_size)
@@ -106,6 +118,9 @@
// Send the data to the device.
flash_partition_files(super_name_, files);
}
+std::string FlashSuperLayoutTask::ToString() {
+ return "optimized-flash-super";
+}
std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize(
const FlashingPlan* fp, std::vector<ImageEntry>& os_images) {
@@ -214,11 +229,9 @@
for (const auto& task : tasks) {
if (auto flash_task = task->AsFlashTask()) {
- if (should_flash_in_userspace(flash_task->GetPartitionAndSlot())) {
- auto partition = flash_task->GetPartitionAndSlot();
- if (!helper->AddPartition(partition, flash_task->GetImageName(), false)) {
- return nullptr;
- }
+ auto partition = flash_task->GetPartitionAndSlot();
+ if (!helper->AddPartition(partition, flash_task->GetImageName(), false)) {
+ return nullptr;
}
}
}
@@ -265,6 +278,9 @@
}
fp_->fb->RawCommand(command, "Updating super partition");
}
+std::string UpdateSuperTask::ToString() {
+ return "update-super";
+}
ResizeTask::ResizeTask(const FlashingPlan* fp, const std::string& pname, const std::string& size,
const std::string& slot)
@@ -279,12 +295,20 @@
do_for_partitions(pname_, slot_, resize_partition, false);
}
+std::string ResizeTask::ToString() {
+ return "resize " + pname_;
+}
+
DeleteTask::DeleteTask(const FlashingPlan* fp, const std::string& pname) : fp_(fp), pname_(pname){};
void DeleteTask::Run() {
fp_->fb->DeletePartition(pname_);
}
+std::string DeleteTask::ToString() {
+ return "delete " + pname_;
+}
+
WipeTask::WipeTask(const FlashingPlan* fp, const std::string& pname) : fp_(fp), pname_(pname){};
void WipeTask::Run() {
@@ -300,3 +324,7 @@
}
fb_perform_format(pname_, 1, partition_type, "", fp_->fs_options);
}
+
+std::string WipeTask::ToString() {
+ return "erase " + pname_;
+}
diff --git a/fastboot/task.h b/fastboot/task.h
index 34e3e92..500655d 100644
--- a/fastboot/task.h
+++ b/fastboot/task.h
@@ -35,6 +35,8 @@
public:
Task() = default;
virtual void Run() = 0;
+ virtual std::string ToString() = 0;
+
virtual FlashTask* AsFlashTask() { return nullptr; }
virtual RebootTask* AsRebootTask() { return nullptr; }
virtual UpdateSuperTask* AsUpdateSuperTask() { return nullptr; }
@@ -46,20 +48,22 @@
class FlashTask : public Task {
public:
FlashTask(const std::string& slot, const std::string& pname, const std::string& fname,
- const bool apply_vbmeta);
+ const bool apply_vbmeta, const FlashingPlan* fp);
virtual FlashTask* AsFlashTask() override { return this; }
+ void Run() override;
+ std::string ToString() override;
std::string GetPartition() { return pname_; }
std::string GetImageName() { return fname_; }
- std::string GetPartitionAndSlot();
std::string GetSlot() { return slot_; }
- void Run() override;
+ std::string GetPartitionAndSlot();
private:
const std::string pname_;
const std::string fname_;
const std::string slot_;
const bool apply_vbmeta_;
+ const FlashingPlan* fp_;
};
class RebootTask : public Task {
@@ -68,6 +72,7 @@
RebootTask(const FlashingPlan* fp, const std::string& reboot_target);
virtual RebootTask* AsRebootTask() override { return this; }
void Run() override;
+ std::string ToString() override;
private:
const std::string reboot_target_ = "";
@@ -84,6 +89,7 @@
const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>& tasks);
using ImageEntry = std::pair<const Image*, std::string>;
void Run() override;
+ std::string ToString() override;
private:
const std::string super_name_;
@@ -98,6 +104,7 @@
virtual UpdateSuperTask* AsUpdateSuperTask() override { return this; }
void Run() override;
+ std::string ToString() override;
private:
const FlashingPlan* fp_;
@@ -108,6 +115,7 @@
ResizeTask(const FlashingPlan* fp, const std::string& pname, const std::string& size,
const std::string& slot);
void Run() override;
+ std::string ToString() override;
private:
const FlashingPlan* fp_;
@@ -118,8 +126,9 @@
class DeleteTask : public Task {
public:
- DeleteTask(const FlashingPlan* _fp, const std::string& _pname);
+ DeleteTask(const FlashingPlan* fp, const std::string& pname);
void Run() override;
+ std::string ToString() override;
private:
const FlashingPlan* fp_;
@@ -130,8 +139,8 @@
public:
WipeTask(const FlashingPlan* fp, const std::string& pname);
virtual WipeTask* AsWipeTask() override { return this; }
-
void Run() override;
+ std::string ToString() override;
private:
const FlashingPlan* fp_;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 598a3d2..c3c10ba 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -242,7 +242,9 @@
LWARNING << "Warning: zramsize= flag malformed: " << arg;
}
}
- } else if (StartsWith(flag, "fileencryption=")) {
+ } else if (StartsWith(flag, "fileencryption=") || flag == "fileencryption") {
+ // "fileencryption" enables file-based encryption. It's normally followed by an = and
+ // then the encryption options. But that can be omitted to use the default options.
ParseFileEncryption(arg, entry);
} else if (StartsWith(flag, "max_comp_streams=")) {
if (!ParseInt(arg, &entry->max_comp_streams)) {
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index ef436e5..f04fc8d 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -1083,7 +1083,7 @@
return 0;
}
- auto ideal_size = std::min(super_info.size, uint64_t(s.f_frsize * s.f_bfree * 0.85));
+ auto ideal_size = std::min(super_info.size, uint64_t(uint64_t(s.f_frsize) * s.f_bfree * 0.85));
// Align up to the filesystem block size.
if (auto remainder = ideal_size % s.f_bsize; remainder > 0) {
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 5deba65..ddda648 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -93,6 +93,9 @@
test_options: {
min_shipping_api_level: 29,
},
+ header_libs: [
+ "libstorage_literals_headers",
+ ],
require_root: true,
}
diff --git a/fs_mgr/libfiemap/fiemap_writer_test.cpp b/fs_mgr/libfiemap/fiemap_writer_test.cpp
index c65481b..bd97a78 100644
--- a/fs_mgr/libfiemap/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer_test.cpp
@@ -22,21 +22,25 @@
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
+#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <unistd.h>
#include <string>
+#include <utility>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
+#include <fstab/fstab.h>
#include <gtest/gtest.h>
#include <libdm/loop_control.h>
#include <libfiemap/fiemap_writer.h>
#include <libfiemap/split_fiemap_writer.h>
#include <libgsi/libgsi.h>
+#include <storage_literals/storage_literals.h>
#include "utility.h"
@@ -46,6 +50,7 @@
using namespace std;
using namespace std::string_literals;
using namespace android::fiemap;
+using namespace android::storage_literals;
using unique_fd = android::base::unique_fd;
using LoopDevice = android::dm::LoopDevice;
@@ -427,90 +432,123 @@
ASSERT_FALSE(ptr->Write(buffer.get(), kSize));
}
-class VerifyBlockWritesExt4 : public ::testing::Test {
+// Get max file size and free space.
+std::pair<uint64_t, uint64_t> GetBigFileLimit(const std::string& mount_point) {
+ struct statvfs fs;
+ if (statvfs(mount_point.c_str(), &fs) < 0) {
+ PLOG(ERROR) << "statfs failed";
+ return {0, 0};
+ }
+
+ auto fs_limit = static_cast<uint64_t>(fs.f_blocks) * (fs.f_bsize - 1);
+ auto fs_free = static_cast<uint64_t>(fs.f_bfree) * fs.f_bsize;
+
+ LOG(INFO) << "Big file limit: " << fs_limit << ", free space: " << fs_free;
+
+ return {fs_limit, fs_free};
+}
+
+class FsTest : public ::testing::Test {
+ protected:
// 2GB Filesystem and 4k block size by default
static constexpr uint64_t block_size = 4096;
- static constexpr uint64_t fs_size = 2147483648;
+ static constexpr uint64_t fs_size = 64 * 1024 * 1024;
- protected:
- void SetUp() override {
- fs_path = std::string(getenv("TMPDIR")) + "/ext4_2G.img";
+ void SetUp() {
+ android::fs_mgr::Fstab fstab;
+ ASSERT_TRUE(android::fs_mgr::ReadFstabFromFile("/proc/mounts", &fstab));
+
+ ASSERT_EQ(access(tmpdir_.path, F_OK), 0);
+ fs_path_ = tmpdir_.path + "/fs_image"s;
+ mntpoint_ = tmpdir_.path + "/mnt_point"s;
+
+ auto entry = android::fs_mgr::GetEntryForMountPoint(&fstab, "/data");
+ ASSERT_NE(entry, nullptr);
+ if (entry->fs_type == "ext4") {
+ SetUpExt4();
+ } else if (entry->fs_type == "f2fs") {
+ SetUpF2fs();
+ } else {
+ FAIL() << "Unrecognized fs_type: " << entry->fs_type;
+ }
+ }
+
+ void SetUpExt4() {
uint64_t count = fs_size / block_size;
std::string dd_cmd =
::android::base::StringPrintf("/system/bin/dd if=/dev/zero of=%s bs=%" PRIu64
" count=%" PRIu64 " > /dev/null 2>&1",
- fs_path.c_str(), block_size, count);
+ fs_path_.c_str(), block_size, count);
std::string mkfs_cmd =
- ::android::base::StringPrintf("/system/bin/mkfs.ext4 -q %s", fs_path.c_str());
+ ::android::base::StringPrintf("/system/bin/mkfs.ext4 -q %s", fs_path_.c_str());
// create mount point
- mntpoint = std::string(getenv("TMPDIR")) + "/fiemap_mnt";
- ASSERT_EQ(mkdir(mntpoint.c_str(), S_IRWXU), 0);
+ ASSERT_EQ(mkdir(mntpoint_.c_str(), S_IRWXU), 0);
// create file for the file system
int ret = system(dd_cmd.c_str());
ASSERT_EQ(ret, 0);
// Get and attach a loop device to the filesystem we created
- LoopDevice loop_dev(fs_path, 10s);
+ LoopDevice loop_dev(fs_path_, 10s);
ASSERT_TRUE(loop_dev.valid());
// create file system
ret = system(mkfs_cmd.c_str());
ASSERT_EQ(ret, 0);
// mount the file system
- ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "ext4", 0, nullptr), 0);
+ ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "ext4", 0, nullptr), 0);
}
- void TearDown() override {
- umount(mntpoint.c_str());
- rmdir(mntpoint.c_str());
- unlink(fs_path.c_str());
- }
-
- std::string mntpoint;
- std::string fs_path;
-};
-
-class VerifyBlockWritesF2fs : public ::testing::Test {
- // 2GB Filesystem and 4k block size by default
- static constexpr uint64_t block_size = 4096;
- static constexpr uint64_t fs_size = 2147483648;
-
- protected:
- void SetUp() override {
- fs_path = std::string(getenv("TMPDIR")) + "/f2fs_2G.img";
+ void SetUpF2fs() {
uint64_t count = fs_size / block_size;
std::string dd_cmd =
::android::base::StringPrintf("/system/bin/dd if=/dev/zero of=%s bs=%" PRIu64
" count=%" PRIu64 " > /dev/null 2>&1",
- fs_path.c_str(), block_size, count);
+ fs_path_.c_str(), block_size, count);
std::string mkfs_cmd =
- ::android::base::StringPrintf("/system/bin/make_f2fs -q %s", fs_path.c_str());
+ ::android::base::StringPrintf("/system/bin/make_f2fs -q %s", fs_path_.c_str());
// create mount point
- mntpoint = std::string(getenv("TMPDIR")) + "/fiemap_mnt";
- ASSERT_EQ(mkdir(mntpoint.c_str(), S_IRWXU), 0);
+ ASSERT_EQ(mkdir(mntpoint_.c_str(), S_IRWXU), 0);
// create file for the file system
int ret = system(dd_cmd.c_str());
ASSERT_EQ(ret, 0);
// Get and attach a loop device to the filesystem we created
- LoopDevice loop_dev(fs_path, 10s);
+ LoopDevice loop_dev(fs_path_, 10s);
ASSERT_TRUE(loop_dev.valid());
// create file system
ret = system(mkfs_cmd.c_str());
ASSERT_EQ(ret, 0);
// mount the file system
- ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "f2fs", 0, nullptr), 0);
+ ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "f2fs", 0, nullptr), 0);
}
void TearDown() override {
- umount(mntpoint.c_str());
- rmdir(mntpoint.c_str());
- unlink(fs_path.c_str());
+ umount(mntpoint_.c_str());
+ rmdir(mntpoint_.c_str());
+ unlink(fs_path_.c_str());
}
- std::string mntpoint;
- std::string fs_path;
+ TemporaryDir tmpdir_;
+ std::string mntpoint_;
+ std::string fs_path_;
};
+TEST_F(FsTest, LowSpaceError) {
+ auto limits = GetBigFileLimit(mntpoint_);
+ ASSERT_GE(limits.first, 0);
+
+ FiemapUniquePtr ptr;
+
+ auto test_file = mntpoint_ + "/big_file";
+ auto status = FiemapWriter::Open(test_file, limits.first, &ptr);
+ ASSERT_FALSE(status.is_ok());
+ ASSERT_EQ(status.error_code(), FiemapStatus::ErrorCode::NO_SPACE);
+
+ // Also test for EFBIG.
+ status = FiemapWriter::Open(test_file, 16_TiB, &ptr);
+ ASSERT_FALSE(status.is_ok());
+ ASSERT_NE(status.error_code(), FiemapStatus::ErrorCode::NO_SPACE);
+}
+
bool DetermineBlockSize() {
struct statfs s;
if (statfs(gTestDir.c_str(), &s)) {
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 7cdb8ed..757f6f1 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -2389,60 +2389,6 @@
<< "FinishedSnapshotWrites should detect overflow of CoW device.";
}
-// Get max file size and free space.
-std::pair<uint64_t, uint64_t> GetBigFileLimit() {
- struct statvfs fs;
- if (statvfs("/data", &fs) < 0) {
- PLOG(ERROR) << "statfs failed";
- return {0, 0};
- }
-
- auto fs_limit = static_cast<uint64_t>(fs.f_blocks) * (fs.f_bsize - 1);
- auto fs_free = static_cast<uint64_t>(fs.f_bfree) * fs.f_bsize;
-
- LOG(INFO) << "Big file limit: " << fs_limit << ", free space: " << fs_free;
-
- return {fs_limit, fs_free};
-}
-
-TEST_F(SnapshotUpdateTest, LowSpace) {
- // To make the low space test more reliable, we force a large cow estimate.
- // However legacy VAB ignores the COW estimate and uses InstallOperations
- // to compute the exact size required for dm-snapshot. It's difficult to
- // make this work reliably (we'd need to somehow fake an extremely large
- // super partition, and we don't have that level of dependency injection).
- //
- // For now, just skip this test on legacy VAB.
- if (!snapuserd_required_) {
- GTEST_SKIP() << "Skipping test on legacy VAB";
- }
-
- auto fs = GetBigFileLimit();
- ASSERT_NE(fs.first, 0);
-
- constexpr uint64_t partition_size = 10_MiB;
- SetSize(sys_, partition_size);
- SetSize(vnd_, partition_size);
- SetSize(prd_, partition_size);
- sys_->set_estimate_cow_size(fs.first);
- vnd_->set_estimate_cow_size(fs.first);
- prd_->set_estimate_cow_size(fs.first);
-
- AddOperationForPartitions();
-
- // Execute the update.
- ASSERT_TRUE(sm->BeginUpdate());
- auto res = sm->CreateUpdateSnapshots(manifest_);
- ASSERT_FALSE(res);
- ASSERT_EQ(Return::ErrorCode::NO_SPACE, res.error_code());
-
- // It's hard to predict exactly how much free space is needed, since /data
- // is writable and the test is not the only process running. Divide by two
- // as a rough lower bound, and adjust this in the future as necessary.
- auto expected_delta = fs.first - fs.second;
- ASSERT_GE(res.required_size(), expected_delta / 2);
-}
-
TEST_F(SnapshotUpdateTest, AddPartition) {
group_->add_partition_names("dlkm");
@@ -2831,38 +2777,6 @@
"Merge"s;
});
-class ImageManagerTest : public SnapshotTest {
- protected:
- void SetUp() override {
- SKIP_IF_NON_VIRTUAL_AB();
- SnapshotTest::SetUp();
- }
- void TearDown() override {
- RETURN_IF_NON_VIRTUAL_AB();
- CleanUp();
- SnapshotTest::TearDown();
- }
- void CleanUp() {
- if (!image_manager_) {
- return;
- }
- EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) ||
- image_manager_->DeleteBackingImage(kImageName));
- }
-
- static constexpr const char* kImageName = "my_image";
-};
-
-TEST_F(ImageManagerTest, CreateImageNoSpace) {
- auto fs = GetBigFileLimit();
- ASSERT_NE(fs.first, 0);
-
- auto res = image_manager_->CreateBackingImage(kImageName, fs.first,
- IImageManager::CREATE_IMAGE_DEFAULT);
- ASSERT_FALSE(res);
- ASSERT_EQ(res.error_code(), FiemapStatus::ErrorCode::NO_SPACE) << res.string();
-}
-
bool Mkdir(const std::string& path) {
if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
diff --git a/fs_mgr/libstorage_literals/storage_literals/storage_literals.h b/fs_mgr/libstorage_literals/storage_literals/storage_literals.h
index ac0dfbd..bbeabd5 100644
--- a/fs_mgr/libstorage_literals/storage_literals/storage_literals.h
+++ b/fs_mgr/libstorage_literals/storage_literals/storage_literals.h
@@ -37,6 +37,7 @@
using KiB = Size<10>;
using MiB = Size<20>;
using GiB = Size<30>;
+using TiB = Size<40>;
constexpr B operator""_B(unsigned long long v) { // NOLINT
return B{v};
@@ -54,6 +55,10 @@
return GiB{v};
}
+constexpr TiB operator""_TiB(unsigned long long v) { // NOLINT
+ return TiB{v};
+}
+
template <typename Dest, typename Src>
constexpr Dest size_cast(Src src) {
if (Src::power < Dest::power) {
@@ -69,6 +74,7 @@
static_assert(1_KiB == 1 << 10);
static_assert(1_MiB == 1 << 20);
static_assert(1_GiB == 1 << 30);
+static_assert(1_TiB == 1ULL << 40);
static_assert(size_cast<KiB>(1_B).count() == 0);
static_assert(size_cast<KiB>(1024_B).count() == 1);
static_assert(size_cast<KiB>(1_MiB).count() == 1024);
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index e33681c..5f889ca 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -497,6 +497,7 @@
EXPECT_EQ("none0", entry->mount_point);
{
FstabEntry::FsMgrFlags flags = {};
+ flags.file_encryption = true;
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
EXPECT_EQ("", entry->metadata_key_dir);
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
index bb2ceb9..4d771fa 100644
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ b/fs_mgr/tests/vts_fs_test.cpp
@@ -55,6 +55,21 @@
}
TEST(fs, PartitionTypes) {
+ // Requirements only apply to Android 13+, 5.10+ devices.
+ int vsr_level = GetVsrLevel();
+ if (vsr_level < __ANDROID_API_T__) {
+ GTEST_SKIP();
+ }
+
+ struct utsname uts;
+ ASSERT_EQ(uname(&uts), 0);
+
+ unsigned int major, minor;
+ ASSERT_EQ(sscanf(uts.release, "%u.%u", &major, &minor), 2);
+ if (major < 5 || (major == 5 && minor < 10)) {
+ GTEST_SKIP();
+ }
+
android::fs_mgr::Fstab fstab;
ASSERT_TRUE(android::fs_mgr::ReadFstabFromFile("/proc/mounts", &fstab));
@@ -64,12 +79,7 @@
ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/super", &super_bdev));
ASSERT_TRUE(android::base::Readlink("/dev/block/by-name/userdata", &userdata_bdev));
- int vsr_level = GetVsrLevel();
-
- std::vector<std::string> must_be_f2fs;
- if (vsr_level >= __ANDROID_API_T__) {
- must_be_f2fs.emplace_back("/data");
- }
+ std::vector<std::string> must_be_f2fs = {"/data"};
if (vsr_level >= __ANDROID_API_U__) {
must_be_f2fs.emplace_back("/metadata");
}
@@ -98,17 +108,13 @@
continue;
}
- if (vsr_level < __ANDROID_API_T__) {
- continue;
- }
- if (vsr_level == __ANDROID_API_T__ && parent_bdev != super_bdev) {
- // Only check for dynamic partitions at this VSR level.
- continue;
- }
-
if (entry.flags & MS_RDONLY) {
- std::vector<std::string> allowed = {"erofs", "ext4", "f2fs"};
+ if (parent_bdev != super_bdev) {
+ // Ignore non-AOSP partitions (eg anything outside of super).
+ continue;
+ }
+ std::vector<std::string> allowed = {"erofs", "ext4", "f2fs"};
EXPECT_NE(std::find(allowed.begin(), allowed.end(), entry.fs_type), allowed.end())
<< entry.mount_point;
} else {
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index f68d65a..bd7955a 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -244,6 +244,8 @@
value = BatteryHealth::UNSPECIFIED_FAILURE;
else if (status == BatteryMonitor::BH_NOT_AVAILABLE)
value = BatteryHealth::NOT_AVAILABLE;
+ else if (status == BatteryMonitor::BH_INCONSISTENT)
+ value = BatteryHealth::INCONSISTENT;
else
value = BatteryHealth::UNKNOWN;
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index a4c013b..e9998ba 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -63,6 +63,7 @@
BH_NEEDS_REPLACEMENT,
BH_FAILED,
BH_NOT_AVAILABLE,
+ BH_INCONSISTENT,
};
BatteryMonitor();
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index b9fa58c..3c012fe 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -33,6 +33,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/scopeguard.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -43,6 +44,7 @@
using android::base::Timer;
using android::base::Trim;
using android::base::unique_fd;
+using android::base::WaitForProperty;
using android::base::WriteFully;
namespace android {
@@ -82,6 +84,33 @@
return access("/dev/.booting", F_OK) == 0;
}
+static bool IsApexActivated() {
+ static bool apex_activated = []() {
+ // Wait for com.android.runtime.apex activation
+ // Property name and value must be kept in sync with system/apexd/apex/apex_constants.h
+ // 60s is the default firmware sysfs fallback timeout. (/sys/class/firmware/timeout)
+ if (!WaitForProperty("apexd.status", "activated", 60s)) {
+ LOG(ERROR) << "Apexd activation wait timeout";
+ return false;
+ }
+ return true;
+ }();
+
+ return apex_activated;
+}
+
+static bool NeedsRerunExternalHandler() {
+ static bool first = true;
+
+ // Rerun external handler only on the first try and when apex is activated
+ if (first) {
+ first = false;
+ return IsApexActivated();
+ }
+
+ return first;
+}
+
ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid,
std::string handler_path)
: devpath(std::move(devpath)), uid(uid), gid(gid), handler_path(std::move(handler_path)) {
@@ -210,6 +239,11 @@
auto result = RunExternalHandler(external_handler.handler_path, external_handler.uid,
external_handler.gid, uevent);
+ if (!result.ok() && NeedsRerunExternalHandler()) {
+ auto res = RunExternalHandler(external_handler.handler_path, external_handler.uid,
+ external_handler.gid, uevent);
+ result = std::move(res);
+ }
if (!result.ok()) {
LOG(ERROR) << "Using default firmware; External firmware handler failed: "
<< result.error();
diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp
index 227380d..d9fcd9d 100644
--- a/init/test_kill_services/init_kill_services_test.cpp
+++ b/init/test_kill_services/init_kill_services_test.cpp
@@ -23,8 +23,15 @@
using ::android::base::GetProperty;
using ::android::base::SetProperty;
+using ::android::base::WaitForProperty;
+using std::literals::chrono_literals::operator""s;
void ExpectKillingServiceRecovers(const std::string& service_name) {
+ // b/280514080 - servicemanager will restart apexd, and apexd will restart the
+ // system when crashed. This is fine as the device recovers, but it causes
+ // flakes in this test.
+ ASSERT_TRUE(WaitForProperty("init.svc.apexd", "stopped", 60s)) << "apexd won't stop";
+
LOG(INFO) << "hello " << service_name << "!";
const std::string status_prop = "init.svc." + service_name;
const std::string pid_prop = "init.svc_debug_pid." + service_name;
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index b135e57..0b5c125 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -286,11 +286,14 @@
],
}
+always_static_test_libraries = [
+ "libjsoncpp",
+]
+
test_libraries = [
"libcutils",
"liblog",
"libbase",
- "libjsoncpp",
"libprocessgroup",
"libcgrouprc",
]
@@ -301,6 +304,7 @@
defaults: ["libcutils_test_default"],
host_supported: true,
shared_libs: test_libraries,
+ static_libs: always_static_test_libraries,
require_root: true,
}
@@ -310,7 +314,7 @@
static_libs: [
"libc",
"libcgrouprc_format",
- ] + test_libraries,
+ ] + test_libraries + always_static_test_libraries,
stl: "libc++_static",
require_root: true,
diff --git a/libcutils/KernelLibcutilsTest.xml b/libcutils/KernelLibcutilsTest.xml
index 40e4ef4..9750cbf 100644
--- a/libcutils/KernelLibcutilsTest.xml
+++ b/libcutils/KernelLibcutilsTest.xml
@@ -22,11 +22,11 @@
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
- <option name="push" value="KernelLibcutilsTest->/data/local/tmp/KernelLibcutilsTest" />
+ <option name="push" value="KernelLibcutilsTest->/data/local/tests/unrestricted/KernelLibcutilsTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="native-test-device-path" value="/data/local/tests/unrestricted" />
<option name="module-name" value="KernelLibcutilsTest" />
<option name="include-filter" value="*AshmemTest*" />
</test>
diff --git a/libcutils/TEST_MAPPING b/libcutils/TEST_MAPPING
index eb63aa5..78b3e44 100644
--- a/libcutils/TEST_MAPPING
+++ b/libcutils/TEST_MAPPING
@@ -12,6 +12,9 @@
"kernel-presubmit": [
{
"name": "libcutils_test"
+ },
+ {
+ "name": "KernelLibcutilsTest"
}
]
}
diff --git a/libdiskconfig/Android.bp b/libdiskconfig/Android.bp
deleted file mode 100644
index f523d4e..0000000
--- a/libdiskconfig/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_library {
- name: "libdiskconfig",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
- srcs: [
- "diskconfig.c",
- "diskutils.c",
- "write_lst.c",
- "config_mbr.c",
- ],
-
- shared_libs: [
- "libcutils",
- "liblog",
- ],
- cflags: ["-Werror"],
- export_include_dirs: ["include"],
- local_include_dirs: ["include"],
-
- target: {
- darwin: {
- enabled: false,
- },
- host_linux: {
- cflags: [
- "-D_LARGEFILE64_SOURCE",
- ],
- },
- },
-}
diff --git a/libdiskconfig/config_mbr.c b/libdiskconfig/config_mbr.c
deleted file mode 100644
index ace9bbf..0000000
--- a/libdiskconfig/config_mbr.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/* libs/diskconfig/diskconfig.c
- *
- * Copyright 2008, 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.
- */
-
-#define LOG_TAG "config_mbr"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <diskconfig/diskconfig.h>
-#include <log/log.h>
-
-/* start and len are in LBA units */
-static void
-cfg_pentry(struct pc_partition *pentry, uint8_t status, uint8_t type,
- uint32_t start, uint32_t len)
-{
- if (len > 0) {
- /* seems that somes BIOSens can get wedged on boot while verifying
- * the mbr if these are 0 */
- memset(&pentry->start, 0xff, sizeof(struct chs));
- memset(&pentry->end, 0xff, sizeof(struct chs));
- } else {
- /* zero out the c/h/s entries.. they are not used */
- memset(&pentry->start, 0, sizeof(struct chs));
- memset(&pentry->end, 0, sizeof(struct chs));
- }
-
- pentry->status = status;
- pentry->type = type;
- pentry->start_lba = start;
- pentry->len_lba = len;
-
- ALOGI("Configuring pentry. status=0x%x type=0x%x start_lba=%u len_lba=%u",
- pentry->status, pentry->type, pentry->start_lba, pentry->len_lba);
-}
-
-
-static inline uint32_t
-kb_to_lba(uint32_t len_kb, uint32_t sect_size)
-{
- uint64_t lba;
-
- lba = (uint64_t)len_kb * 1024;
- /* bump it up to the next LBA boundary just in case */
- lba = (lba + (uint64_t)sect_size - 1) & ~((uint64_t)sect_size - 1);
- lba /= (uint64_t)sect_size;
- if (lba >= 0xffffffffULL)
- ALOGE("Error converting kb -> lba. 32bit overflow, expect weirdness");
- return (uint32_t)(lba & 0xffffffffULL);
-}
-
-
-static struct write_list *
-mk_pri_pentry(struct disk_info *dinfo, struct part_info *pinfo, int pnum,
- uint32_t *lba)
-{
- struct write_list *item;
- struct pc_partition *pentry;
-
- if (pnum >= PC_NUM_BOOT_RECORD_PARTS) {
- ALOGE("Maximum number of primary partition exceeded.");
- return NULL;
- }
-
- if (!(item = alloc_wl(sizeof(struct pc_partition)))) {
- ALOGE("Unable to allocate memory for partition entry.");
- return NULL;
- }
-
- {
- /* DO NOT DEREFERENCE */
- struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET;
- /* grab the offset in mbr where to write this partition entry. */
- item->offset = (loff_t)((uintptr_t)((uint8_t *)(&mbr->ptable[pnum])));
- }
-
- pentry = (struct pc_partition *) &item->data;
-
- /* need a standard primary partition entry */
- if (pinfo) {
- /* need this to be 64 bit in case len_kb is large */
- uint64_t len_lba;
-
- if (pinfo->len_kb != (uint32_t)-1) {
- /* bump it up to the next LBA boundary just in case */
- len_lba = ((uint64_t)pinfo->len_kb * 1024);
- len_lba += ((uint64_t)dinfo->sect_size - 1);
- len_lba &= ~((uint64_t)dinfo->sect_size - 1);
- len_lba /= (uint64_t)dinfo->sect_size;
- } else {
- /* make it fill the rest of disk */
- len_lba = dinfo->num_lba - *lba;
- }
-
- cfg_pentry(pentry, ((pinfo->flags & PART_ACTIVE_FLAG) ?
- PC_PART_ACTIVE : PC_PART_NORMAL),
- pinfo->type, *lba, (uint32_t)len_lba);
-
- pinfo->start_lba = *lba;
- *lba += (uint32_t)len_lba;
- } else {
- /* this should be made an extended partition, and should take
- * up the rest of the disk as a primary partition */
- cfg_pentry(pentry, PC_PART_NORMAL, PC_PART_TYPE_EXTENDED,
- *lba, dinfo->num_lba - *lba);
-
- /* note that we do not update the *lba because we now have to
- * create a chain of extended partition tables, and first one is at
- * *lba */
- }
-
- return item;
-}
-
-
-/* This function configures an extended boot record at the beginning of an
- * extended partition. This creates a logical partition and a pointer to
- * the next EBR.
- *
- * ext_lba == The start of the toplevel extended partition (pointed to by the
- * entry in the MBR).
- */
-static struct write_list *
-mk_ext_pentry(struct disk_info *dinfo, struct part_info *pinfo, uint32_t *lba,
- uint32_t ext_lba, struct part_info *pnext)
-{
- struct write_list *item;
- struct pc_boot_record *ebr;
- uint32_t len; /* in lba units */
-
- if (!(item = alloc_wl(sizeof(struct pc_boot_record)))) {
- ALOGE("Unable to allocate memory for EBR.");
- return NULL;
- }
-
- /* we are going to write the ebr at the current LBA, and then bump the
- * lba counter since that is where the logical data partition will start */
- item->offset = ((loff_t)(*lba)) * dinfo->sect_size;
- (*lba)++;
-
- ebr = (struct pc_boot_record *) &item->data;
- memset(ebr, 0, sizeof(struct pc_boot_record));
- ebr->mbr_sig = PC_BIOS_BOOT_SIG;
-
- if (pinfo->len_kb != (uint32_t)-1)
- len = kb_to_lba(pinfo->len_kb, dinfo->sect_size);
- else {
- if (pnext) {
- ALOGE("Only the last partition can be specified to fill the disk "
- "(name = '%s')", pinfo->name);
- goto fail;
- }
- len = dinfo->num_lba - *lba;
- /* update the pinfo structure to reflect the new size, for
- * bookkeeping */
- pinfo->len_kb =
- (uint32_t)(((uint64_t)len * (uint64_t)dinfo->sect_size) /
- ((uint64_t)1024));
- }
-
- cfg_pentry(&ebr->ptable[PC_EBR_LOGICAL_PART], PC_PART_NORMAL,
- pinfo->type, 1, len);
-
- pinfo->start_lba = *lba;
- *lba += len;
-
- /* If this is not the last partition, we have to create a link to the
- * next extended partition.
- *
- * Otherwise, there's nothing to do since the "pointer entry" is
- * already zero-filled.
- */
- if (pnext) {
- /* The start lba for next partition is an offset from the beginning
- * of the top-level extended partition */
- uint32_t next_start_lba = *lba - ext_lba;
- uint32_t next_len_lba;
- if (pnext->len_kb != (uint32_t)-1)
- next_len_lba = 1 + kb_to_lba(pnext->len_kb, dinfo->sect_size);
- else
- next_len_lba = dinfo->num_lba - *lba;
- cfg_pentry(&ebr->ptable[PC_EBR_NEXT_PTR_PART], PC_PART_NORMAL,
- PC_PART_TYPE_EXTENDED, next_start_lba, next_len_lba);
- }
-
- return item;
-
-fail:
- free_wl(item);
- return NULL;
-}
-
-
-static struct write_list *
-mk_mbr_sig()
-{
- struct write_list *item;
- if (!(item = alloc_wl(sizeof(uint16_t)))) {
- ALOGE("Unable to allocate memory for MBR signature.");
- return NULL;
- }
-
- {
- /* DO NOT DEREFERENCE */
- struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET;
- /* grab the offset in mbr where to write mbr signature. */
- item->offset = (loff_t)((uintptr_t)((uint8_t *)(&mbr->mbr_sig)));
- }
-
- *((uint16_t*)item->data) = PC_BIOS_BOOT_SIG;
- return item;
-}
-
-struct write_list *
-config_mbr(struct disk_info *dinfo)
-{
- struct part_info *pinfo;
- uint32_t cur_lba = dinfo->skip_lba;
- uint32_t ext_lba = 0;
- struct write_list *wr_list = NULL;
- struct write_list *temp_wr = NULL;
- int cnt = 0;
- int extended = 0;
-
- if (!dinfo->part_lst)
- return NULL;
-
- for (cnt = 0; cnt < dinfo->num_parts; ++cnt) {
- pinfo = &dinfo->part_lst[cnt];
-
- /* Should we create an extedned partition? */
- if (cnt == (PC_NUM_BOOT_RECORD_PARTS - 1)) {
- if (cnt + 1 < dinfo->num_parts) {
- extended = 1;
- ext_lba = cur_lba;
- if ((temp_wr = mk_pri_pentry(dinfo, NULL, cnt, &cur_lba)))
- wlist_add(&wr_list, temp_wr);
- else {
- ALOGE("Cannot create primary extended partition.");
- goto fail;
- }
- }
- }
-
- /* if extended, need 1 lba for ebr */
- if ((cur_lba + extended) >= dinfo->num_lba)
- goto nospace;
- else if (pinfo->len_kb != (uint32_t)-1) {
- uint32_t sz_lba = (pinfo->len_kb / dinfo->sect_size) * 1024;
- if ((cur_lba + sz_lba + extended) > dinfo->num_lba)
- goto nospace;
- }
-
- if (!extended)
- temp_wr = mk_pri_pentry(dinfo, pinfo, cnt, &cur_lba);
- else {
- struct part_info *pnext;
- pnext = cnt + 1 < dinfo->num_parts ? &dinfo->part_lst[cnt+1] : NULL;
- temp_wr = mk_ext_pentry(dinfo, pinfo, &cur_lba, ext_lba, pnext);
- }
-
- if (temp_wr)
- wlist_add(&wr_list, temp_wr);
- else {
- ALOGE("Cannot create partition %d (%s).", cnt, pinfo->name);
- goto fail;
- }
- }
-
- /* fill in the rest of the MBR with empty parts (if needed). */
- for (; cnt < PC_NUM_BOOT_RECORD_PARTS; ++cnt) {
- struct part_info blank;
- cur_lba = 0;
- memset(&blank, 0, sizeof(struct part_info));
- if (!(temp_wr = mk_pri_pentry(dinfo, &blank, cnt, &cur_lba))) {
- ALOGE("Cannot create blank partition %d.", cnt);
- goto fail;
- }
- wlist_add(&wr_list, temp_wr);
- }
-
- if ((temp_wr = mk_mbr_sig()))
- wlist_add(&wr_list, temp_wr);
- else {
- ALOGE("Cannot set MBR signature");
- goto fail;
- }
-
- return wr_list;
-
-nospace:
- ALOGE("Not enough space to add parttion '%s'.", pinfo->name);
-
-fail:
- wlist_free(wr_list);
- return NULL;
-}
-
-
-/* Returns the device path of the partition referred to by 'name'
- * Must be freed by the caller.
- */
-char *
-find_mbr_part(struct disk_info *dinfo, const char *name)
-{
- struct part_info *plist = dinfo->part_lst;
- int num = 0;
- char *dev_name = NULL;
- int has_extended = (dinfo->num_parts > PC_NUM_BOOT_RECORD_PARTS);
-
- for(num = 1; num <= dinfo->num_parts; ++num) {
- if (!strcmp(plist[num-1].name, name))
- break;
- }
-
- if (num > dinfo->num_parts)
- return NULL;
-
- if (has_extended && (num >= PC_NUM_BOOT_RECORD_PARTS))
- num++;
-
- if (!(dev_name = malloc(MAX_NAME_LEN))) {
- ALOGE("Cannot allocate memory.");
- return NULL;
- }
-
- num = snprintf(dev_name, MAX_NAME_LEN, "%s%d", dinfo->device, num);
- if (num >= MAX_NAME_LEN) {
- ALOGE("Device name is too long?!");
- free(dev_name);
- return NULL;
- }
-
- return dev_name;
-}
diff --git a/libdiskconfig/diskconfig.c b/libdiskconfig/diskconfig.c
deleted file mode 100644
index 5f34748..0000000
--- a/libdiskconfig/diskconfig.c
+++ /dev/null
@@ -1,535 +0,0 @@
-/* libs/diskconfig/diskconfig.c
- *
- * Copyright 2008, 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.
- */
-
-#define LOG_TAG "diskconfig"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <linux/fs.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <cutils/config_utils.h>
-#include <log/log.h>
-
-#include <diskconfig/diskconfig.h>
-
-static int
-parse_len(const char *str, uint64_t *plen)
-{
- char tmp[64];
- int len_str;
- uint32_t multiple = 1;
-
- strncpy(tmp, str, sizeof(tmp));
- tmp[sizeof(tmp)-1] = '\0';
- len_str = strlen(tmp);
- if (!len_str) {
- ALOGE("Invalid disk length specified.");
- return 1;
- }
-
- switch(tmp[len_str - 1]) {
- case 'M': case 'm':
- /* megabyte */
- multiple <<= 10;
- case 'K': case 'k':
- /* kilobytes */
- multiple <<= 10;
- tmp[len_str - 1] = '\0';
- break;
- default:
- break;
- }
-
- *plen = strtoull(tmp, NULL, 0);
- if (!*plen) {
- ALOGE("Invalid length specified: %s", str);
- return 1;
- }
-
- if (*plen == (uint64_t)-1) {
- if (multiple > 1) {
- ALOGE("Size modifier illegal when len is -1");
- return 1;
- }
- } else {
- /* convert len to kilobytes */
- if (multiple > 1024)
- multiple >>= 10;
- *plen *= multiple;
-
- if (*plen > 0xffffffffULL) {
- ALOGE("Length specified is too large!: %"PRIu64" KB", *plen);
- return 1;
- }
- }
-
- return 0;
-}
-
-
-static int
-load_partitions(cnode *root, struct disk_info *dinfo)
-{
- cnode *partnode;
-
- dinfo->num_parts = 0;
- for (partnode = root->first_child; partnode; partnode = partnode->next) {
- struct part_info *pinfo = &dinfo->part_lst[dinfo->num_parts];
- const char *tmp;
-
- /* bleh, i will leak memory here, but i DONT CARE since
- * the only right thing to do when this function fails
- * is to quit */
- pinfo->name = strdup(partnode->name);
-
- if(config_bool(partnode, "active", 0))
- pinfo->flags |= PART_ACTIVE_FLAG;
-
- if (!(tmp = config_str(partnode, "type", NULL))) {
- ALOGE("Partition type required: %s", pinfo->name);
- return 1;
- }
-
- /* possible values are: linux, fat32 */
- if (!strcmp(tmp, "linux")) {
- pinfo->type = PC_PART_TYPE_LINUX;
- } else if (!strcmp(tmp, "fat32")) {
- pinfo->type = PC_PART_TYPE_FAT32;
- } else {
- ALOGE("Unsupported partition type found: %s", tmp);
- return 1;
- }
-
- if ((tmp = config_str(partnode, "len", NULL)) != NULL) {
- uint64_t len;
- if (parse_len(tmp, &len))
- return 1;
- pinfo->len_kb = (uint32_t) len;
- } else
- pinfo->len_kb = 0;
-
- ++dinfo->num_parts;
- }
-
- return 0;
-}
-
-struct disk_info *
-load_diskconfig(const char *fn, char *path_override)
-{
- struct disk_info *dinfo;
- cnode *devroot;
- cnode *partnode;
- cnode *root = config_node("", "");
- const char *tmp;
-
- if (!(dinfo = malloc(sizeof(struct disk_info)))) {
- ALOGE("Could not malloc disk_info");
- return NULL;
- }
- memset(dinfo, 0, sizeof(struct disk_info));
-
- if (!(dinfo->part_lst = malloc(MAX_NUM_PARTS * sizeof(struct part_info)))) {
- ALOGE("Could not malloc part_lst");
- goto fail;
- }
- memset(dinfo->part_lst, 0,
- (MAX_NUM_PARTS * sizeof(struct part_info)));
-
- config_load_file(root, fn);
- if (root->first_child == NULL) {
- ALOGE("Could not read config file %s", fn);
- goto fail;
- }
-
- if (!(devroot = config_find(root, "device"))) {
- ALOGE("Could not find device section in config file '%s'", fn);
- goto fail;
- }
-
-
- if (!(tmp = config_str(devroot, "path", path_override))) {
- ALOGE("device path is requried");
- goto fail;
- }
- dinfo->device = strdup(tmp);
-
- /* find the partition scheme */
- if (!(tmp = config_str(devroot, "scheme", NULL))) {
- ALOGE("partition scheme is required");
- goto fail;
- } else if (!strcmp(tmp, "mbr")) {
- dinfo->scheme = PART_SCHEME_MBR;
- } else if (!strcmp(tmp, "gpt")) {
- ALOGE("'gpt' partition scheme not supported yet.");
- goto fail;
- } else {
- ALOGE("Unknown partition scheme specified: %s", tmp);
- goto fail;
- }
-
- /* grab the sector size (in bytes) */
- tmp = config_str(devroot, "sector_size", "512");
- dinfo->sect_size = strtol(tmp, NULL, 0);
- if (!dinfo->sect_size) {
- ALOGE("Invalid sector size: %s", tmp);
- goto fail;
- }
-
- /* first lba where the partitions will start on disk */
- if (!(tmp = config_str(devroot, "start_lba", NULL))) {
- ALOGE("start_lba must be provided");
- goto fail;
- }
-
- if (!(dinfo->skip_lba = strtol(tmp, NULL, 0))) {
- ALOGE("Invalid starting LBA (or zero): %s", tmp);
- goto fail;
- }
-
- /* Number of LBAs on disk */
- if (!(tmp = config_str(devroot, "num_lba", NULL))) {
- ALOGE("num_lba is required");
- goto fail;
- }
- dinfo->num_lba = strtoul(tmp, NULL, 0);
-
- if (!(partnode = config_find(devroot, "partitions"))) {
- ALOGE("Device must specify partition list");
- goto fail;
- }
-
- if (load_partitions(partnode, dinfo))
- goto fail;
-
- return dinfo;
-
-fail:
- if (dinfo->part_lst)
- free(dinfo->part_lst);
- if (dinfo->device)
- free(dinfo->device);
- free(dinfo);
- return NULL;
-}
-
-static int
-sync_ptable(int fd)
-{
- struct stat stat;
- int rv;
-
- sync();
-
- if (fstat(fd, &stat)) {
- ALOGE("Cannot stat, errno=%d.", errno);
- return -1;
- }
-
- if (S_ISBLK(stat.st_mode) && ((rv = ioctl(fd, BLKRRPART, NULL)) < 0)) {
- ALOGE("Could not re-read partition table. REBOOT!. (errno=%d)", errno);
- return -1;
- }
-
- return 0;
-}
-
-/* This function verifies that the disk info provided is valid, and if so,
- * returns an open file descriptor.
- *
- * This does not necessarily mean that it will later be successfully written
- * though. If we use the pc-bios partitioning scheme, we must use extended
- * partitions, which eat up some hd space. If the user manually provisioned
- * every single partition, but did not account for the extra needed space,
- * then we will later fail.
- *
- * TODO: Make validation more complete.
- */
-static int
-validate(struct disk_info *dinfo)
-{
- int fd;
- int sect_sz;
- uint64_t disk_size;
- uint64_t total_size;
- int cnt;
- struct stat stat;
-
- if (!dinfo)
- return -1;
-
- if ((fd = open(dinfo->device, O_RDWR)) < 0) {
- ALOGE("Cannot open device '%s' (errno=%d)", dinfo->device, errno);
- return -1;
- }
-
- if (fstat(fd, &stat)) {
- ALOGE("Cannot stat file '%s', errno=%d.", dinfo->device, errno);
- goto fail;
- }
-
-
- /* XXX: Some of the code below is kind of redundant and should probably
- * be refactored a little, but it will do for now. */
-
- /* Verify that we can operate on the device that was requested.
- * We presently only support block devices and regular file images. */
- if (S_ISBLK(stat.st_mode)) {
- /* get the sector size and make sure we agree */
- if (ioctl(fd, BLKSSZGET, §_sz) < 0) {
- ALOGE("Cannot get sector size (errno=%d)", errno);
- goto fail;
- }
-
- if (!sect_sz || sect_sz != dinfo->sect_size) {
- ALOGE("Device sector size is zero or sector sizes do not match!");
- goto fail;
- }
-
- /* allow the user override the "disk size" if they provided num_lba */
- if (!dinfo->num_lba) {
- if (ioctl(fd, BLKGETSIZE64, &disk_size) < 0) {
- ALOGE("Could not get block device size (errno=%d)", errno);
- goto fail;
- }
- /* XXX: we assume that the disk has < 2^32 sectors :-) */
- dinfo->num_lba = (uint32_t)(disk_size / (uint64_t)dinfo->sect_size);
- } else
- disk_size = (uint64_t)dinfo->num_lba * (uint64_t)dinfo->sect_size;
- } else if (S_ISREG(stat.st_mode)) {
- ALOGI("Requesting operation on a regular file, not block device.");
- if (!dinfo->sect_size) {
- ALOGE("Sector size for regular file images cannot be zero");
- goto fail;
- }
- if (dinfo->num_lba)
- disk_size = (uint64_t)dinfo->num_lba * (uint64_t)dinfo->sect_size;
- else {
- dinfo->num_lba = (uint32_t)(stat.st_size / dinfo->sect_size);
- disk_size = (uint64_t)stat.st_size;
- }
- } else {
- ALOGE("Device does not refer to a regular file or a block device!");
- goto fail;
- }
-
-#if 1
- ALOGV("Device/file %s: size=%" PRIu64 " bytes, num_lba=%u, sect_size=%d",
- dinfo->device, disk_size, dinfo->num_lba, dinfo->sect_size);
-#endif
-
- /* since this is our offset into the disk, we start off with that as
- * our size of needed partitions */
- total_size = dinfo->skip_lba * dinfo->sect_size;
-
- /* add up all the partition sizes and make sure it fits */
- for (cnt = 0; cnt < dinfo->num_parts; ++cnt) {
- struct part_info *part = &dinfo->part_lst[cnt];
- if (part->len_kb != (uint32_t)-1) {
- total_size += part->len_kb * 1024;
- } else if (part->len_kb == 0) {
- ALOGE("Zero-size partition '%s' is invalid.", part->name);
- goto fail;
- } else {
- /* the partition requests the rest of the disk. */
- if (cnt + 1 != dinfo->num_parts) {
- ALOGE("Only the last partition in the list can request to fill "
- "the rest of disk.");
- goto fail;
- }
- }
-
- if ((part->type != PC_PART_TYPE_LINUX) &&
- (part->type != PC_PART_TYPE_FAT32)) {
- ALOGE("Unknown partition type (0x%x) encountered for partition "
- "'%s'\n", part->type, part->name);
- goto fail;
- }
- }
-
- /* only matters for disks, not files */
- if (S_ISBLK(stat.st_mode) && total_size > disk_size) {
- ALOGE("Total requested size of partitions (%"PRIu64") is greater than disk "
- "size (%"PRIu64").", total_size, disk_size);
- goto fail;
- }
-
- return fd;
-
-fail:
- close(fd);
- return -1;
-}
-
-static int
-validate_and_config(struct disk_info *dinfo, int *fd, struct write_list **lst)
-{
- *lst = NULL;
- *fd = -1;
-
- if ((*fd = validate(dinfo)) < 0)
- return 1;
-
- switch (dinfo->scheme) {
- case PART_SCHEME_MBR:
- *lst = config_mbr(dinfo);
- return *lst == NULL;
- case PART_SCHEME_GPT:
- /* not supported yet */
- default:
- ALOGE("Unknown partition scheme.");
- break;
- }
-
- close(*fd);
- *lst = NULL;
- return 1;
-}
-
-/* validate and process the disk layout configuration.
- * This will cause an update to the partitions' start lba.
- *
- * Basically, this does the same thing as apply_disk_config in test mode,
- * except that wlist_commit is not called to print out the data to be
- * written.
- */
-int
-process_disk_config(struct disk_info *dinfo)
-{
- struct write_list *lst;
- int fd;
-
- if (validate_and_config(dinfo, &fd, &lst) != 0)
- return 1;
-
- close(fd);
- wlist_free(lst);
- return 0;
-}
-
-
-int
-apply_disk_config(struct disk_info *dinfo, int test)
-{
- int fd;
- struct write_list *wr_lst = NULL;
- int rv;
-
- if (validate_and_config(dinfo, &fd, &wr_lst) != 0) {
- ALOGE("Configuration is invalid.");
- goto fail;
- }
-
- if ((rv = wlist_commit(fd, wr_lst, test)) >= 0)
- rv = test ? 0 : sync_ptable(fd);
-
- close(fd);
- wlist_free(wr_lst);
- return rv;
-
-fail:
- close(fd);
- if (wr_lst)
- wlist_free(wr_lst);
- return 1;
-}
-
-int
-dump_disk_config(struct disk_info *dinfo)
-{
- int cnt;
- struct part_info *part;
-
- printf("Device: %s\n", dinfo->device);
- printf("Scheme: ");
- switch (dinfo->scheme) {
- case PART_SCHEME_MBR:
- printf("MBR");
- break;
- case PART_SCHEME_GPT:
- printf("GPT (unsupported)");
- break;
- default:
- printf("Unknown");
- break;
- }
- printf ("\n");
-
- printf("Sector size: %d\n", dinfo->sect_size);
- printf("Skip leading LBAs: %u\n", dinfo->skip_lba);
- printf("Number of LBAs: %u\n", dinfo->num_lba);
- printf("Partitions:\n");
-
- for (cnt = 0; cnt < dinfo->num_parts; ++cnt) {
- part = &dinfo->part_lst[cnt];
- printf("\tname = %s\n", part->name);
- printf("\t\tflags = %s\n",
- part->flags & PART_ACTIVE_FLAG ? "Active" : "None");
- printf("\t\ttype = %s\n",
- part->type == PC_PART_TYPE_LINUX ? "Linux" : "Unknown");
- if (part->len_kb == (uint32_t)-1)
- printf("\t\tlen = rest of disk\n");
- else
- printf("\t\tlen = %uKB\n", part->len_kb);
- }
- printf("Total number of partitions: %d\n", cnt);
- printf("\n");
-
- return 0;
-}
-
-struct part_info *
-find_part(struct disk_info *dinfo, const char *name)
-{
- struct part_info *pinfo;
- int cnt;
-
- for (cnt = 0; cnt < dinfo->num_parts; ++cnt) {
- pinfo = &dinfo->part_lst[cnt];
- if (!strcmp(pinfo->name, name))
- return pinfo;
- }
-
- return NULL;
-}
-
-/* NOTE: If the returned ptr is non-NULL, it must be freed by the caller. */
-char *
-find_part_device(struct disk_info *dinfo, const char *name)
-{
- switch (dinfo->scheme) {
- case PART_SCHEME_MBR:
- return find_mbr_part(dinfo, name);
- case PART_SCHEME_GPT:
- ALOGE("GPT is presently not supported");
- break;
- default:
- ALOGE("Unknown partition table scheme");
- break;
- }
-
- return NULL;
-}
-
-
diff --git a/libdiskconfig/diskutils.c b/libdiskconfig/diskutils.c
deleted file mode 100644
index fe1b4c1..0000000
--- a/libdiskconfig/diskutils.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/* libs/diskconfig/diskutils.c
- *
- * Copyright 2008, 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.
- */
-
-#define LOG_TAG "diskutils"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include <diskconfig/diskconfig.h>
-
-int
-write_raw_image(const char *dst, const char *src, loff_t offset, int test)
-{
- int dst_fd = -1;
- int src_fd = -1;
- uint8_t buffer[2048];
- ssize_t nr_bytes;
- ssize_t tmp;
- int done = 0;
- uint64_t total = 0;
-
- ALOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, (unsigned long long)offset);
- if ((src_fd = open(src, O_RDONLY)) < 0) {
- ALOGE("Could not open %s for reading (errno=%d).", src, errno);
- goto fail;
- }
-
- if (!test) {
- if ((dst_fd = open(dst, O_RDWR)) < 0) {
- ALOGE("Could not open '%s' for read/write (errno=%d).", dst, errno);
- goto fail;
- }
-
- if (lseek64(dst_fd, offset, SEEK_SET) != offset) {
- ALOGE("Could not seek to offset %lld in %s.", (long long)offset, dst);
- goto fail;
- }
- }
-
- while (!done) {
- if ((nr_bytes = read(src_fd, buffer, sizeof(buffer))) < 0) {
- /* XXX: Should we not even bother with EINTR? */
- if (errno == EINTR)
- continue;
- ALOGE("Error (%d) while reading from '%s'", errno, src);
- goto fail;
- }
-
- if (!nr_bytes) {
- /* we're done. */
- done = 1;
- break;
- }
-
- total += nr_bytes;
-
- /* skip the write loop if we're testing */
- if (test)
- nr_bytes = 0;
-
- while (nr_bytes > 0) {
- if ((tmp = write(dst_fd, buffer, nr_bytes)) < 0) {
- /* XXX: Should we not even bother with EINTR? */
- if (errno == EINTR)
- continue;
- ALOGE("Error (%d) while writing to '%s'", errno, dst);
- goto fail;
- }
- if (!tmp)
- continue;
- nr_bytes -= tmp;
- }
- }
-
- if (!done) {
- ALOGE("Exited read/write loop without setting flag! WTF?!");
- goto fail;
- }
-
- if (dst_fd >= 0)
- fsync(dst_fd);
-
- ALOGI("Wrote %" PRIu64 " bytes to %s @ %lld", total, dst, (long long)offset);
-
- close(src_fd);
- if (dst_fd >= 0)
- close(dst_fd);
- return 0;
-
-fail:
- if (dst_fd >= 0)
- close(dst_fd);
- if (src_fd >= 0)
- close(src_fd);
- return 1;
-}
diff --git a/libdiskconfig/dump_diskconfig.c b/libdiskconfig/dump_diskconfig.c
deleted file mode 100644
index 3c4f620..0000000
--- a/libdiskconfig/dump_diskconfig.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/* libs/diskconfig/dump_diskconfig.c
- *
- * Copyright 2008, 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.
- */
-
-#define LOG_TAG "dump_diskconfig"
-
-#include <stdio.h>
-
-#include <log/log.h>
-
-#include "diskconfig.h"
-
-int
-main(int argc, char *argv[])
-{
- struct disk_info *dinfo;
-
- if (argc < 2) {
- ALOGE("usage: %s <conf file>", argv[0]);
- return 1;
- }
-
- if (!(dinfo = load_diskconfig(argv[1], NULL)))
- return 1;
-
- dump_disk_config(dinfo);
-
- return 0;
-}
-
diff --git a/libdiskconfig/include/diskconfig/diskconfig.h b/libdiskconfig/include/diskconfig/diskconfig.h
deleted file mode 100644
index d45b99e..0000000
--- a/libdiskconfig/include/diskconfig/diskconfig.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* system/core/include/diskconfig/diskconfig.h
- *
- * Copyright 2008, 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 __LIBS_DISKCONFIG_H
-#define __LIBS_DISKCONFIG_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define MAX_NAME_LEN 512
-#define MAX_NUM_PARTS 16
-
-/* known partition schemes */
-#define PART_SCHEME_MBR 0x1
-#define PART_SCHEME_GPT 0x2
-
-/* PC Bios partition status */
-#define PC_PART_ACTIVE 0x80
-#define PC_PART_NORMAL 0x0
-
-/* Known (rather, used by us) partition types */
-#define PC_PART_TYPE_LINUX 0x83
-#define PC_PART_TYPE_EXTENDED 0x05
-#define PC_PART_TYPE_FAT32 0x0c
-
-#define PC_NUM_BOOT_RECORD_PARTS 4
-
-#define PC_EBR_LOGICAL_PART 0
-#define PC_EBR_NEXT_PTR_PART 1
-
-#define PC_BIOS_BOOT_SIG 0xAA55
-
-#define PC_MBR_DISK_OFFSET 0
-#define PC_MBR_SIZE 512
-
-#define PART_ACTIVE_FLAG 0x1
-
-struct chs {
- uint8_t head;
- uint8_t sector;
- uint8_t cylinder;
-} __attribute__((__packed__));
-
-/* 16 byte pc partition descriptor that sits in MBR and EPBR.
- * Note: multi-byte entities have little-endian layout on disk */
-struct pc_partition {
- uint8_t status; /* byte 0 */
- struct chs start; /* bytes 1-3 */
- uint8_t type; /* byte 4 */
- struct chs end; /* bytes 5-7 */
- uint32_t start_lba; /* bytes 8-11 */
- uint32_t len_lba; /* bytes 12-15 */
-} __attribute__((__packed__));
-
-struct pc_boot_record {
- uint8_t code[440]; /* bytes 0-439 */
- uint32_t disk_sig; /* bytes 440-443 */
- uint16_t pad; /* bytes 444-445 */
- struct pc_partition ptable[PC_NUM_BOOT_RECORD_PARTS]; /* bytes 446-509 */
- uint16_t mbr_sig; /* bytes 510-511 */
-} __attribute__((__packed__));
-
-struct part_info {
- char *name;
- uint8_t flags;
- uint8_t type;
- uint32_t len_kb; /* in 1K-bytes */
- uint32_t start_lba; /* the LBA where this partition begins */
-};
-
-struct disk_info {
- char *device;
- uint8_t scheme;
- int sect_size; /* expected sector size in bytes. MUST BE POWER OF 2 */
- uint32_t skip_lba; /* in sectors (1 unit of LBA) */
- uint32_t num_lba; /* the size of the disk in LBA units */
- struct part_info *part_lst;
- int num_parts;
-};
-
-struct write_list {
- struct write_list *next;
- loff_t offset;
- uint32_t len;
- uint8_t data[0];
-};
-
-
-struct write_list *alloc_wl(uint32_t data_len);
-void free_wl(struct write_list *item);
-struct write_list *wlist_add(struct write_list **lst, struct write_list *item);
-void wlist_free(struct write_list *lst);
-int wlist_commit(int fd, struct write_list *lst, int test);
-
-struct disk_info *load_diskconfig(const char *fn, char *path_override);
-int dump_disk_config(struct disk_info *dinfo);
-int apply_disk_config(struct disk_info *dinfo, int test);
-char *find_part_device(struct disk_info *dinfo, const char *name);
-int process_disk_config(struct disk_info *dinfo);
-struct part_info *find_part(struct disk_info *dinfo, const char *name);
-
-int write_raw_image(const char *dst, const char *src, loff_t offset, int test);
-
-/* For MBR partition schemes */
-struct write_list *config_mbr(struct disk_info *dinfo);
-char *find_mbr_part(struct disk_info *dinfo, const char *name);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LIBS_DISKCONFIG_H */
diff --git a/libdiskconfig/write_lst.c b/libdiskconfig/write_lst.c
deleted file mode 100644
index c3d5c0a..0000000
--- a/libdiskconfig/write_lst.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/* libs/diskconfig/write_lst.c
- *
- * Copyright 2008, 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.
- */
-
-#define LOG_TAG "write_lst"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <diskconfig/diskconfig.h>
-#include <log/log.h>
-
-struct write_list *
-alloc_wl(uint32_t data_len)
-{
- struct write_list *item;
-
- if (!(item = malloc(sizeof(struct write_list) + data_len))) {
- ALOGE("Unable to allocate memory.");
- return NULL;
- }
-
- item->len = data_len;
- return item;
-}
-
-void
-free_wl(struct write_list *item)
-{
- if (item)
- free(item);
-}
-
-struct write_list *
-wlist_add(struct write_list **lst, struct write_list *item)
-{
- item->next = (*lst);
- *lst = item;
- return item;
-}
-
-void
-wlist_free(struct write_list *lst)
-{
- struct write_list *temp_wr;
- while (lst) {
- temp_wr = lst->next;
- free_wl(lst);
- lst = temp_wr;
- }
-}
-
-int
-wlist_commit(int fd, struct write_list *lst, int test)
-{
- for(; lst; lst = lst->next) {
- if (lseek64(fd, lst->offset, SEEK_SET) != (loff_t)lst->offset) {
- ALOGE("Cannot seek to the specified position (%lld).", (long long)lst->offset);
- goto fail;
- }
-
- if (!test) {
- if (write(fd, lst->data, lst->len) != (int)lst->len) {
- ALOGE("Failed writing %u bytes at position %lld.", lst->len,
- (long long)lst->offset);
- goto fail;
- }
- } else
- ALOGI("Would write %d bytes @ offset %lld.", lst->len, (long long)lst->offset);
- }
-
- return 0;
-
-fail:
- return -1;
-}
diff --git a/libutils/Errors.cpp b/libutils/Errors.cpp
index 74f3bef..dfb4d9b 100644
--- a/libutils/Errors.cpp
+++ b/libutils/Errors.cpp
@@ -15,6 +15,8 @@
*/
#include <utils/Errors.h>
+#include <string.h>
+
namespace android {
std::string statusToString(status_t s) {
diff --git a/libutils/RefBase_test.cpp b/libutils/RefBase_test.cpp
index aed3b9b..d675598 100644
--- a/libutils/RefBase_test.cpp
+++ b/libutils/RefBase_test.cpp
@@ -28,7 +28,7 @@
using namespace android;
-static constexpr int NITERS = 1000000;
+static constexpr int NITERS = 500000;
static constexpr int INITIAL_STRONG_VALUE = 1 << 28; // Mirroring RefBase definition.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index d755b50..0ee85c7 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -295,7 +295,7 @@
write /proc/sys/kernel/randomize_va_space 2
write /proc/sys/vm/mmap_min_addr 32768
write /proc/sys/net/ipv4/ping_group_range "0 2147483647"
- write /proc/sys/net/unix/max_dgram_qlen 600
+ write /proc/sys/net/unix/max_dgram_qlen 2400
# Assign reasonable ceiling values for socket rcv/snd buffers.
# These should almost always be overridden by the target per the
@@ -1004,6 +1004,11 @@
exec_start derive_classpath
load_exports /data/system/environ/classpath
+ # Start ART's oneshot boot service to propagate boot experiment flags to
+ # dalvik.vm.*. This needs to be done before odsign since odrefresh uses and
+ # validates those properties against the signed cache-info.xml.
+ exec_start art_boot
+
# Start the on-device signing daemon, and wait for it to finish, to ensure
# ART artifacts are generated if needed.
# Must start after 'derive_classpath' to have *CLASSPATH variables set.
diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp
index 17f8156..17d4e31 100644
--- a/toolbox/modprobe.cpp
+++ b/toolbox/modprobe.cpp
@@ -85,6 +85,26 @@
}
}
+// Find directories in format of "/lib/modules/x.y.z-*".
+static int KernelVersionNameFilter(const dirent* de) {
+ unsigned int major, minor;
+ static std::string kernel_version;
+ utsname uts;
+
+ if (kernel_version.empty()) {
+ if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) {
+ LOG(ERROR) << "Could not parse the kernel version from uname";
+ return 0;
+ }
+ kernel_version = android::base::StringPrintf("%u.%u", major, minor);
+ }
+
+ if (android::base::StartsWith(de->d_name, kernel_version)) {
+ return 1;
+ }
+ return 0;
+}
+
} // anonymous namespace
extern "C" int modprobe_main(int argc, char** argv) {
@@ -192,9 +212,22 @@
}
if (mod_dirs.empty()) {
- utsname uts;
- uname(&uts);
- mod_dirs.emplace_back(android::base::StringPrintf("/lib/modules/%s", uts.release));
+ static constexpr auto LIB_MODULES_PREFIX = "/lib/modules/";
+ dirent** kernel_dirs = NULL;
+
+ int n = scandir(LIB_MODULES_PREFIX, &kernel_dirs, KernelVersionNameFilter, NULL);
+ if (n == -1) {
+ PLOG(ERROR) << "Failed to scan dir " << LIB_MODULES_PREFIX;
+ return EXIT_FAILURE;
+ } else if (n > 0) {
+ while (n--) {
+ mod_dirs.emplace_back(LIB_MODULES_PREFIX + std::string(kernel_dirs[n]->d_name));
+ }
+ }
+ free(kernel_dirs);
+
+ // Allow modules to be directly inside /lib/modules
+ mod_dirs.emplace_back(LIB_MODULES_PREFIX);
}
LOG(DEBUG) << "mode is " << mode;
@@ -212,11 +245,6 @@
return EXIT_FAILURE;
}
}
- if (mod_dirs.empty()) {
- LOG(ERROR) << "No module configuration directories given.";
- print_usage();
- return EXIT_FAILURE;
- }
if (parameter_count && modules.size() > 1) {
LOG(ERROR) << "Only one module may be loaded when specifying module parameters.";
print_usage();