Merge "init: use '/system' as the system mount point for force_normal_boot"
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index cf4d294..380dfa6 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -146,6 +146,10 @@
return true;
}
bool is_root = strcmp(dir, "/") == 0;
+ if (is_root && !find_mount("/system", false).empty()) {
+ dir = "/system";
+ is_root = false;
+ }
std::string dev = find_mount(dir, is_root);
// Even if the device for the root is not found, we still try to remount it
// as rw. This typically only happens when running Android in a container:
@@ -216,13 +220,19 @@
// If we can use overlayfs, lets get it in place first
// before we struggle with determining deduplication operations.
- if (!verity_enabled && fs_mgr_overlayfs_setup() && fs_mgr_overlayfs_mount_all()) {
- WriteFdExactly(fd.get(), "overlayfs mounted\n");
+ if (!verity_enabled && fs_mgr_overlayfs_setup()) {
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ if (fs_mgr_overlayfs_mount_all(fstab.get())) {
+ WriteFdExactly(fd.get(), "overlayfs mounted\n");
+ }
}
// Find partitions that are deduplicated, and can be un-deduplicated.
std::set<std::string> dedup;
- for (const auto& partition : partitions) {
+ for (const auto& part : partitions) {
+ auto partition = part;
+ if ((part == "/") && !find_mount("/system", false).empty()) partition = "/system";
std::string dev = find_mount(partition.c_str(), partition == "/");
if (dev.empty() || !fs_mgr_has_shared_blocks(partition, dev)) {
continue;
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 8417690..2bac486 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -103,7 +103,9 @@
if (reboot_arg.empty()) reboot_arg = "adb";
std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
- if (reboot_arg == "fastboot" && access("/dev/socket/recovery", F_OK) == 0) {
+ if (reboot_arg == "fastboot" &&
+ android::base::GetBoolProperty("ro.boot.logical_partitions", false) &&
+ access("/dev/socket/recovery", F_OK) == 0) {
LOG(INFO) << "Recovery specific reboot fastboot";
/*
* The socket is created to allow switching between recovery and
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index dee87bd..98a73eb 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -147,24 +147,34 @@
return fde;
}
-void fdevent_destroy(fdevent* fde) {
+unique_fd fdevent_release(fdevent* fde) {
check_main_thread();
- if (fde == nullptr) return;
+ if (!fde) {
+ return {};
+ }
+
if (!(fde->state & FDE_CREATED)) {
LOG(FATAL) << "destroying fde not created by fdevent_create(): " << dump_fde(fde);
}
+ unique_fd result = std::move(fde->fd);
if (fde->state & FDE_ACTIVE) {
- g_poll_node_map.erase(fde->fd.get());
+ g_poll_node_map.erase(result.get());
+
if (fde->state & FDE_PENDING) {
g_pending_list.remove(fde);
}
- fde->fd.reset();
fde->state = 0;
fde->events = 0;
}
delete fde;
+ return result;
+}
+
+void fdevent_destroy(fdevent* fde) {
+ // Release, and then let unique_fd's destructor cleanup.
+ fdevent_release(fde);
}
static void fdevent_update(fdevent* fde, unsigned events) {
diff --git a/adb/fdevent.h b/adb/fdevent.h
index d501b86..df2339a 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -50,11 +50,12 @@
*/
fdevent *fdevent_create(int fd, fd_func func, void *arg);
-/* Uninitialize and deallocate an fdevent object that was
-** created by fdevent_create()
-*/
+// Deallocate an fdevent object that was created by fdevent_create.
void fdevent_destroy(fdevent *fde);
+// fdevent_destroy, except releasing the file descriptor previously owned by the fdevent.
+unique_fd fdevent_release(fdevent* fde);
+
/* Change which events should cause notifications
*/
void fdevent_set(fdevent *fde, unsigned events);
diff --git a/adb/test_device.py b/adb/test_device.py
old mode 100644
new mode 100755
index 9f45115..c3166ff
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -751,7 +751,7 @@
shutil.rmtree(host_dir)
def test_push_empty(self):
- """Push a directory containing an empty directory to the device."""
+ """Push an empty directory to the device."""
self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
@@ -767,9 +767,10 @@
self.device.push(empty_dir_path, self.DEVICE_TEMP_DIR)
- test_empty_cmd = ['[', '-d',
- os.path.join(self.DEVICE_TEMP_DIR, 'empty')]
+ remote_path = os.path.join(self.DEVICE_TEMP_DIR, "empty")
+ test_empty_cmd = ["[", "-d", remote_path, "]"]
rc, _, _ = self.device.shell_nocheck(test_empty_cmd)
+
self.assertEqual(rc, 0)
self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
finally:
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index f0fe1d0..f0bdfbf 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -224,7 +224,7 @@
// Prefixes.
if (!strncmp(arg, "wait-", strlen("wait-"))) {
char buf[1];
- TEMP_FAILURE_RETRY(read(STDIN_FILENO, buf, sizeof(buf)));
+ UNUSED(TEMP_FAILURE_RETRY(read(STDIN_FILENO, buf, sizeof(buf))));
return do_action(arg + strlen("wait-"));
} else if (!strncmp(arg, "exhaustfd-", strlen("exhaustfd-"))) {
errno = 0;
@@ -258,10 +258,14 @@
__assert("some_file.c", 123, "false");
} else if (!strcasecmp(arg, "assert2")) {
__assert2("some_file.c", 123, "some_function", "false");
+#if !defined(__clang_analyzer__)
} else if (!strcasecmp(arg, "fortify")) {
+ // FORTIFY is disabled when running clang-tidy and other tools, so this
+ // shouldn't depend on internal implementation details of it.
char buf[10];
__read_chk(-1, buf, 32, 10);
while (true) pause();
+#endif
} else if (!strcasecmp(arg, "fdsan_file")) {
FILE* f = fopen("/dev/null", "r");
close(fileno(f));
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index 1152007..e433787 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -39,27 +39,27 @@
strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
}
-boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, void* ramdisk, int64_t ramdisk_size,
- void* second, int64_t second_size, size_t base,
- const boot_img_hdr_v1& src, int64_t* bootimg_size) {
+boot_img_hdr_v1* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
+ const std::vector<char>& second, size_t base, const boot_img_hdr_v1& src,
+ std::vector<char>* out) {
const size_t page_mask = src.page_size - 1;
int64_t header_actual = (sizeof(boot_img_hdr_v1) + page_mask) & (~page_mask);
- int64_t kernel_actual = (kernel_size + page_mask) & (~page_mask);
- int64_t ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
- int64_t second_actual = (second_size + page_mask) & (~page_mask);
+ int64_t kernel_actual = (kernel.size() + page_mask) & (~page_mask);
+ int64_t ramdisk_actual = (ramdisk.size() + page_mask) & (~page_mask);
+ int64_t second_actual = (second.size() + page_mask) & (~page_mask);
- *bootimg_size = header_actual + kernel_actual + ramdisk_actual + second_actual;
+ int64_t bootimg_size = header_actual + kernel_actual + ramdisk_actual + second_actual;
+ out->resize(bootimg_size);
- boot_img_hdr_v1* hdr = reinterpret_cast<boot_img_hdr_v1*>(calloc(*bootimg_size, 1));
- if (hdr == nullptr) die("couldn't allocate boot image: %" PRId64 " bytes", *bootimg_size);
+ boot_img_hdr_v1* hdr = reinterpret_cast<boot_img_hdr_v1*>(out->data());
*hdr = src;
memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
- hdr->kernel_size = kernel_size;
- hdr->ramdisk_size = ramdisk_size;
- hdr->second_size = second_size;
+ hdr->kernel_size = kernel.size();
+ hdr->ramdisk_size = ramdisk.size();
+ hdr->second_size = second.size();
hdr->kernel_addr += base;
hdr->ramdisk_addr += base;
@@ -70,8 +70,9 @@
hdr->header_size = sizeof(boot_img_hdr_v1);
}
- memcpy(hdr->magic + hdr->page_size, kernel, kernel_size);
- memcpy(hdr->magic + hdr->page_size + kernel_actual, ramdisk, ramdisk_size);
- memcpy(hdr->magic + hdr->page_size + kernel_actual + ramdisk_actual, second, second_size);
+ memcpy(hdr->magic + hdr->page_size, kernel.data(), kernel.size());
+ memcpy(hdr->magic + hdr->page_size + kernel_actual, ramdisk.data(), ramdisk.size());
+ memcpy(hdr->magic + hdr->page_size + kernel_actual + ramdisk_actual, second.data(),
+ second.size());
return hdr;
}
diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h
index fe805b0..a4e8870 100644
--- a/fastboot/bootimg_utils.h
+++ b/fastboot/bootimg_utils.h
@@ -33,8 +33,9 @@
#include <sys/types.h>
#include <string>
+#include <vector>
-boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, void* ramdisk, int64_t ramdisk_size,
- void* second, int64_t second_size, size_t base,
- const boot_img_hdr_v1& src, int64_t* bootimg_size);
+boot_img_hdr_v1* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
+ const std::vector<char>& second, size_t base, const boot_img_hdr_v1& src,
+ std::vector<char>* out);
void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline);
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 57e25fc..2a68a2b 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -32,6 +32,7 @@
#define FB_CMD_DELETE_PARTITION "delete-logical-partition"
#define FB_CMD_RESIZE_PARTITION "resize-logical-partition"
#define FB_CMD_UPDATE_SUPER "update-super"
+#define FB_CMD_OEM "oem"
#define RESPONSE_OKAY "OKAY"
#define RESPONSE_FAIL "FAIL"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 0ec0994..b7cafac 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -40,6 +40,9 @@
using ::android::hardware::boot::V1_0::BoolResult;
using ::android::hardware::boot::V1_0::CommandResult;
using ::android::hardware::boot::V1_0::Slot;
+using ::android::hardware::fastboot::V1_0::Result;
+using ::android::hardware::fastboot::V1_0::Status;
+
using namespace android::fs_mgr;
struct VariableHandlers {
@@ -133,6 +136,24 @@
return device->WriteStatus(FastbootResult::FAIL, "Erasing failed");
}
+bool OemCmdHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ auto fastboot_hal = device->fastboot_hal();
+ if (!fastboot_hal) {
+ return device->WriteStatus(FastbootResult::FAIL, "Unable to open fastboot HAL");
+ }
+
+ Result ret;
+ auto ret_val = fastboot_hal->doOemCommand(args[0], [&](Result result) { ret = result; });
+ if (!ret_val.isOk()) {
+ return device->WriteStatus(FastbootResult::FAIL, "Unable to do OEM command");
+ }
+ if (ret.status != Status::SUCCESS) {
+ return device->WriteStatus(FastbootResult::FAIL, ret.message);
+ }
+
+ return device->WriteStatus(FastbootResult::OKAY, ret.message);
+}
+
bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
if (args.size() < 2) {
return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
@@ -159,6 +180,12 @@
if (args.size() < 2) {
return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
}
+
+ if (GetDeviceLockStatus()) {
+ return device->WriteStatus(FastbootResult::FAIL,
+ "Flashing is not allowed on locked devices");
+ }
+
int ret = Flash(device, args[1]);
if (ret < 0) {
return device->WriteStatus(FastbootResult::FAIL, strerror(-ret));
@@ -304,6 +331,10 @@
return device->WriteFail("Invalid partition name and size");
}
+ if (GetDeviceLockStatus()) {
+ return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
+ }
+
uint64_t partition_size;
std::string partition_name = args[1];
if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
@@ -344,6 +375,10 @@
return device->WriteFail("Invalid partition name and size");
}
+ if (GetDeviceLockStatus()) {
+ return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
+ }
+
PartitionBuilder builder(device);
if (!builder.Valid()) {
return device->WriteFail("Could not open super partition");
@@ -360,6 +395,10 @@
return device->WriteFail("Invalid partition name and size");
}
+ if (GetDeviceLockStatus()) {
+ return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
+ }
+
uint64_t partition_size;
std::string partition_name = args[1];
if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
@@ -388,6 +427,11 @@
if (args.size() < 2) {
return device->WriteFail("Invalid arguments");
}
+
+ if (GetDeviceLockStatus()) {
+ return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
+ }
+
bool wipe = (args.size() >= 3 && args[2] == "wipe");
return UpdateSuper(device, args[1], wipe);
}
diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h
index 4778d23..9df43a9 100644
--- a/fastboot/device/commands.h
+++ b/fastboot/device/commands.h
@@ -45,3 +45,4 @@
bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args);
bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args);
bool UpdateSuperHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool OemCmdHandler(FastbootDevice* device, const std::vector<std::string>& args);
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index ae2e7a6..6862741 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -48,6 +48,7 @@
{FB_CMD_DELETE_PARTITION, DeletePartitionHandler},
{FB_CMD_RESIZE_PARTITION, ResizePartitionHandler},
{FB_CMD_UPDATE_SUPER, UpdateSuperHandler},
+ {FB_CMD_OEM, OemCmdHandler},
}),
transport_(std::make_unique<ClientUsbTransport>()),
boot_control_hal_(IBootControl::getService()),
@@ -120,10 +121,20 @@
command[bytes_read] = '\0';
LOG(INFO) << "Fastboot command: " << command;
- auto args = android::base::Split(command, ":");
- auto found_command = kCommandMap.find(args[0]);
+
+ std::vector<std::string> args;
+ std::string cmd_name;
+ if (android::base::StartsWith(command, "oem ")) {
+ args = {command};
+ cmd_name = "oem";
+ } else {
+ args = android::base::Split(command, ":");
+ cmd_name = args[0];
+ }
+
+ auto found_command = kCommandMap.find(cmd_name);
if (found_command == kCommandMap.end()) {
- WriteStatus(FastbootResult::FAIL, "Unrecognized command");
+ WriteStatus(FastbootResult::FAIL, "Unrecognized command " + args[0]);
continue;
}
if (!found_command->second(this, args)) {
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 261a202..02f6f2c 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <fs_mgr_dm_linear.h>
#include <liblp/liblp.h>
@@ -159,3 +160,9 @@
}
return partitions;
}
+
+bool GetDeviceLockStatus() {
+ std::string cmdline;
+ android::base::ReadFileToString("/proc/cmdline", &cmdline);
+ return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
+}
diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h
index 4f0d079..bb08f72 100644
--- a/fastboot/device/utility.h
+++ b/fastboot/device/utility.h
@@ -58,3 +58,4 @@
bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle);
bool GetSlotNumber(const std::string& slot, android::hardware::boot::V1_0::Slot* number);
std::vector<std::string> ListPartitions(FastbootDevice* device);
+bool GetDeviceLockStatus();
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index 7535248..002e043 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -148,7 +148,7 @@
bool GetUnlocked(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
std::string* message) {
- *message = "yes";
+ *message = GetDeviceLockStatus() ? "no" : "yes";
return true;
}
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 0ac57af..a43e7a6 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -103,9 +103,9 @@
RUN_COMMAND(fb->Flash(partition));
}
-void fb_flash(const std::string& partition, void* data, uint32_t sz) {
- Status(StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024));
- RUN_COMMAND(fb->Download(static_cast<char*>(data), sz));
+void fb_flash(const std::string& partition, const std::vector<char>& data) {
+ Status(StringPrintf("Sending '%s' (%zu KB)", partition.c_str(), data.size() / 1024));
+ RUN_COMMAND(fb->Download(data));
Status("Writing '" + partition + "'");
RUN_COMMAND(fb->Flash(partition));
@@ -136,69 +136,6 @@
RUN_COMMAND(fb->RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size));
}
-static int match(const char* str, const char** value, unsigned count) {
- unsigned n;
-
- for (n = 0; n < count; n++) {
- const char *val = value[n];
- int len = strlen(val);
- int match;
-
- if ((len > 1) && (val[len-1] == '*')) {
- len--;
- match = !strncmp(val, str, len);
- } else {
- match = !strcmp(val, str);
- }
-
- if (match) return 1;
- }
-
- return 0;
-}
-
-void fb_require(const std::string& product, const std::string& var, bool invert, size_t count,
- const char** values) {
- Status("Checking '" + var + "'");
-
- double start = now();
-
- std::string var_value;
- auto status = fb->GetVar(var, &var_value);
-
- if (status) {
- fprintf(stderr, "getvar:%s FAILED (%s)\n", var.c_str(), fb->Error().c_str());
- die("requirements not met!");
- }
-
- if (!product.empty()) {
- if (product != cur_product) {
- double split = now();
- fprintf(stderr, "IGNORE, product is %s required only for %s [%7.3fs]\n", cur_product,
- product.c_str(), (split - start));
- return;
- }
- }
-
- int yes = match(var_value.c_str(), values, count);
- if (invert) yes = !yes;
-
- if (yes) {
- double split = now();
- fprintf(stderr, "OKAY [%7.3fs]\n", (split - start));
- return;
- }
-
- fprintf(stderr, "FAILED\n\n");
- fprintf(stderr, "Device %s is '%s'.\n", var.c_str(), var_value.c_str());
- fprintf(stderr, "Update %s '%s'", invert ? "rejects" : "requires", values[0]);
- for (size_t n = 1; n < count; n++) {
- fprintf(stderr, " or '%s'", values[n]);
- }
- fprintf(stderr, ".\n\n");
- die("requirements not met!");
-}
-
void fb_display(const std::string& label, const std::string& var) {
std::string value;
auto status = fb->GetVar(var, &value);
@@ -210,18 +147,6 @@
fprintf(stderr, "%s: %s\n", label.c_str(), value.c_str());
}
-void fb_query_save(const std::string& var, char* dest, uint32_t dest_size) {
- std::string value;
- auto status = fb->GetVar(var, &value);
-
- if (status) {
- fprintf(stderr, "getvar:%s FAILED (%s)\n", var.c_str(), fb->Error().c_str());
- return;
- }
-
- strncpy(dest, value.c_str(), dest_size);
-}
-
void fb_reboot() {
fprintf(stderr, "Rebooting");
fb->Reboot();
@@ -233,9 +158,9 @@
RUN_COMMAND(fb->RawCommand(cmd));
}
-void fb_download(const std::string& name, void* data, uint32_t size) {
+void fb_download(const std::string& name, const std::vector<char>& data) {
Status("Downloading '" + name + "'");
- RUN_COMMAND(fb->Download(static_cast<char*>(data), size));
+ RUN_COMMAND(fb->Download(data));
}
void fb_download_fd(const std::string& name, int fd, uint32_t sz) {
diff --git a/fastboot/engine.h b/fastboot/engine.h
index d78cb13..b681f5a 100644
--- a/fastboot/engine.h
+++ b/fastboot/engine.h
@@ -48,18 +48,15 @@
void fb_reinit(Transport* transport);
bool fb_getvar(const std::string& key, std::string* value);
-void fb_flash(const std::string& partition, void* data, uint32_t sz);
+void fb_flash(const std::string& partition, const std::vector<char>& data);
void fb_flash_fd(const std::string& partition, int fd, uint32_t sz);
void fb_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
size_t current, size_t total);
void fb_erase(const std::string& partition);
-void fb_require(const std::string& prod, const std::string& var, bool invert, size_t nvalues,
- const char** values);
void fb_display(const std::string& label, const std::string& var);
-void fb_query_save(const std::string& var, char* dest, uint32_t dest_size);
void fb_reboot();
void fb_command(const std::string& cmd, const std::string& msg);
-void fb_download(const std::string& name, void* data, uint32_t size);
+void fb_download(const std::string& name, const std::vector<char>& data);
void fb_download_fd(const std::string& name, int fd, uint32_t sz);
void fb_upload(const std::string& outfile);
void fb_notice(const std::string& notice);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 8e6c125..5173bab 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -43,6 +43,7 @@
#include <chrono>
#include <functional>
+#include <regex>
#include <thread>
#include <utility>
#include <vector>
@@ -69,14 +70,15 @@
#include "udp.h"
#include "usb.h"
+using android::base::ReadFully;
+using android::base::Split;
+using android::base::Trim;
using android::base::unique_fd;
#ifndef O_BINARY
#define O_BINARY 0
#endif
-char cur_product[FB_RESPONSE_SZ + 1];
-
static const char* serial = nullptr;
static bool g_long_listing = false;
@@ -179,38 +181,22 @@
static int64_t get_file_size(int fd) {
struct stat sb;
- return fstat(fd, &sb) == -1 ? -1 : sb.st_size;
+ if (fstat(fd, &sb) == -1) {
+ die("could not get file size");
+ }
+ return sb.st_size;
}
-static void* load_fd(int fd, int64_t* sz) {
- int errno_tmp;
- char* data = nullptr;
+bool ReadFileToVector(const std::string& file, std::vector<char>* out) {
+ out->clear();
- *sz = get_file_size(fd);
- if (*sz < 0) {
- goto oops;
+ unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY)));
+ if (fd == -1) {
+ return false;
}
- data = (char*) malloc(*sz);
- if (data == nullptr) goto oops;
-
- if(read(fd, data, *sz) != *sz) goto oops;
- close(fd);
-
- return data;
-
-oops:
- errno_tmp = errno;
- close(fd);
- if(data != 0) free(data);
- errno = errno_tmp;
- return 0;
-}
-
-static void* load_file(const std::string& path, int64_t* sz) {
- int fd = open(path.c_str(), O_RDONLY | O_BINARY);
- if (fd == -1) return nullptr;
- return load_fd(fd, sz);
+ out->resize(get_file_size(fd));
+ return ReadFully(fd, out->data(), out->size());
}
static int match_fastboot_with_serial(usb_ifc_info* info, const char* local_serial) {
@@ -418,70 +404,71 @@
return 0;
}
-static void* load_bootable_image(const std::string& kernel, const std::string& ramdisk,
- const std::string& second_stage, int64_t* sz) {
- int64_t ksize;
- void* kdata = load_file(kernel.c_str(), &ksize);
- if (kdata == nullptr) die("cannot load '%s': %s", kernel.c_str(), strerror(errno));
+static std::vector<char> LoadBootableImage(const std::string& kernel, const std::string& ramdisk,
+ const std::string& second_stage) {
+ std::vector<char> kernel_data;
+ if (!ReadFileToVector(kernel, &kernel_data)) {
+ die("cannot load '%s': %s", kernel.c_str(), strerror(errno));
+ }
// Is this actually a boot image?
- if (ksize < static_cast<int64_t>(sizeof(boot_img_hdr_v1))) {
+ if (kernel_data.size() < sizeof(boot_img_hdr_v1)) {
die("cannot load '%s': too short", kernel.c_str());
}
- if (!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+ if (!memcmp(kernel_data.data(), BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
if (!g_cmdline.empty()) {
- bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kdata), g_cmdline);
+ bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kernel_data.data()), g_cmdline);
}
if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
- *sz = ksize;
- return kdata;
+ return kernel_data;
}
- void* rdata = nullptr;
- int64_t rsize = 0;
+ std::vector<char> ramdisk_data;
if (!ramdisk.empty()) {
- rdata = load_file(ramdisk.c_str(), &rsize);
- if (rdata == nullptr) die("cannot load '%s': %s", ramdisk.c_str(), strerror(errno));
+ if (!ReadFileToVector(ramdisk, &ramdisk_data)) {
+ die("cannot load '%s': %s", ramdisk.c_str(), strerror(errno));
+ }
}
- void* sdata = nullptr;
- int64_t ssize = 0;
+ std::vector<char> second_stage_data;
if (!second_stage.empty()) {
- sdata = load_file(second_stage.c_str(), &ssize);
- if (sdata == nullptr) die("cannot load '%s': %s", second_stage.c_str(), strerror(errno));
+ if (!ReadFileToVector(second_stage, &second_stage_data)) {
+ die("cannot load '%s': %s", second_stage.c_str(), strerror(errno));
+ }
}
-
fprintf(stderr,"creating boot image...\n");
- boot_img_hdr_v1* bdata = mkbootimg(kdata, ksize, rdata, rsize, sdata, ssize,
- g_base_addr, g_boot_img_hdr, sz);
- if (bdata == nullptr) die("failed to create boot.img");
- if (!g_cmdline.empty()) bootimg_set_cmdline(bdata, g_cmdline);
- fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", *sz);
+ std::vector<char> out;
+ boot_img_hdr_v1* boot_image_data = mkbootimg(kernel_data, ramdisk_data, second_stage_data,
+ g_base_addr, g_boot_img_hdr, &out);
- return bdata;
+ if (!g_cmdline.empty()) bootimg_set_cmdline(boot_image_data, g_cmdline);
+ fprintf(stderr, "creating boot image - %zu bytes\n", out.size());
+
+ return out;
}
-static void* unzip_to_memory(ZipArchiveHandle zip, const char* entry_name, int64_t* sz) {
- ZipString zip_entry_name(entry_name);
+static bool UnzipToMemory(ZipArchiveHandle zip, const std::string& entry_name,
+ std::vector<char>* out) {
+ ZipString zip_entry_name(entry_name.c_str());
ZipEntry zip_entry;
if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
- fprintf(stderr, "archive does not contain '%s'\n", entry_name);
- return nullptr;
+ fprintf(stderr, "archive does not contain '%s'\n", entry_name.c_str());
+ return false;
}
- *sz = zip_entry.uncompressed_length;
+ out->resize(zip_entry.uncompressed_length);
- fprintf(stderr, "extracting %s (%" PRId64 " MB) to RAM...\n", entry_name, *sz / 1024 / 1024);
- uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length));
- if (data == nullptr) die("failed to allocate %" PRId64 " bytes for '%s'", *sz, entry_name);
+ fprintf(stderr, "extracting %s (%zu MB) to RAM...\n", entry_name.c_str(),
+ out->size() / 1024 / 1024);
- int error = ExtractToMemory(zip, &zip_entry, data, zip_entry.uncompressed_length);
- if (error != 0) die("failed to extract '%s': %s", entry_name, ErrorCodeString(error));
+ int error = ExtractToMemory(zip, &zip_entry, reinterpret_cast<uint8_t*>(out->data()),
+ out->size());
+ if (error != 0) die("failed to extract '%s': %s", entry_name.c_str(), ErrorCodeString(error));
- return data;
+ return true;
}
#if defined(_WIN32)
@@ -602,109 +589,145 @@
return fd.release();
}
-static char* strip(char* s) {
- while (*s && isspace(*s)) s++;
+static void CheckRequirement(const std::string& cur_product, const std::string& var,
+ const std::string& product, bool invert,
+ const std::vector<std::string>& options) {
+ Status("Checking '" + var + "'");
- int n = strlen(s);
- while (n-- > 0) {
- if (!isspace(s[n])) break;
- s[n] = 0;
+ double start = now();
+
+ if (!product.empty()) {
+ if (product != cur_product) {
+ double split = now();
+ fprintf(stderr, "IGNORE, product is %s required only for %s [%7.3fs]\n",
+ cur_product.c_str(), product.c_str(), (split - start));
+ return;
+ }
}
- return s;
+
+ std::string var_value;
+ if (!fb_getvar(var, &var_value)) {
+ fprintf(stderr, "FAILED\n\n");
+ fprintf(stderr, "Could not getvar for '%s' (%s)\n\n", var.c_str(), fb_get_error().c_str());
+ die("requirements not met!");
+ }
+
+ bool match = false;
+ for (const auto& option : options) {
+ if (option == var_value || (option.back() == '*' &&
+ !var_value.compare(0, option.length() - 1, option, 0,
+ option.length() - 1))) {
+ match = true;
+ break;
+ }
+ }
+
+ if (invert) {
+ match = !match;
+ }
+
+ if (match) {
+ double split = now();
+ fprintf(stderr, "OKAY [%7.3fs]\n", (split - start));
+ return;
+ }
+
+ fprintf(stderr, "FAILED\n\n");
+ fprintf(stderr, "Device %s is '%s'.\n", var.c_str(), var_value.c_str());
+ fprintf(stderr, "Update %s '%s'", invert ? "rejects" : "requires", options[0].c_str());
+ for (auto it = std::next(options.begin()); it != options.end(); ++it) {
+ fprintf(stderr, " or '%s'", it->c_str());
+ }
+ fprintf(stderr, ".\n\n");
+ die("requirements not met!");
}
-#define MAX_OPTIONS 32
-static void check_requirement(char* line) {
- char *val[MAX_OPTIONS];
- unsigned count;
- char *x;
- int invert = 0;
-
+bool ParseRequirementLine(const std::string& line, std::string* name, std::string* product,
+ bool* invert, std::vector<std::string>* options) {
// "require product=alpha|beta|gamma"
// "require version-bootloader=1234"
// "require-for-product:gamma version-bootloader=istanbul|constantinople"
// "require partition-exists=vendor"
+ *product = "";
+ *invert = false;
- char* name = line;
- const char* product = "";
- if (!strncmp(name, "reject ", 7)) {
- name += 7;
- invert = 1;
- } else if (!strncmp(name, "require ", 8)) {
- name += 8;
- invert = 0;
- } else if (!strncmp(name, "require-for-product:", 20)) {
- // Get the product and point name past it
- product = name + 20;
- name = strchr(name, ' ');
- if (!name) die("android-info.txt syntax error: %s", line);
- *name = 0;
- name += 1;
- invert = 0;
+ auto require_reject_regex = std::regex{"(require\\s+|reject\\s+)?\\s*(\\S+)\\s*=\\s*(.*)"};
+ auto require_product_regex =
+ std::regex{"require-for-product:\\s*(\\S+)\\s+(\\S+)\\s*=\\s*(.*)"};
+ std::smatch match_results;
+
+ if (std::regex_match(line, match_results, require_reject_regex)) {
+ *invert = Trim(match_results[1]) == "reject";
+ } else if (std::regex_match(line, match_results, require_product_regex)) {
+ *product = match_results[1];
+ } else {
+ return false;
}
- x = strchr(name, '=');
- if (x == 0) return;
- *x = 0;
- val[0] = x + 1;
-
- name = strip(name);
-
- // "require partition-exists=x" is a special case, added because of the trouble we had when
- // Pixel 2 shipped with new partitions and users used old versions of fastboot to flash them,
- // missing out new partitions. A device with new partitions can use "partition-exists" to
- // override the fields `optional_if_no_image` in the `images` array.
- if (!strcmp(name, "partition-exists")) {
- const char* partition_name = val[0];
- std::string has_slot;
- if (!fb_getvar(std::string("has-slot:") + partition_name, &has_slot) ||
- (has_slot != "yes" && has_slot != "no")) {
- die("device doesn't have required partition %s!", partition_name);
- }
- bool known_partition = false;
- for (size_t i = 0; i < arraysize(images); ++i) {
- if (images[i].nickname && !strcmp(images[i].nickname, partition_name)) {
- images[i].optional_if_no_image = false;
- known_partition = true;
- }
- }
- if (!known_partition) {
- die("device requires partition %s which is not known to this version of fastboot",
- partition_name);
- }
- return;
- }
-
- for(count = 1; count < MAX_OPTIONS; count++) {
- x = strchr(val[count - 1],'|');
- if (x == 0) break;
- *x = 0;
- val[count] = x + 1;
- }
-
+ *name = match_results[2];
// Work around an unfortunate name mismatch.
- const char* var = name;
- if (!strcmp(name, "board")) var = "product";
-
- const char** out = reinterpret_cast<const char**>(malloc(sizeof(char*) * count));
- if (out == nullptr) die("out of memory");
-
- for (size_t i = 0; i < count; ++i) {
- out[i] = xstrdup(strip(val[i]));
+ if (*name == "board") {
+ *name = "product";
}
- fb_require(product, var, invert, count, out);
+ auto raw_options = Split(match_results[3], "|");
+ for (const auto& option : raw_options) {
+ auto trimmed_option = Trim(option);
+ options->emplace_back(trimmed_option);
+ }
+
+ return true;
}
-static void check_requirements(char* data, int64_t sz) {
- char* s = data;
- while (sz-- > 0) {
- if (*s == '\n') {
- *s++ = 0;
- check_requirement(data);
- data = s;
+// "require partition-exists=x" is a special case, added because of the trouble we had when
+// Pixel 2 shipped with new partitions and users used old versions of fastboot to flash them,
+// missing out new partitions. A device with new partitions can use "partition-exists" to
+// override the fields `optional_if_no_image` in the `images` array.
+static void HandlePartitionExists(const std::vector<std::string>& options) {
+ const std::string& partition_name = options[0];
+ std::string has_slot;
+ if (!fb_getvar("has-slot:" + partition_name, &has_slot) ||
+ (has_slot != "yes" && has_slot != "no")) {
+ die("device doesn't have required partition %s!", partition_name.c_str());
+ }
+ bool known_partition = false;
+ for (size_t i = 0; i < arraysize(images); ++i) {
+ if (images[i].nickname && images[i].nickname == partition_name) {
+ images[i].optional_if_no_image = false;
+ known_partition = true;
+ }
+ }
+ if (!known_partition) {
+ die("device requires partition %s which is not known to this version of fastboot",
+ partition_name.c_str());
+ }
+}
+
+static void CheckRequirements(const std::string& data) {
+ std::string cur_product;
+ if (!fb_getvar("product", &cur_product)) {
+ fprintf(stderr, "getvar:product FAILED (%s)\n", fb_get_error().c_str());
+ }
+
+ auto lines = Split(data, "\n");
+ for (const auto& line : lines) {
+ if (line.empty()) {
+ continue;
+ }
+
+ std::string name;
+ std::string product;
+ bool invert;
+ std::vector<std::string> options;
+
+ if (!ParseRequirementLine(line, &name, &product, &invert, &options)) {
+ fprintf(stderr, "android-info.txt syntax error: %s\n", line.c_str());
+ continue;
+ }
+ if (name == "partition-exists") {
+ HandlePartitionExists(options);
} else {
- s++;
+ CheckRequirement(cur_product, name, product, invert, options);
}
}
}
@@ -1097,7 +1120,7 @@
class ImageSource {
public:
- virtual void* ReadFile(const std::string& name, int64_t* size) const = 0;
+ virtual bool ReadFile(const std::string& name, std::vector<char>* out) const = 0;
virtual int OpenFile(const std::string& name) const = 0;
};
@@ -1166,12 +1189,11 @@
}
void FlashAllTool::CheckRequirements() {
- int64_t sz;
- void* data = source_.ReadFile("android-info.txt", &sz);
- if (data == nullptr) {
+ std::vector<char> contents;
+ if (!source_.ReadFile("android-info.txt", &contents)) {
die("could not read android-info.txt");
}
- check_requirements(reinterpret_cast<char*>(data), sz);
+ ::CheckRequirements({contents.data(), contents.size()});
}
void FlashAllTool::DetermineSecondarySlot() {
@@ -1224,10 +1246,9 @@
void FlashAllTool::FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf) {
auto flash = [&, this](const std::string& partition_name) {
- int64_t sz;
- void* data = source_.ReadFile(image.sig_name, &sz);
- if (data) {
- fb_download("signature", data, sz);
+ std::vector<char> signature_data;
+ if (source_.ReadFile(image.sig_name, &signature_data)) {
+ fb_download("signature", signature_data);
fb_command("signature", "installing signature");
}
@@ -1263,15 +1284,15 @@
class ZipImageSource final : public ImageSource {
public:
explicit ZipImageSource(ZipArchiveHandle zip) : zip_(zip) {}
- void* ReadFile(const std::string& name, int64_t* size) const override;
+ bool ReadFile(const std::string& name, std::vector<char>* out) const override;
int OpenFile(const std::string& name) const override;
private:
ZipArchiveHandle zip_;
};
-void* ZipImageSource::ReadFile(const std::string& name, int64_t* size) const {
- return unzip_to_memory(zip_, name.c_str(), size);
+bool ZipImageSource::ReadFile(const std::string& name, std::vector<char>* out) const {
+ return UnzipToMemory(zip_, name, out);
}
int ZipImageSource::OpenFile(const std::string& name) const {
@@ -1281,8 +1302,6 @@
static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) {
dump_info();
- fb_query_save("product", cur_product, sizeof(cur_product));
-
ZipArchiveHandle zip;
int error = OpenArchive(filename, &zip);
if (error != 0) {
@@ -1297,16 +1316,16 @@
class LocalImageSource final : public ImageSource {
public:
- void* ReadFile(const std::string& name, int64_t* size) const override;
+ bool ReadFile(const std::string& name, std::vector<char>* out) const override;
int OpenFile(const std::string& name) const override;
};
-void* LocalImageSource::ReadFile(const std::string& name, int64_t* size) const {
+bool LocalImageSource::ReadFile(const std::string& name, std::vector<char>* out) const {
auto path = find_item_given_name(name);
if (path.empty()) {
- return nullptr;
+ return false;
}
- return load_file(path.c_str(), size);
+ return ReadFileToVector(path, out);
}
int LocalImageSource::OpenFile(const std::string& name) const {
@@ -1318,8 +1337,6 @@
std::string fname;
dump_info();
- fb_query_save("product", cur_product, sizeof(cur_product));
-
FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe);
tool.Flash();
}
@@ -1473,8 +1490,6 @@
bool wants_set_active = false;
bool skip_secondary = false;
bool set_fbe_marker = false;
- void *data;
- int64_t sz;
int longindex;
std::string slot_override;
std::string next_active;
@@ -1678,10 +1693,12 @@
do_for_partitions(partition.c_str(), slot_override, format, true);
} else if (command == "signature") {
std::string filename = next_arg(&args);
- data = load_file(filename.c_str(), &sz);
- if (data == nullptr) die("could not load '%s': %s", filename.c_str(), strerror(errno));
- if (sz != 256) die("signature must be 256 bytes (got %" PRId64 ")", sz);
- fb_download("signature", data, sz);
+ std::vector<char> data;
+ if (!ReadFileToVector(filename, &data)) {
+ die("could not load '%s': %s", filename.c_str(), strerror(errno));
+ }
+ if (data.size() != 256) die("signature must be 256 bytes (got %zu)", data.size());
+ fb_download("signature", data);
fb_command("signature", "installing signature");
} else if (command == "reboot") {
wants_reboot = true;
@@ -1718,8 +1735,8 @@
std::string second_stage;
if (!args.empty()) second_stage = next_arg(&args);
- data = load_bootable_image(kernel, ramdisk, second_stage, &sz);
- fb_download("boot.img", data, sz);
+ auto data = LoadBootableImage(kernel, ramdisk, second_stage);
+ fb_download("boot.img", data);
fb_command("boot", "booting");
} else if (command == "flash") {
std::string pname = next_arg(&args);
@@ -1744,9 +1761,9 @@
std::string second_stage;
if (!args.empty()) second_stage = next_arg(&args);
- data = load_bootable_image(kernel, ramdisk, second_stage, &sz);
- auto flashraw = [&](const std::string& partition) {
- fb_flash(partition, data, sz);
+ auto data = LoadBootableImage(kernel, ramdisk, second_stage);
+ auto flashraw = [&data](const std::string& partition) {
+ fb_flash(partition, data);
};
do_for_partitions(partition, slot_override, flashraw, true);
} else if (command == "flashall") {
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index 4a14131..72ba619 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -147,28 +147,6 @@
return SUCCESS;
}
-RetCode FastBootDriver::Require(const std::string& var, const std::vector<std::string>& allowed,
- bool* reqmet, bool invert) {
- *reqmet = invert;
- RetCode ret;
- std::string response;
- if ((ret = GetVar(var, &response))) {
- return ret;
- }
-
- // Now check if we have a match
- for (const auto s : allowed) {
- // If it ends in *, and starting substring match
- if (response == s || (s.length() && s.back() == '*' &&
- !response.compare(0, s.length() - 1, s, 0, s.length() - 1))) {
- *reqmet = !invert;
- break;
- }
- }
-
- return SUCCESS;
-}
-
RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
std::vector<std::string>* info) {
RetCode ret;
@@ -194,24 +172,19 @@
RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
std::vector<std::string>* info) {
- return Download(buf.data(), buf.size(), response, info);
-}
-
-RetCode FastBootDriver::Download(const char* buf, uint32_t size, std::string* response,
- std::vector<std::string>* info) {
RetCode ret;
error_ = "";
- if ((size == 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
+ if ((buf.size() == 0 || buf.size() > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
error_ = "Buffer is too large or 0 bytes";
return BAD_ARG;
}
- if ((ret = DownloadCommand(size, response, info))) {
+ if ((ret = DownloadCommand(buf.size(), response, info))) {
return ret;
}
// Write the buffer
- if ((ret = SendBuffer(buf, size))) {
+ if ((ret = SendBuffer(buf))) {
return ret;
}
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index 4d85ba0..2d45085 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -74,9 +74,6 @@
std::vector<std::string>* info = nullptr);
RetCode Download(const std::vector<char>& buf, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
- // This will be removed after fastboot is modified to use a vector
- RetCode Download(const char* buf, uint32_t size, std::string* response = nullptr,
- std::vector<std::string>* info = nullptr);
RetCode Download(sparse_file* s, bool use_crc = false, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode Erase(const std::string& part, std::string* response = nullptr,
diff --git a/fastboot/fastboot_test.cpp b/fastboot/fastboot_test.cpp
index 43201fa..e0bbd56 100644
--- a/fastboot/fastboot_test.cpp
+++ b/fastboot/fastboot_test.cpp
@@ -59,3 +59,145 @@
EXPECT_DEATH(fb.ParseOsVersion(&hdr, "1.128.3"), "bad OS version");
EXPECT_DEATH(fb.ParseOsVersion(&hdr, "1.2.128"), "bad OS version");
}
+
+extern bool ParseRequirementLine(const std::string& line, std::string* name, std::string* product,
+ bool* invert, std::vector<std::string>* options);
+
+static void ParseRequirementLineTest(const std::string& line, const std::string& expected_name,
+ const std::string& expected_product, bool expected_invert,
+ const std::vector<std::string>& expected_options) {
+ std::string name;
+ std::string product;
+ bool invert;
+ std::vector<std::string> options;
+
+ EXPECT_TRUE(ParseRequirementLine(line, &name, &product, &invert, &options)) << line;
+
+ EXPECT_EQ(expected_name, name) << line;
+ EXPECT_EQ(expected_product, product) << line;
+ EXPECT_EQ(expected_invert, invert) << line;
+ EXPECT_EQ(expected_options, options) << line;
+}
+
+TEST(FastBoot, ParseRequirementLineSuccesses) {
+ // Examples provided in the code + slight variations.
+ ParseRequirementLineTest("require product=alpha", "product", "", false, {"alpha"});
+ ParseRequirementLineTest("require product=alpha|beta|gamma", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ ParseRequirementLineTest("require version-bootloader=1234", "version-bootloader", "", false,
+ {"1234"});
+ ParseRequirementLineTest("require-for-product:gamma version-bootloader=istanbul",
+ "version-bootloader", "gamma", false, {"istanbul"});
+ ParseRequirementLineTest("require-for-product:gamma version-bootloader=istanbul|constantinople",
+ "version-bootloader", "gamma", false, {"istanbul", "constantinople"});
+ ParseRequirementLineTest("require partition-exists=vendor", "partition-exists", "", false,
+ {"vendor"});
+ ParseRequirementLineTest("reject product=alpha", "product", "", true, {"alpha"});
+ ParseRequirementLineTest("reject product=alpha|beta|gamma", "product", "", true,
+ {"alpha", "beta", "gamma"});
+
+ // Without any prefix, assume 'require'
+ ParseRequirementLineTest("product=alpha|beta|gamma", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ // Including if the variable name is otherwise a prefix keyword
+ ParseRequirementLineTest("require = alpha", "require", "", false, {"alpha"});
+ ParseRequirementLineTest("reject = alpha", "reject", "", false, {"alpha"});
+ ParseRequirementLineTest("require-for-product:gamma = alpha", "require-for-product:gamma", "",
+ false, {"alpha"});
+
+ // Extra spaces are allowed.
+ ParseRequirementLineTest("require product=alpha|beta|gamma", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ ParseRequirementLineTest("require product =alpha|beta|gamma", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ ParseRequirementLineTest("require product= alpha|beta|gamma", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ ParseRequirementLineTest("require product = alpha|beta|gamma", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ ParseRequirementLineTest("require product=alpha |beta|gamma", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ ParseRequirementLineTest("require product=alpha| beta|gamma", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ ParseRequirementLineTest("require product=alpha | beta|gamma", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ ParseRequirementLineTest("require product=alpha|beta|gamma ", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ ParseRequirementLineTest("product = alpha | beta | gamma ", "product", "", false,
+ {"alpha", "beta", "gamma"});
+ ParseRequirementLineTest("require-for-product: gamma version-bootloader=istanbul",
+ "version-bootloader", "gamma", false, {"istanbul"});
+
+ // Extraneous ending | is okay, implies accepting an empty string.
+ ParseRequirementLineTest("require product=alpha|", "product", "", false, {"alpha", ""});
+ ParseRequirementLineTest("require product=alpha|beta|gamma|", "product", "", false,
+ {"alpha", "beta", "gamma", ""});
+
+ // Accept empty options, double ||, etc, implies accepting an empty string.
+ ParseRequirementLineTest("require product=alpha||beta| |gamma", "product", "", false,
+ {"alpha", "", "beta", "", "gamma"});
+ ParseRequirementLineTest("require product=alpha||beta|gamma", "product", "", false,
+ {"alpha", "", "beta", "gamma"});
+ ParseRequirementLineTest("require product=alpha|beta| |gamma", "product", "", false,
+ {"alpha", "beta", "", "gamma"});
+ ParseRequirementLineTest("require product=alpha||", "product", "", false, {"alpha", "", ""});
+ ParseRequirementLineTest("require product=alpha|| ", "product", "", false, {"alpha", "", ""});
+ ParseRequirementLineTest("require product=alpha| ", "product", "", false, {"alpha", ""});
+ ParseRequirementLineTest("require product=alpha|beta| ", "product", "", false,
+ {"alpha", "beta", ""});
+
+ // No option string is also treating as accepting an empty string.
+ ParseRequirementLineTest("require =", "require", "", false, {""});
+ ParseRequirementLineTest("require = |", "require", "", false, {"", ""});
+ ParseRequirementLineTest("reject =", "reject", "", false, {""});
+ ParseRequirementLineTest("reject = |", "reject", "", false, {"", ""});
+ ParseRequirementLineTest("require-for-product: =", "require-for-product:", "", false, {""});
+ ParseRequirementLineTest("require-for-product: = | ", "require-for-product:", "", false,
+ {"", ""});
+ ParseRequirementLineTest("require product=", "product", "", false, {""});
+ ParseRequirementLineTest("require product = ", "product", "", false, {""});
+ ParseRequirementLineTest("require product = | ", "product", "", false, {"", ""});
+ ParseRequirementLineTest("reject product=", "product", "", true, {""});
+ ParseRequirementLineTest("reject product = ", "product", "", true, {""});
+ ParseRequirementLineTest("reject product = | ", "product", "", true, {"", ""});
+ ParseRequirementLineTest("require-for-product:gamma product=", "product", "gamma", false, {""});
+ ParseRequirementLineTest("require-for-product:gamma product = ", "product", "gamma", false,
+ {""});
+ ParseRequirementLineTest("require-for-product:gamma product = |", "product", "gamma", false,
+ {"", ""});
+
+ // Check for board -> product substitution.
+ ParseRequirementLineTest("require board=alpha", "product", "", false, {"alpha"});
+ ParseRequirementLineTest("board=alpha", "product", "", false, {"alpha"});
+}
+
+static void ParseRequirementLineTestMalformed(const std::string& line) {
+ std::string name;
+ std::string product;
+ bool invert;
+ std::vector<std::string> options;
+
+ EXPECT_FALSE(ParseRequirementLine(line, &name, &product, &invert, &options)) << line;
+}
+
+TEST(FastBoot, ParseRequirementLineMalformed) {
+ ParseRequirementLineTestMalformed("nothing");
+ ParseRequirementLineTestMalformed("");
+ ParseRequirementLineTestMalformed("=");
+ ParseRequirementLineTestMalformed("|");
+
+ ParseRequirementLineTestMalformed("require");
+ ParseRequirementLineTestMalformed("require ");
+ ParseRequirementLineTestMalformed("reject");
+ ParseRequirementLineTestMalformed("reject ");
+ ParseRequirementLineTestMalformed("require-for-product:");
+ ParseRequirementLineTestMalformed("require-for-product: ");
+
+ ParseRequirementLineTestMalformed("require product");
+ ParseRequirementLineTestMalformed("reject product");
+
+ ParseRequirementLineTestMalformed("require-for-product:gamma");
+ ParseRequirementLineTestMalformed("require-for-product:gamma product");
+
+ // No spaces allowed before between require-for-product and :.
+ ParseRequirementLineTestMalformed("require-for-product :");
+}
diff --git a/fastboot/util.cpp b/fastboot/util.cpp
index 125182d..7d15047 100644
--- a/fastboot/util.cpp
+++ b/fastboot/util.cpp
@@ -74,9 +74,3 @@
static constexpr char kStatusFormat[] = "%-50s ";
fprintf(stderr, kStatusFormat, message.c_str());
}
-
-char* xstrdup(const char* s) {
- char* result = strdup(s);
- if (!result) die("out of memory");
- return result;
-}
diff --git a/fastboot/util.h b/fastboot/util.h
index 20be461..533d2c7 100644
--- a/fastboot/util.h
+++ b/fastboot/util.h
@@ -9,7 +9,6 @@
/* util stuff */
double now();
-char* xstrdup(const char*);
void set_verbose();
void Status(const std::string& message);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index f56043c..d29ccf4 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -569,8 +569,7 @@
* -1 on failure with errno set to match the 1st mount failure.
* 0 on success.
*/
-static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_idx, int *attempted_idx)
-{
+static int mount_with_alternatives(fstab* fstab, int start_idx, int* end_idx, int* attempted_idx) {
int i;
int mount_errno = 0;
int mounted = 0;
@@ -805,6 +804,23 @@
return true;
}
+static bool call_vdc_ret(const std::vector<std::string>& args, int* ret) {
+ std::vector<char const*> argv;
+ argv.emplace_back("/system/bin/vdc");
+ for (auto& arg : args) {
+ argv.emplace_back(arg.c_str());
+ }
+ LOG(INFO) << "Calling: " << android::base::Join(argv, ' ');
+ int err = android_fork_execvp(argv.size(), const_cast<char**>(argv.data()), ret, false, true);
+ if (err != 0) {
+ LOG(ERROR) << "vdc call failed with error code: " << err;
+ return false;
+ }
+ LOG(DEBUG) << "vdc finished successfully";
+ *ret = WEXITSTATUS(*ret);
+ return true;
+}
+
bool fs_mgr_update_logical_partition(struct fstab_rec* rec) {
// Logical partitions are specified with a named partition rather than a
// block device, so if the block device is a path, then it has already
@@ -823,19 +839,37 @@
return true;
}
+bool fs_mgr_update_checkpoint_partition(struct fstab_rec* rec) {
+ if (fs_mgr_is_checkpoint(rec)) {
+ if (!strcmp(rec->fs_type, "f2fs")) {
+ std::string opts(rec->fs_options);
+
+ opts += ",checkpoint=disable";
+ free(rec->fs_options);
+ rec->fs_options = strdup(opts.c_str());
+ } else {
+ LERROR << rec->fs_type << " does not implement checkpoints.";
+ }
+ } else if (rec->fs_mgr_flags & MF_CHECKPOINT_BLK) {
+ LERROR << "Block based checkpoint not implemented.";
+ return false;
+ }
+ return true;
+}
+
/* When multiple fstab records share the same mount_point, it will
* try to mount each one in turn, and ignore any duplicates after a
* first successful mount.
* Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
*/
-int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
-{
+int fs_mgr_mount_all(fstab* fstab, int mount_mode) {
int i = 0;
int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
int error_count = 0;
int mret = -1;
int mount_errno = 0;
int attempted_idx = -1;
+ int need_checkpoint = -1;
FsManagerAvbUniquePtr avb_handle(nullptr);
if (!fstab) {
@@ -882,6 +916,18 @@
}
}
+ if (fs_mgr_is_checkpoint(&fstab->recs[i])) {
+ if (need_checkpoint == -1 &&
+ !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &need_checkpoint)) {
+ LERROR << "Failed to find if checkpointing is needed. Assuming no.";
+ need_checkpoint = 0;
+ }
+ if (need_checkpoint == 1 && !fs_mgr_update_checkpoint_partition(&fstab->recs[i])) {
+ LERROR << "Could not set up checkpoint partition, skipping!";
+ continue;
+ }
+ }
+
if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
!fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
LERROR << "Skipping '" << fstab->recs[i].blk_device << "' during mount_all";
@@ -1045,7 +1091,7 @@
}
#if ALLOW_ADBD_DISABLE_VERITY == 1 // "userdebug" build
- fs_mgr_overlayfs_mount_all();
+ fs_mgr_overlayfs_mount_all(fstab);
#endif
if (error_count) {
@@ -1081,9 +1127,8 @@
* If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
* in turn, and stop on 1st success, or no more match.
*/
-int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
- char *tmp_mount_point)
-{
+static int fs_mgr_do_mount_helper(fstab* fstab, const char* n_name, char* n_blk_device,
+ char* tmp_mount_point, int need_checkpoint) {
int i = 0;
int mount_errors = 0;
int first_mount_errno = 0;
@@ -1116,6 +1161,18 @@
}
}
+ if (fs_mgr_is_checkpoint(&fstab->recs[i])) {
+ if (need_checkpoint == -1 &&
+ !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &need_checkpoint)) {
+ LERROR << "Failed to find if checkpointing is needed. Assuming no.";
+ need_checkpoint = 0;
+ }
+ if (need_checkpoint == 1 && !fs_mgr_update_checkpoint_partition(&fstab->recs[i])) {
+ LERROR << "Could not set up checkpoint partition, skipping!";
+ continue;
+ }
+ }
+
/* First check the filesystem if requested */
if (fstab->recs[i].fs_mgr_flags & MF_WAIT && !fs_mgr_wait_for_file(n_blk_device, 20s)) {
LERROR << "Skipping mounting '" << n_blk_device << "'";
@@ -1185,6 +1242,15 @@
return FS_MGR_DOMNT_FAILED;
}
+int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point) {
+ return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, -1);
+}
+
+int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
+ bool needs_cp) {
+ return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_cp);
+}
+
/*
* mount a tmpfs filesystem at the given point.
* return 0 on success, non-zero on failure.
@@ -1207,8 +1273,7 @@
/* This must be called after mount_all, because the mkswap command needs to be
* available.
*/
-int fs_mgr_swapon_all(struct fstab *fstab)
-{
+int fs_mgr_swapon_all(fstab* fstab) {
int i = 0;
int flags = 0;
int err = 0;
@@ -1298,7 +1363,7 @@
return ret;
}
-struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab) {
+struct fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab) {
int i;
if (!fstab) {
@@ -1322,7 +1387,7 @@
*
* real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
*/
-void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size) {
+void fs_mgr_get_crypt_info(fstab* fstab, char* key_loc, char* real_blk_device, size_t size) {
struct fstab_rec const* rec = fs_mgr_get_crypt_entry(fstab);
if (key_loc) {
if (rec) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index f87a3b1..250793a 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -80,37 +80,39 @@
};
static struct flag_list fs_mgr_flags[] = {
- {"wait", MF_WAIT},
- {"check", MF_CHECK},
- {"encryptable=", MF_CRYPT},
- {"forceencrypt=", MF_FORCECRYPT},
- {"fileencryption=", MF_FILEENCRYPTION},
- {"forcefdeorfbe=", MF_FORCEFDEORFBE},
- {"keydirectory=", MF_KEYDIRECTORY},
- {"nonremovable", MF_NONREMOVABLE},
- {"voldmanaged=", MF_VOLDMANAGED},
- {"length=", MF_LENGTH},
- {"recoveryonly", MF_RECOVERYONLY},
- {"swapprio=", MF_SWAPPRIO},
- {"zramsize=", MF_ZRAMSIZE},
- {"max_comp_streams=", MF_MAX_COMP_STREAMS},
- {"verifyatboot", MF_VERIFYATBOOT},
- {"verify", MF_VERIFY},
- {"avb", MF_AVB},
- {"noemulatedsd", MF_NOEMULATEDSD},
- {"notrim", MF_NOTRIM},
- {"formattable", MF_FORMATTABLE},
- {"slotselect", MF_SLOTSELECT},
- {"nofail", MF_NOFAIL},
- {"latemount", MF_LATEMOUNT},
- {"reservedsize=", MF_RESERVEDSIZE},
- {"quota", MF_QUOTA},
- {"eraseblk=", MF_ERASEBLKSIZE},
- {"logicalblk=", MF_LOGICALBLKSIZE},
- {"sysfs_path=", MF_SYSFS},
- {"defaults", 0},
- {"logical", MF_LOGICAL},
- {0, 0},
+ {"wait", MF_WAIT},
+ {"check", MF_CHECK},
+ {"encryptable=", MF_CRYPT},
+ {"forceencrypt=", MF_FORCECRYPT},
+ {"fileencryption=", MF_FILEENCRYPTION},
+ {"forcefdeorfbe=", MF_FORCEFDEORFBE},
+ {"keydirectory=", MF_KEYDIRECTORY},
+ {"nonremovable", MF_NONREMOVABLE},
+ {"voldmanaged=", MF_VOLDMANAGED},
+ {"length=", MF_LENGTH},
+ {"recoveryonly", MF_RECOVERYONLY},
+ {"swapprio=", MF_SWAPPRIO},
+ {"zramsize=", MF_ZRAMSIZE},
+ {"max_comp_streams=", MF_MAX_COMP_STREAMS},
+ {"verifyatboot", MF_VERIFYATBOOT},
+ {"verify", MF_VERIFY},
+ {"avb", MF_AVB},
+ {"noemulatedsd", MF_NOEMULATEDSD},
+ {"notrim", MF_NOTRIM},
+ {"formattable", MF_FORMATTABLE},
+ {"slotselect", MF_SLOTSELECT},
+ {"nofail", MF_NOFAIL},
+ {"latemount", MF_LATEMOUNT},
+ {"reservedsize=", MF_RESERVEDSIZE},
+ {"quota", MF_QUOTA},
+ {"eraseblk=", MF_ERASEBLKSIZE},
+ {"logicalblk=", MF_LOGICALBLKSIZE},
+ {"sysfs_path=", MF_SYSFS},
+ {"defaults", 0},
+ {"logical", MF_LOGICAL},
+ {"checkpoint=block", MF_CHECKPOINT_BLK},
+ {"checkpoint=fs", MF_CHECKPOINT_FS},
+ {0, 0},
};
#define EM_AES_256_XTS 1
@@ -1004,3 +1006,15 @@
int fs_mgr_is_logical(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_LOGICAL;
}
+
+int fs_mgr_is_checkpoint(const struct fstab_rec* fstab) {
+ return fstab->fs_mgr_flags & (MF_CHECKPOINT_FS | MF_CHECKPOINT_BLK);
+}
+
+int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab) {
+ return fstab->fs_mgr_flags & MF_CHECKPOINT_FS;
+}
+
+int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab) {
+ return fstab->fs_mgr_flags & MF_CHECKPOINT_BLK;
+}
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 720dcfd..c0bef2c 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -49,7 +49,7 @@
#if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs
-bool fs_mgr_overlayfs_mount_all() {
+bool fs_mgr_overlayfs_mount_all(const fstab*) {
return false;
}
@@ -109,9 +109,9 @@
struct statvfs vst;
if (statvfs(mount_point, &vst)) return true;
- static constexpr int percent = 1; // 1%
+ static constexpr int kPercentThreshold = 1; // 1%
- return (vst.f_bfree >= (vst.f_blocks * percent / 100));
+ return (vst.f_bfree >= (vst.f_blocks * kPercentThreshold / 100));
}
bool fs_mgr_overlayfs_enabled(const struct fstab_rec* fsrec) {
@@ -123,22 +123,24 @@
!fs_mgr_filesystem_has_space(fsrec->mount_point);
}
-constexpr char upper_name[] = "upper";
-constexpr char work_name[] = "work";
+const auto kUpperName = "upper"s;
+const auto kWorkName = "work"s;
+const auto kOverlayTopDir = "/overlay"s;
std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) {
if (!fs_mgr_is_dir(mount_point)) return "";
- auto dir = kOverlayMountPoint + "/overlay/" + android::base::Basename(mount_point) + "/";
- auto upper = dir + upper_name;
+ auto dir =
+ kOverlayMountPoint + kOverlayTopDir + "/" + android::base::Basename(mount_point) + "/";
+ auto upper = dir + kUpperName;
if (!fs_mgr_is_dir(upper)) return "";
- auto work = dir + work_name;
+ auto work = dir + kWorkName;
if (!fs_mgr_is_dir(work)) return "";
if (!fs_mgr_dir_is_writable(work)) return "";
return dir;
}
-constexpr char lowerdir_option[] = "lowerdir=";
-constexpr char upperdir_option[] = "upperdir=";
+const auto kLowerdirOption = "lowerdir="s;
+const auto kUpperdirOption = "upperdir="s;
// default options for mount_point, returns empty string for none available.
std::string fs_mgr_get_overlayfs_options(const std::string& mount_point) {
@@ -147,8 +149,8 @@
auto context = fs_mgr_get_context(mount_point);
if (!context.empty()) context = ",rootcontext="s + context;
- return "override_creds=off,"s + lowerdir_option + mount_point + "," + upperdir_option +
- candidate + upper_name + ",workdir=" + candidate + work_name + context;
+ return "override_creds=off,"s + kLowerdirOption + mount_point + "," + kUpperdirOption +
+ candidate + kUpperName + ",workdir=" + candidate + kWorkName + context;
}
bool fs_mgr_system_root_image(const fstab* fstab) {
@@ -192,6 +194,31 @@
return overlayfs_in_kernel;
}
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) {
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab("/proc/mounts"),
+ fs_mgr_free_fstab);
+ if (!fstab) return false;
+ const auto lowerdir = kLowerdirOption + mount_point;
+ for (auto i = 0; i < fstab->num_entries; ++i) {
+ const auto fsrec = &fstab->recs[i];
+ const auto fs_type = fsrec->fs_type;
+ if (!fs_type) continue;
+ if (("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
+ auto fsrec_mount_point = fsrec->mount_point;
+ if (!fsrec_mount_point) continue;
+ if (mount_point != fsrec_mount_point) continue;
+ const auto fs_options = fsrec->fs_options;
+ if (!fs_options) continue;
+ const auto options = android::base::Split(fs_options, ",");
+ for (const auto& opt : options) {
+ if (opt == lowerdir) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool fs_mgr_wants_overlayfs(const fstab_rec* fsrec) {
if (!fsrec) return false;
@@ -265,16 +292,16 @@
return ret;
}
-constexpr char overlayfs_file_context[] = "u:object_r:overlayfs_file:s0";
+constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";
bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& mount_point,
bool* change) {
auto ret = true;
- auto fsrec_mount_point = overlay + android::base::Basename(mount_point) + "/";
+ auto fsrec_mount_point = overlay + "/" + android::base::Basename(mount_point) + "/";
- if (setfscreatecon(overlayfs_file_context)) {
+ if (setfscreatecon(kOverlayfsFileContext)) {
ret = false;
- PERROR << "overlayfs setfscreatecon " << overlayfs_file_context;
+ PERROR << "overlayfs setfscreatecon " << kOverlayfsFileContext;
}
auto save_errno = errno;
if (!mkdir(fsrec_mount_point.c_str(), 0755)) {
@@ -287,11 +314,11 @@
}
save_errno = errno;
- if (!mkdir((fsrec_mount_point + work_name).c_str(), 0755)) {
+ if (!mkdir((fsrec_mount_point + kWorkName).c_str(), 0755)) {
if (change) *change = true;
} else if (errno != EEXIST) {
ret = false;
- PERROR << "overlayfs mkdir " << fsrec_mount_point << work_name;
+ PERROR << "overlayfs mkdir " << fsrec_mount_point << kWorkName;
} else {
errno = save_errno;
}
@@ -302,7 +329,7 @@
ret = false;
PERROR << "overlayfs setfscreatecon " << new_context;
}
- auto upper = fsrec_mount_point + upper_name;
+ auto upper = fsrec_mount_point + kUpperName;
save_errno = errno;
if (!mkdir(upper.c_str(), 0755)) {
if (change) *change = true;
@@ -325,7 +352,7 @@
auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay";
const auto opt_list = android::base::Split(options, ",");
for (const auto opt : opt_list) {
- if (android::base::StartsWith(opt, upperdir_option)) {
+ if (android::base::StartsWith(opt, kUpperdirOption)) {
report = report + "," + opt;
break;
}
@@ -343,31 +370,6 @@
}
}
-bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) {
- std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(
- fs_mgr_read_fstab("/proc/mounts"), fs_mgr_free_fstab);
- if (!fstab) return false;
- const auto lowerdir = std::string(lowerdir_option) + mount_point;
- for (auto i = 0; i < fstab->num_entries; ++i) {
- const auto fsrec = &fstab->recs[i];
- const auto fs_type = fsrec->fs_type;
- if (!fs_type) continue;
- if (("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
- auto fsrec_mount_point = fsrec->mount_point;
- if (!fsrec_mount_point) continue;
- if (mount_point != fsrec_mount_point) continue;
- const auto fs_options = fsrec->fs_options;
- if (!fs_options) continue;
- const auto options = android::base::Split(fs_options, ",");
- for (const auto opt : options) {
- if (opt == lowerdir) {
- return true;
- }
- }
- }
- return false;
-}
-
std::vector<std::string> fs_mgr_candidate_list(const fstab* fstab,
const char* mount_point = nullptr) {
std::vector<std::string> mounts;
@@ -398,16 +400,14 @@
} // namespace
-bool fs_mgr_overlayfs_mount_all() {
+bool fs_mgr_overlayfs_mount_all(const fstab* fstab) {
auto ret = false;
if (!fs_mgr_wants_overlayfs()) return ret;
- std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
- fs_mgr_free_fstab);
if (!fstab) return ret;
- for (const auto& mount_point : fs_mgr_candidate_list(fstab.get())) {
+ for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
if (fs_mgr_overlayfs_already_mounted(mount_point)) continue;
if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
}
@@ -430,16 +430,16 @@
return ret;
}
- std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
- fs_mgr_free_fstab);
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
if (fstab && !fs_mgr_get_entry_for_mount_point(fstab.get(), kOverlayMountPoint)) return ret;
auto mounts = fs_mgr_candidate_list(fstab.get(), fs_mgr_mount_point(fstab.get(), mount_point));
if (fstab && mounts.empty()) return ret;
- if (setfscreatecon(overlayfs_file_context)) {
- PERROR << "overlayfs setfscreatecon " << overlayfs_file_context;
+ if (setfscreatecon(kOverlayfsFileContext)) {
+ PERROR << "overlayfs setfscreatecon " << kOverlayfsFileContext;
}
- auto overlay = kOverlayMountPoint + "/overlay/";
+ auto overlay = kOverlayMountPoint + kOverlayTopDir;
auto save_errno = errno;
if (!mkdir(overlay.c_str(), 0755)) {
if (change) *change = true;
@@ -462,13 +462,13 @@
// If something is altered, set *change.
bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) {
if (change) *change = false;
- mount_point = fs_mgr_mount_point(std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)>(
+ mount_point = fs_mgr_mount_point(std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>(
fs_mgr_read_fstab_default(), fs_mgr_free_fstab)
.get(),
mount_point);
auto ret = true;
- const auto overlay = kOverlayMountPoint + "/overlay";
- const auto oldpath = overlay + (mount_point ?: "");
+ const auto overlay = kOverlayMountPoint + kOverlayTopDir;
+ const auto oldpath = overlay + (mount_point ? "/"s + mount_point : ""s);
const auto newpath = oldpath + ".teardown";
ret &= fs_mgr_rm_all(newpath);
auto save_errno = errno;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index ebc4a0f..506e81d 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -113,6 +113,8 @@
#define MF_KEYDIRECTORY 0X4000000
#define MF_SYSFS 0X8000000
#define MF_LOGICAL 0x10000000
+#define MF_CHECKPOINT_BLK 0x20000000
+#define MF_CHECKPOINT_FS 0x40000000
// clang-format on
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 1049fb6..cee069b 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -70,6 +70,8 @@
int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point);
+int fs_mgr_do_mount(struct fstab* fstab, const char* n_name, char* n_blk_device,
+ char* tmp_mount_point, bool need_cp);
int fs_mgr_do_mount_one(struct fstab_rec *rec);
int fs_mgr_do_tmpfs_mount(const char *n_name);
struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index ceb45de..251dd9b 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -20,7 +20,7 @@
#include <string>
-bool fs_mgr_overlayfs_mount_all();
+bool fs_mgr_overlayfs_mount_all(const fstab* fstab);
bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
bool* change = nullptr);
bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index b1ee328..bb40511 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -86,6 +86,9 @@
int fs_mgr_is_latemount(const struct fstab_rec* fstab);
int fs_mgr_is_quota(const struct fstab_rec* fstab);
int fs_mgr_is_logical(const struct fstab_rec* fstab);
+int fs_mgr_is_checkpoint(const struct fstab_rec* fstab);
+int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab);
+int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab);
int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
std::string fs_mgr_get_slot_suffix();
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 018c280..352647b 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -482,6 +482,14 @@
return (geometry_.last_logical_sector - geometry_.first_logical_sector + 1) * LP_SECTOR_SIZE;
}
+uint64_t MetadataBuilder::UsedSpace() const {
+ uint64_t size = 0;
+ for (const auto& partition : partitions_) {
+ size += partition->size();
+ }
+ return size;
+}
+
uint64_t MetadataBuilder::AlignSector(uint64_t sector) {
// Note: when reading alignment info from the Kernel, we don't assume it
// is aligned to the sector size, so we round up to the nearest sector.
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index da9c8f3..0c7e43d 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -202,14 +202,28 @@
}
TEST(liblp, UseAllDiskSpace) {
- unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
- EXPECT_EQ(builder->AllocatableSpace(), 1036288);
+ static constexpr uint64_t total = 1024 * 1024;
+ static constexpr uint64_t metadata = 1024;
+ static constexpr uint64_t slots = 2;
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(total, metadata, slots);
+ // We reserve a geometry block (4KB) plus space for each copy of the
+ // maximum size of a metadata blob. Then, we double that space since
+ // we store a backup copy of everything.
+ static constexpr uint64_t geometry = 4 * 1024;
+ static constexpr uint64_t allocatable = total - (metadata * slots + geometry) * 2;
+ EXPECT_EQ(builder->AllocatableSpace(), allocatable);
+ EXPECT_EQ(builder->UsedSpace(), 0);
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
- EXPECT_EQ(builder->ResizePartition(system, 1036288), true);
- EXPECT_EQ(system->size(), 1036288);
- EXPECT_EQ(builder->ResizePartition(system, 1036289), false);
+ EXPECT_EQ(builder->ResizePartition(system, allocatable), true);
+ EXPECT_EQ(system->size(), allocatable);
+ EXPECT_EQ(builder->UsedSpace(), allocatable);
+ EXPECT_EQ(builder->AllocatableSpace(), allocatable);
+ EXPECT_EQ(builder->ResizePartition(system, allocatable + 1), false);
+ EXPECT_EQ(system->size(), allocatable);
+ EXPECT_EQ(builder->UsedSpace(), allocatable);
+ EXPECT_EQ(builder->AllocatableSpace(), allocatable);
}
TEST(liblp, BuildComplex) {
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 38842a4..2780825 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -184,6 +184,7 @@
// Amount of space that can be allocated to logical partitions.
uint64_t AllocatableSpace() const;
+ uint64_t UsedSpace() const;
// Merge new block device information into previous values. Alignment values
// are only overwritten if the new values are non-zero.
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 329a901..eda68fd 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -117,6 +117,9 @@
uint64_t size;
ASSERT_TRUE(GetDescriptorSize(fd, &size));
ASSERT_EQ(size, kDiskSize);
+
+ // Verify that we can't read unwritten metadata.
+ ASSERT_EQ(ReadMetadata(fd, 1), nullptr);
}
// Flashing metadata should not work if the metadata was created for a larger
@@ -191,9 +194,6 @@
ASSERT_EQ(imported->partitions.size(), 1);
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "system");
- // Verify that we can't read unwritten metadata.
- ASSERT_EQ(ReadMetadata(fd, 1), nullptr);
-
// Change the name before writing to the next slot.
strncpy(imported->partitions[0].name, "vendor", sizeof(imported->partitions[0].name));
ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1));
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index ad84b22..9dd2745 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -94,7 +94,8 @@
}
// Make sure we're writing within the space reserved.
if (blob->size() > geometry.metadata_max_size) {
- LERROR << "Logical partition metadata is too large.";
+ LERROR << "Logical partition metadata is too large. " << blob->size() << " > "
+ << geometry.metadata_max_size;
return false;
}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index a901131..71a8e0d 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -396,7 +396,7 @@
}
}
- fs_mgr_overlayfs_mount_all();
+ fs_mgr_overlayfs_mount_all(device_tree_fstab_.get());
return true;
}
diff --git a/init/init.cpp b/init/init.cpp
index e5c1548..47cfe32 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -346,12 +346,12 @@
if (!android::base::GetBoolProperty("ro.oem_unlock_supported", false)) {
return;
}
-
- std::string value = GetProperty("ro.boot.verifiedbootstate", "");
-
- if (!value.empty()) {
- property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
- }
+ import_kernel_cmdline(
+ false, [](const std::string& key, const std::string& value, bool in_qemu) {
+ if (key == "androidboot.verifiedbootstate") {
+ property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
+ }
+ });
}
static void export_kernel_boot_props() {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 2f88121..b84bfd3 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -464,6 +464,12 @@
cmd = ANDROID_RB_RESTART2;
if (cmd_params.size() >= 2) {
reboot_target = cmd_params[1];
+ // adb reboot fastboot should boot into bootloader for devices not
+ // supporting logical partitions.
+ if (reboot_target == "fastboot" &&
+ !android::base::GetBoolProperty("ro.boot.logical_partitions", false)) {
+ reboot_target = "bootloader";
+ }
// When rebooting to the bootloader notify the bootloader writing
// also the BCB.
if (reboot_target == "bootloader") {
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index c2a21d4..092c51c 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -62,7 +62,9 @@
Result<std::string> ReadMessage(int socket) {
char buffer[kBufferSize] = {};
auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
- if (result <= 0) {
+ if (result == 0) {
+ return Error();
+ } else if (result < 0) {
return ErrnoError();
}
return std::string(buffer, result);
@@ -175,6 +177,12 @@
auto init_message = ReadMessage(init_fd_);
if (!init_message) {
+ if (init_message.error_errno() == 0) {
+ // If the init file descriptor was closed, let's exit quietly. If
+ // this was accidental, init will restart us. If init died, this
+ // avoids calling abort(3) unnecessarily.
+ return;
+ }
LOG(FATAL) << "Could not read message from init: " << init_message.error();
}
diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp
index bcc0616..d27feb9 100644
--- a/libgrallocusage/Android.bp
+++ b/libgrallocusage/Android.bp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-cc_library_static {
+cc_library {
name: "libgrallocusage",
vendor_available: true,
cflags: [
diff --git a/libgrallocusage/OWNERS b/libgrallocusage/OWNERS
new file mode 100644
index 0000000..154dc6d
--- /dev/null
+++ b/libgrallocusage/OWNERS
@@ -0,0 +1,3 @@
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index d1f20f4..383d0e7 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -131,7 +131,7 @@
static bool isLogdwActive() {
std::string logdwSignature =
- popenToString("grep /dev/socket/logdw /proc/net/unix");
+ popenToString("grep -a /dev/socket/logdw /proc/net/unix");
size_t beginning = logdwSignature.find(' ');
if (beginning == std::string::npos) return true;
beginning = logdwSignature.find(' ', beginning + 1);
@@ -145,7 +145,7 @@
end = logdwSignature.find(' ', end + 1);
if (end == std::string::npos) return true;
std::string allLogdwEndpoints = popenToString(
- "grep ' 00000002" + logdwSignature.substr(beginning, end - beginning) +
+ "grep -a ' 00000002" + logdwSignature.substr(beginning, end - beginning) +
" ' /proc/net/unix | " +
"sed -n 's/.* \\([0-9][0-9]*\\)$/ -> socket:[\\1]/p'");
if (allLogdwEndpoints.length() == 0) return true;
diff --git a/mkbootimg/include/bootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h
index bce308b..4432f9e 100644
--- a/mkbootimg/include/bootimg/bootimg.h
+++ b/mkbootimg/include/bootimg/bootimg.h
@@ -110,25 +110,25 @@
*/
struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
- uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO image */
- uint64_t recovery_dtbo_offset; /* offset to recovery dtbo in boot image */
+ uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO/ACPIO image */
+ uint64_t recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */
uint32_t header_size;
} __attribute__((packed));
/* When the boot image header has a version of 1, the structure of the boot
* image is as follows:
*
- * +-----------------+
- * | boot header | 1 page
- * +-----------------+
- * | kernel | n pages
- * +-----------------+
- * | ramdisk | m pages
- * +-----------------+
- * | second stage | o pages
- * +-----------------+
- * | recovery dtbo | p pages
- * +-----------------+
+ * +---------------------+
+ * | boot header | 1 page
+ * +---------------------+
+ * | kernel | n pages
+ * +---------------------+
+ * | ramdisk | m pages
+ * +---------------------+
+ * | second stage | o pages
+ * +---------------------+
+ * | recovery dtbo/acpio | p pages
+ * +---------------------+
* n = (kernel_size + page_size - 1) / page_size
* m = (ramdisk_size + page_size - 1) / page_size
* o = (second_size + page_size - 1) / page_size
@@ -136,13 +136,14 @@
*
* 0. all entities are page_size aligned in flash
* 1. kernel and ramdisk are required (size != 0)
- * 2. recovery_dtbo is required for recovery.img in non-A/B devices(recovery_dtbo_size != 0)
+ * 2. recovery_dtbo/recovery_acpio is required for recovery.img in non-A/B
+ * devices(recovery_dtbo_size != 0)
* 3. second is optional (second_size == 0 -> no second)
* 4. load each element (kernel, ramdisk, second) at
* the specified physical address (kernel_addr, etc)
- * 5. If booting to recovery mode in a non-A/B device, extract recovery dtbo and
- * apply the correct set of overlays on the base device tree depending on the
- * hardware/product revision.
+ * 5. If booting to recovery mode in a non-A/B device, extract recovery
+ * dtbo/acpio and apply the correct set of overlays on the base device tree
+ * depending on the hardware/product revision.
* 6. prepare tags at tag_addr. kernel_args[] is
* appended to the kernel commandline in the tags.
* 7. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg
index fda9af0..2eb2bab 100755
--- a/mkbootimg/mkbootimg
+++ b/mkbootimg/mkbootimg
@@ -161,7 +161,10 @@
required=True)
parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
- parser.add_argument('--recovery_dtbo', help='path to the recovery DTBO', type=FileType('rb'))
+ recovery_dtbo_group = parser.add_mutually_exclusive_group()
+ recovery_dtbo_group.add_argument('--recovery_dtbo', help='path to the recovery DTBO', type=FileType('rb'))
+ recovery_dtbo_group.add_argument('--recovery_acpio', help='path to the recovery ACPIO',
+ type=FileType('rb'), metavar='RECOVERY_ACPIO', dest='recovery_dtbo')
parser.add_argument('--cmdline', help='extra arguments to be passed on the '
'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536)
parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 915540e..f39ea7c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -407,6 +407,9 @@
mkdir /data/bootchart 0755 shell shell
bootchart start
+ # Start apexd as soon as we can
+ start apexd
+
# Avoid predictable entropy pool. Carry over entropy from previous boot.
copy /data/system/entropy.dat /dev/urandom