Merge "fs_mgr/init: use unique_ptr + CLO_EXEC for setmntent()/fopen()"
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 6e143c1..e38e305 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -841,14 +841,19 @@
return -1;
}
- std::string service = android::base::StringPrintf(
- "sideload-host:%d:%d", static_cast<int>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
+ std::string service =
+ android::base::StringPrintf("sideload-host:%" PRId64 ":%d",
+ static_cast<int64_t>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
std::string error;
unique_fd device_fd(adb_connect(service, &error));
if (device_fd < 0) {
- // Try falling back to the older (<= K) sideload method. Maybe this
- // is an older device that doesn't support sideload-host.
fprintf(stderr, "adb: sideload connection failed: %s\n", error.c_str());
+
+ // If this is a small enough package, maybe this is an older device that doesn't
+ // support sideload-host. Try falling back to the older (<= K) sideload method.
+ if (sb.st_size > INT_MAX) {
+ return -1;
+ }
fprintf(stderr, "adb: trying pre-KitKat sideload method...\n");
return adb_sideload_legacy(filename, package_fd, static_cast<int>(sb.st_size));
}
@@ -858,7 +863,7 @@
char buf[SIDELOAD_HOST_BLOCK_SIZE];
- size_t xfer = 0;
+ int64_t xfer = 0;
int last_percent = -1;
while (true) {
if (!ReadFdExactly(device_fd, buf, 8)) {
@@ -874,20 +879,22 @@
return 0;
}
- int block = strtol(buf, nullptr, 10);
-
- size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
- if (offset >= static_cast<size_t>(sb.st_size)) {
- fprintf(stderr, "adb: failed to read block %d past end\n", block);
+ int64_t block = strtoll(buf, nullptr, 10);
+ int64_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
+ if (offset >= static_cast<int64_t>(sb.st_size)) {
+ fprintf(stderr,
+ "adb: failed to read block %" PRId64 " at offset %" PRId64 ", past end %" PRId64
+ "\n",
+ block, offset, static_cast<int64_t>(sb.st_size));
return -1;
}
size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
- if ((offset + SIDELOAD_HOST_BLOCK_SIZE) > static_cast<size_t>(sb.st_size)) {
+ if ((offset + SIDELOAD_HOST_BLOCK_SIZE) > static_cast<int64_t>(sb.st_size)) {
to_write = sb.st_size - offset;
}
- if (adb_lseek(package_fd, offset, SEEK_SET) != static_cast<int>(offset)) {
+ if (adb_lseek(package_fd, offset, SEEK_SET) != offset) {
fprintf(stderr, "adb: failed to seek to package block: %s\n", strerror(errno));
return -1;
}
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index cf4d294..ae02525 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -35,6 +35,7 @@
#include <string>
#include <vector>
+#include <android-base/file.h>
#include <android-base/properties.h>
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
@@ -47,6 +48,8 @@
#include "adb_utils.h"
#include "set_verity_enable_state_service.h"
+using android::base::Realpath;
+
// Returns the last device used to mount a directory in /proc/mounts.
// This will find overlayfs entry where upperdir=lowerdir, to make sure
// remount is associated with the correct directory.
@@ -55,9 +58,15 @@
std::string mnt_fsname;
if (!fp) return mnt_fsname;
+ // dir might be a symlink, e.g., /product -> /system/product in GSI.
+ std::string canonical_path;
+ if (!Realpath(dir, &canonical_path)) {
+ PLOG(ERROR) << "Realpath failed: " << dir;
+ }
+
mntent* e;
while ((e = getmntent(fp.get())) != nullptr) {
- if (strcmp(dir, e->mnt_dir) == 0) {
+ if (canonical_path == e->mnt_dir) {
mnt_fsname = e->mnt_fsname;
}
}
@@ -146,6 +155,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 +229,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/sysdeps.h b/adb/sysdeps.h
index be0bdd0..b8d7e06 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -52,10 +52,11 @@
#include <fcntl.h>
#include <io.h>
#include <process.h>
+#include <stdint.h>
#include <sys/stat.h>
#include <utime.h>
-#include <winsock2.h>
#include <windows.h>
+#include <winsock2.h>
#include <ws2tcpip.h>
#include <memory> // unique_ptr
@@ -92,7 +93,7 @@
extern int adb_creat(const char* path, int mode);
extern int adb_read(int fd, void* buf, int len);
extern int adb_write(int fd, const void* buf, int len);
-extern int adb_lseek(int fd, int pos, int where);
+extern int64_t adb_lseek(int fd, int64_t pos, int where);
extern int adb_shutdown(int fd, int direction = SHUT_RDWR);
extern int adb_close(int fd);
extern int adb_register_socket(SOCKET s);
@@ -315,25 +316,24 @@
#else /* !_WIN32 a.k.a. Unix */
-#include <cutils/sockets.h>
#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <pthread.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdarg.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <poll.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <string>
+#include <cutils/sockets.h>
+
#define OS_PATH_SEPARATORS "/"
#define OS_PATH_SEPARATOR '/'
#define OS_PATH_SEPARATOR_STR "/"
@@ -443,12 +443,15 @@
#undef write
#define write ___xxx_write
-static __inline__ int adb_lseek(int fd, int pos, int where)
-{
+static __inline__ int64_t adb_lseek(int fd, int64_t pos, int where) {
+#if defined(__APPLE__)
return lseek(fd, pos, where);
+#else
+ return lseek64(fd, pos, where);
+#endif
}
-#undef lseek
-#define lseek ___xxx_lseek
+#undef lseek
+#define lseek ___xxx_lseek
static __inline__ int adb_unlink(const char* path)
{
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 026dd1c..8784757 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -52,12 +52,11 @@
typedef const struct FHClassRec_* FHClass;
typedef struct FHRec_* FH;
-typedef struct EventHookRec_* EventHook;
typedef struct FHClassRec_ {
void (*_fh_init)(FH);
int (*_fh_close)(FH);
- int (*_fh_lseek)(FH, int, int);
+ int64_t (*_fh_lseek)(FH, int64_t, int);
int (*_fh_read)(FH, void*, int);
int (*_fh_write)(FH, const void*, int);
int (*_fh_writev)(FH, const adb_iovec*, int);
@@ -65,7 +64,7 @@
static void _fh_file_init(FH);
static int _fh_file_close(FH);
-static int _fh_file_lseek(FH, int, int);
+static int64_t _fh_file_lseek(FH, int64_t, int);
static int _fh_file_read(FH, void*, int);
static int _fh_file_write(FH, const void*, int);
static int _fh_file_writev(FH, const adb_iovec*, int);
@@ -81,7 +80,7 @@
static void _fh_socket_init(FH);
static int _fh_socket_close(FH);
-static int _fh_socket_lseek(FH, int, int);
+static int64_t _fh_socket_lseek(FH, int64_t, int);
static int _fh_socket_read(FH, void*, int);
static int _fh_socket_write(FH, const void*, int);
static int _fh_socket_writev(FH, const adb_iovec*, int);
@@ -318,10 +317,8 @@
return wrote_bytes;
}
-static int _fh_file_lseek(FH f, int pos, int origin) {
+static int64_t _fh_file_lseek(FH f, int64_t pos, int origin) {
DWORD method;
- DWORD result;
-
switch (origin) {
case SEEK_SET:
method = FILE_BEGIN;
@@ -337,14 +334,13 @@
return -1;
}
- result = SetFilePointer(f->fh_handle, pos, nullptr, method);
- if (result == INVALID_SET_FILE_POINTER) {
+ LARGE_INTEGER li = {.QuadPart = pos};
+ if (!SetFilePointerEx(f->fh_handle, li, &li, method)) {
errno = EIO;
return -1;
- } else {
- f->eof = 0;
}
- return (int)result;
+ f->eof = 0;
+ return li.QuadPart;
}
/**************************************************************************/
@@ -491,14 +487,12 @@
return f->clazz->_fh_writev(f, iov, iovcnt);
}
-int adb_lseek(int fd, int pos, int where) {
+int64_t adb_lseek(int fd, int64_t pos, int where) {
FH f = _fh_from_int(fd, __func__);
-
if (!f) {
errno = EBADF;
return -1;
}
-
return f->clazz->_fh_lseek(f, pos, where);
}
@@ -644,7 +638,7 @@
return 0;
}
-static int _fh_socket_lseek(FH f, int pos, int origin) {
+static int64_t _fh_socket_lseek(FH f, int64_t pos, int origin) {
errno = EPIPE;
return -1;
}
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/base/Android.bp b/base/Android.bp
index 3d80d97..daa820a 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -56,6 +56,7 @@
"test_utils.cpp",
],
+ cppflags: ["-Wexit-time-destructors"],
shared_libs: ["liblog"],
target: {
android: {
@@ -68,13 +69,11 @@
srcs: [
"errors_unix.cpp",
],
- cppflags: ["-Wexit-time-destructors"],
},
darwin: {
srcs: [
"errors_unix.cpp",
],
- cppflags: ["-Wexit-time-destructors"],
},
linux_bionic: {
enabled: true,
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index c17e00f..6700b6c 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -236,7 +236,7 @@
{"reboot,rescueparty", 90},
{"charge", 91},
{"oem_tz_crash", 92},
- {"uvlo", 93},
+ {"uvlo", 93}, // aliasReasons converts to reboot,undervoltage
{"oem_ps_hold", 94},
{"abnormal_reset", 95},
{"oemerr_unknown", 96},
@@ -248,9 +248,9 @@
{"watchdog_nonsec", 102},
{"watchdog_apps_bark", 103},
{"reboot_dmverity_corrupted", 104},
- {"reboot_smpl", 105},
+ {"reboot_smpl", 105}, // aliasReasons converts to reboot,powerloss
{"watchdog_sdi_apps_reset", 106},
- {"smpl", 107},
+ {"smpl", 107}, // aliasReasons converts to reboot,powerloss
{"oem_modem_failed_to_powerup", 108},
{"reboot_normal", 109},
{"oem_lpass_cfg", 110},
@@ -262,8 +262,8 @@
{"oem_rpm_undef_error", 116},
{"oem_crash_on_the_lk", 117},
{"oem_rpm_reset", 118},
- {"REUSE1", 119}, // Former dupe, can be re-used
- {"REUSE2", 120}, // Former dupe, can be re-used
+ {"reboot,powerloss", 119},
+ {"reboot,undervoltage", 120},
{"factory_cable", 121},
{"oem_ar6320_failed_to_powerup", 122},
{"watchdog_rpm_bite", 123},
@@ -840,6 +840,8 @@
{"reboot,tool", "tool_by_pass_pwk"},
{"!reboot,longkey", "reboot_longkey"},
{"!reboot,longkey", "kpdpwr"},
+ {"!reboot,undervoltage", "uvlo"},
+ {"!reboot,powerloss", "smpl"},
{"bootloader", ""},
};
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/Android.bp b/fastboot/Android.bp
index 6b175af..50d18ed 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -122,6 +122,7 @@
shared_libs: [
"android.hardware.boot@1.0",
"android.hardware.fastboot@1.0",
+ "android.hardware.health@2.0",
"libadbd",
"libasyncio",
"libbase",
@@ -139,6 +140,10 @@
"libutils",
],
+ static_libs: [
+ "libhealthhalutils",
+ ],
+
cpp_std: "c++17",
}
@@ -202,7 +207,6 @@
cpp_std: "c++17",
srcs: [
"bootimg_utils.cpp",
- "engine.cpp",
"fastboot.cpp",
"fs.cpp",
"socket.cpp",
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..2eaf006 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"
@@ -59,3 +60,6 @@
#define FB_VAR_IS_LOGICAL "is-logical"
#define FB_VAR_IS_USERSPACE "is-userspace"
#define FB_VAR_HW_REVISION "hw-revision"
+#define FB_VAR_VARIANT "variant"
+#define FB_VAR_OFF_MODE_CHARGE_STATE "off-mode-charge"
+#define FB_VAR_BATTERY_VOLTAGE "battery-voltage"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 0ec0994..b02d968 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 {
@@ -79,6 +82,7 @@
{FB_VAR_VERSION_BASEBAND, {GetBasebandVersion, nullptr}},
{FB_VAR_PRODUCT, {GetProduct, nullptr}},
{FB_VAR_SERIALNO, {GetSerial, nullptr}},
+ {FB_VAR_VARIANT, {GetVariant, nullptr}},
{FB_VAR_SECURE, {GetSecure, nullptr}},
{FB_VAR_UNLOCKED, {GetUnlocked, nullptr}},
{FB_VAR_MAX_DOWNLOAD_SIZE, {GetMaxDownloadSize, nullptr}},
@@ -91,6 +95,8 @@
{FB_VAR_PARTITION_TYPE, {GetPartitionType, GetAllPartitionArgsWithSlot}},
{FB_VAR_IS_LOGICAL, {GetPartitionIsLogical, GetAllPartitionArgsWithSlot}},
{FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}},
+ {FB_VAR_OFF_MODE_CHARGE_STATE, {GetOffModeChargeState, nullptr}},
+ {FB_VAR_BATTERY_VOLTAGE, {GetBatteryVoltage, nullptr}},
{FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}}};
if (args.size() < 2) {
@@ -133,6 +139,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 +183,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 +334,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 +378,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 +398,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 +430,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..b843c05 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -20,6 +20,8 @@
#include <android-base/strings.h>
#include <android/hardware/boot/1.0/IBootControl.h>
#include <android/hardware/fastboot/1.0/IFastboot.h>
+#include <healthhalutils/HealthHalUtils.h>
+
#include <algorithm>
#include "constants.h"
@@ -30,6 +32,8 @@
using ::android::hardware::boot::V1_0::IBootControl;
using ::android::hardware::boot::V1_0::Slot;
using ::android::hardware::fastboot::V1_0::IFastboot;
+using ::android::hardware::health::V2_0::get_health_service;
+
namespace sph = std::placeholders;
FastbootDevice::FastbootDevice()
@@ -48,9 +52,11 @@
{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()),
+ health_hal_(get_health_service()),
fastboot_hal_(IFastboot::getService()) {}
FastbootDevice::~FastbootDevice() {
@@ -120,10 +126,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/fastboot_device.h b/fastboot/device/fastboot_device.h
index 189cf80..2eb7177 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -24,6 +24,7 @@
#include <android/hardware/boot/1.0/IBootControl.h>
#include <android/hardware/fastboot/1.0/IFastboot.h>
+#include <android/hardware/health/2.0/IHealth.h>
#include "commands.h"
#include "transport.h"
@@ -53,12 +54,14 @@
android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal() {
return fastboot_hal_;
}
+ android::sp<android::hardware::health::V2_0::IHealth> health_hal() { return health_hal_; }
private:
const std::unordered_map<std::string, CommandHandler> kCommandMap;
std::unique_ptr<Transport> transport_;
android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal_;
+ android::sp<android::hardware::health::V2_0::IHealth> health_hal_;
android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal_;
std::vector<char> download_data_;
};
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..01415d7 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -24,6 +24,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <ext4_utils/ext4_utils.h>
+#include <healthhalutils/HealthHalUtils.h>
#include "fastboot_device.h"
#include "flashing.h"
@@ -74,6 +75,73 @@
return true;
}
+bool GetVariant(FastbootDevice* device, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ auto fastboot_hal = device->fastboot_hal();
+ if (!fastboot_hal) {
+ *message = "Fastboot HAL not found";
+ return false;
+ }
+
+ Result ret;
+ auto ret_val = fastboot_hal->getVariant([&](std::string device_variant, Result result) {
+ *message = device_variant;
+ ret = result;
+ });
+ if (!ret_val.isOk() || ret.status != Status::SUCCESS) {
+ *message = "Unable to get device variant";
+ return false;
+ }
+
+ return true;
+}
+
+bool GetOffModeChargeState(FastbootDevice* device, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ auto fastboot_hal = device->fastboot_hal();
+ if (!fastboot_hal) {
+ *message = "Fastboot HAL not found";
+ return false;
+ }
+
+ Result ret;
+ auto ret_val =
+ fastboot_hal->getOffModeChargeState([&](bool off_mode_charging_state, Result result) {
+ *message = off_mode_charging_state ? "1" : "0";
+ ret = result;
+ });
+ if (!ret_val.isOk() || (ret.status != Status::SUCCESS)) {
+ *message = "Unable to get off mode charge state";
+ return false;
+ }
+
+ return true;
+}
+
+bool GetBatteryVoltage(FastbootDevice* device, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ using android::hardware::health::V2_0::HealthInfo;
+ using android::hardware::health::V2_0::Result;
+
+ auto health_hal = device->health_hal();
+ if (!health_hal) {
+ *message = "Health HAL not found";
+ return false;
+ }
+
+ Result ret;
+ auto ret_val = health_hal->getHealthInfo([&](Result result, HealthInfo info) {
+ *message = std::to_string(info.legacy.batteryVoltage);
+ ret = result;
+ });
+ if (!ret_val.isOk() || (ret != Result::SUCCESS)) {
+ *message = "Unable to get battery voltage";
+ return false;
+ }
+
+ return true;
+}
+
bool GetCurrentSlot(FastbootDevice* device, const std::vector<std::string>& /* args */,
std::string* message) {
std::string suffix = device->GetCurrentSlot();
@@ -148,7 +216,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/device/variables.h b/fastboot/device/variables.h
index 63f2670..e7c3c7c 100644
--- a/fastboot/device/variables.h
+++ b/fastboot/device/variables.h
@@ -52,7 +52,11 @@
std::string* message);
bool GetHardwareRevision(FastbootDevice* device, const std::vector<std::string>& args,
std::string* message);
-
+bool GetVariant(FastbootDevice* device, const std::vector<std::string>& args, std::string* message);
+bool GetOffModeChargeState(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
+bool GetBatteryVoltage(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
// Helpers for getvar all.
std::vector<std::vector<std::string>> GetAllPartitionArgsWithSlot(FastbootDevice* device);
std::vector<std::vector<std::string>> GetAllPartitionArgsNoSlot(FastbootDevice* device);
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
deleted file mode 100644
index 0ac57af..0000000
--- a/fastboot/engine.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include "engine.h"
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <vector>
-
-#include <android-base/stringprintf.h>
-
-#include "constants.h"
-#include "transport.h"
-
-using android::base::StringPrintf;
-
-static fastboot::FastBootDriver* fb = nullptr;
-
-void fb_init(fastboot::FastBootDriver& fbi) {
- fb = &fbi;
- auto cb = [](std::string& info) { fprintf(stderr, "(bootloader) %s\n", info.c_str()); };
- fb->SetInfoCallback(cb);
-}
-
-void fb_reinit(Transport* transport) {
- if (Transport* old_transport = fb->set_transport(transport)) {
- delete old_transport;
- }
-}
-
-const std::string fb_get_error() {
- return fb->Error();
-}
-
-bool fb_getvar(const std::string& key, std::string* value) {
- return !fb->GetVar(key, value);
-}
-
-static void HandleResult(double start, int status) {
- if (status) {
- fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
- die("Command failed");
- } else {
- double split = now();
- fprintf(stderr, "OKAY [%7.3fs]\n", (split - start));
- }
-}
-
-#define RUN_COMMAND(command) \
- { \
- double start = now(); \
- auto status = (command); \
- HandleResult(start, status); \
- }
-
-void fb_set_active(const std::string& slot) {
- Status("Setting current slot to '" + slot + "'");
- RUN_COMMAND(fb->SetActive(slot));
-}
-
-void fb_erase(const std::string& partition) {
- Status("Erasing '" + partition + "'");
- RUN_COMMAND(fb->Erase(partition));
-}
-
-void fb_flash_fd(const std::string& partition, int fd, uint32_t sz) {
- Status(StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024));
- RUN_COMMAND(fb->Download(fd, sz));
-
- Status("Writing '" + partition + "'");
- 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));
-
- Status("Writing '" + partition + "'");
- RUN_COMMAND(fb->Flash(partition));
-}
-
-void fb_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
- size_t current, size_t total) {
- Status(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
- sz / 1024));
- RUN_COMMAND(fb->Download(s));
-
- Status(StringPrintf("Writing sparse '%s' %zu/%zu", partition.c_str(), current, total));
- RUN_COMMAND(fb->Flash(partition));
-}
-
-void fb_create_partition(const std::string& partition, const std::string& size) {
- Status("Creating '" + partition + "'");
- RUN_COMMAND(fb->RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size));
-}
-
-void fb_delete_partition(const std::string& partition) {
- Status("Deleting '" + partition + "'");
- RUN_COMMAND(fb->RawCommand(FB_CMD_DELETE_PARTITION ":" + partition));
-}
-
-void fb_resize_partition(const std::string& partition, const std::string& size) {
- Status("Resizing '" + partition + "'");
- 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);
-
- if (status) {
- fprintf(stderr, "getvar:%s FAILED (%s)\n", var.c_str(), fb->Error().c_str());
- return;
- }
- 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();
- fprintf(stderr, "\n");
-}
-
-void fb_command(const std::string& cmd, const std::string& msg) {
- Status(msg);
- RUN_COMMAND(fb->RawCommand(cmd));
-}
-
-void fb_download(const std::string& name, void* data, uint32_t size) {
- Status("Downloading '" + name + "'");
- RUN_COMMAND(fb->Download(static_cast<char*>(data), size));
-}
-
-void fb_download_fd(const std::string& name, int fd, uint32_t sz) {
- Status(StringPrintf("Sending '%s' (%u KB)", name.c_str(), sz / 1024));
- RUN_COMMAND(fb->Download(fd, sz));
-}
-
-void fb_upload(const std::string& outfile) {
- Status("Uploading '" + outfile + "'");
- RUN_COMMAND(fb->Upload(outfile));
-}
-
-void fb_notice(const std::string& notice) {
- Status(notice);
- fprintf(stderr, "\n");
-}
-
-void fb_wait_for_disconnect() {
- fb->WaitForDisconnect();
-}
-
-bool fb_reboot_to_userspace() {
- Status("Rebooting to userspace fastboot");
- verbose("\n");
-
- if (fb->RebootTo("fastboot") != fastboot::RetCode::SUCCESS) {
- fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
- return false;
- }
- fprintf(stderr, "OKAY\n");
-
- fb_reinit(nullptr);
- return true;
-}
diff --git a/fastboot/engine.h b/fastboot/engine.h
deleted file mode 100644
index d78cb13..0000000
--- a/fastboot/engine.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <inttypes.h>
-#include <stdlib.h>
-
-#include <string>
-
-#include <bootimg.h>
-#include "fastboot_driver.h"
-#include "util.h"
-
-#include "constants.h"
-
-class Transport;
-struct sparse_file;
-
-const std::string fb_get_error();
-
-void fb_init(fastboot::FastBootDriver& fbi);
-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_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_fd(const std::string& name, int fd, uint32_t sz);
-void fb_upload(const std::string& outfile);
-void fb_notice(const std::string& notice);
-void fb_wait_for_disconnect(void);
-void fb_create_partition(const std::string& partition, const std::string& size);
-void fb_delete_partition(const std::string& partition);
-void fb_resize_partition(const std::string& partition, const std::string& size);
-void fb_set_active(const std::string& slot);
-bool fb_reboot_to_userspace();
-
-/* Current product */
-extern char cur_product[FB_RESPONSE_SZ + 1];
-
-class FastBootTool {
- public:
- int Main(int argc, char* argv[]);
-
- void ParseOsPatchLevel(boot_img_hdr_v1*, const char*);
- void ParseOsVersion(boot_img_hdr_v1*, const char*);
-};
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 8e6c125..5962650 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
+#include "fastboot.h"
+
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -43,6 +45,7 @@
#include <chrono>
#include <functional>
+#include <regex>
#include <thread>
#include <utility>
#include <vector>
@@ -62,21 +65,23 @@
#include "bootimg_utils.h"
#include "diagnose_usb.h"
-#include "engine.h"
+#include "fastboot_driver.h"
#include "fs.h"
#include "tcp.h"
#include "transport.h"
#include "udp.h"
#include "usb.h"
+#include "util.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;
@@ -96,6 +101,8 @@
static const std::string convert_fbe_marker_filename("convert_fbe");
+fastboot::FastBootDriver* fb = nullptr;
+
enum fb_buffer_type {
FB_BUFFER_FD,
FB_BUFFER_SPARSE,
@@ -177,40 +184,46 @@
return "";
}
+double last_start_time;
+
+static void Status(const std::string& message) {
+ static constexpr char kStatusFormat[] = "%-50s ";
+ fprintf(stderr, kStatusFormat, message.c_str());
+ last_start_time = now();
+}
+
+static void Epilog(int status) {
+ if (status) {
+ fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
+ die("Command failed");
+ } else {
+ double split = now();
+ fprintf(stderr, "OKAY [%7.3fs]\n", (split - last_start_time));
+ }
+}
+
+static void InfoMessage(const std::string& info) {
+ fprintf(stderr, "(bootloader) %s\n", info.c_str());
+}
+
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 +431,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,119 +616,168 @@
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) != fastboot::SUCCESS) {
+ fprintf(stderr, "FAILED\n\n");
+ fprintf(stderr, "Could not getvar for '%s' (%s)\n\n", var.c_str(),
+ fb->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 = match_results[2];
+ // Work around an unfortunate name mismatch.
+ if (*name == "board") {
+ *name = "product";
+ }
- name = strip(name);
+ auto raw_options = Split(match_results[3], "|");
+ for (const auto& option : raw_options) {
+ auto trimmed_option = Trim(option);
+ options->emplace_back(trimmed_option);
+ }
- // "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);
+ return true;
+}
+
+// "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) != fastboot::SUCCESS ||
+ (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;
}
- 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.c_str());
+ }
+}
+
+static void CheckRequirements(const std::string& data) {
+ std::string cur_product;
+ if (fb->GetVar("product", &cur_product) != fastboot::SUCCESS) {
+ fprintf(stderr, "getvar:product FAILED (%s)\n", fb->Error().c_str());
+ }
+
+ auto lines = Split(data, "\n");
+ for (const auto& line : lines) {
+ if (line.empty()) {
+ continue;
}
- if (!known_partition) {
- die("device requires partition %s which is not known to this version of fastboot",
- partition_name);
+
+ 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 {
+ CheckRequirement(cur_product, name, product, invert, options);
+ }
+ }
+}
+
+static void DisplayVarOrError(const std::string& label, const std::string& var) {
+ std::string value;
+
+ if (fb->GetVar(var, &value) != fastboot::SUCCESS) {
+ Status("getvar:" + var);
+ fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
return;
}
-
- for(count = 1; count < MAX_OPTIONS; count++) {
- x = strchr(val[count - 1],'|');
- if (x == 0) break;
- *x = 0;
- val[count] = x + 1;
- }
-
- // 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]));
- }
-
- fb_require(product, var, invert, count, out);
+ fprintf(stderr, "%s: %s\n", label.c_str(), value.c_str());
}
-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;
- } else {
- s++;
- }
- }
-}
+static void DumpInfo() {
+ fprintf(stderr, "--------------------------------------------\n");
+ DisplayVarOrError("Bootloader Version...", "version-bootloader");
+ DisplayVarOrError("Baseband Version.....", "version-baseband");
+ DisplayVarOrError("Serial Number........", "serialno");
+ fprintf(stderr, "--------------------------------------------\n");
-static void dump_info() {
- fb_notice("--------------------------------------------");
- fb_display("Bootloader Version...", "version-bootloader");
- fb_display("Baseband Version.....", "version-baseband");
- fb_display("Serial Number........", "serialno");
- fb_notice("--------------------------------------------");
}
static struct sparse_file** load_sparse_files(int fd, int64_t max_size) {
@@ -739,7 +802,7 @@
static int64_t get_target_sparse_limit() {
std::string max_download_size;
- if (!fb_getvar("max-download-size", &max_download_size) ||
+ if (fb->GetVar("max-download-size", &max_download_size) != fastboot::SUCCESS ||
max_download_size.empty()) {
verbose("target didn't report max-download-size");
return 0;
@@ -887,12 +950,12 @@
for (size_t i = 0; i < sparse_files.size(); ++i) {
const auto& pair = sparse_files[i];
- fb_flash_sparse(partition, pair.first, pair.second, i + 1, sparse_files.size());
+ fb->FlashPartition(partition, pair.first, pair.second, i + 1, sparse_files.size());
}
break;
}
case FB_BUFFER_FD:
- fb_flash_fd(partition, buf->fd, buf->sz);
+ fb->FlashPartition(partition, buf->fd, buf->sz);
break;
default:
die("unknown buffer type: %d", buf->type);
@@ -901,14 +964,15 @@
static std::string get_current_slot() {
std::string current_slot;
- if (!fb_getvar("current-slot", ¤t_slot)) return "";
+ if (fb->GetVar("current-slot", ¤t_slot) != fastboot::SUCCESS) return "";
return current_slot;
}
static int get_slot_count() {
std::string var;
int count = 0;
- if (!fb_getvar("slot-count", &var) || !android::base::ParseInt(var, &count)) {
+ if (fb->GetVar("slot-count", &var) != fastboot::SUCCESS ||
+ !android::base::ParseInt(var, &count)) {
return 0;
}
return count;
@@ -983,7 +1047,7 @@
std::string has_slot;
std::string current_slot;
- if (!fb_getvar("has-slot:" + part, &has_slot)) {
+ if (fb->GetVar("has-slot:" + part, &has_slot) != fastboot::SUCCESS) {
/* If has-slot is not supported, the answer is no. */
has_slot = "no";
}
@@ -1016,7 +1080,7 @@
std::string has_slot;
if (slot == "all") {
- if (!fb_getvar("has-slot:" + part, &has_slot)) {
+ if (fb->GetVar("has-slot:" + part, &has_slot) != fastboot::SUCCESS) {
die("Could not check if partition %s has slot %s", part.c_str(), slot.c_str());
}
if (has_slot == "yes") {
@@ -1046,25 +1110,25 @@
if (!supports_AB()) return;
if (slot_override != "") {
- fb_set_active(slot_override);
+ fb->SetActive(slot_override);
} else {
std::string current_slot = get_current_slot();
if (current_slot != "") {
- fb_set_active(current_slot);
+ fb->SetActive(current_slot);
}
}
}
static bool is_userspace_fastboot() {
std::string value;
- return fb_getvar("is-userspace", &value) && value == "yes";
+ return fb->GetVar("is-userspace", &value) == fastboot::SUCCESS && value == "yes";
}
static bool if_partition_exists(const std::string& partition, const std::string& slot) {
std::string has_slot;
std::string partition_name = partition;
- if (fb_getvar("has-slot:" + partition, &has_slot) && has_slot == "yes") {
+ if (fb->GetVar("has-slot:" + partition, &has_slot) == fastboot::SUCCESS && has_slot == "yes") {
if (slot == "") {
std::string current_slot = get_current_slot();
if (current_slot == "") {
@@ -1076,28 +1140,29 @@
}
}
std::string partition_size;
- return fb_getvar("partition-size:" + partition_name, &partition_size);
+ return fb->GetVar("partition-size:" + partition_name, &partition_size) == fastboot::SUCCESS;
}
static bool is_logical(const std::string& partition) {
std::string value;
- return fb_getvar("is-logical:" + partition, &value) && value == "yes";
+ return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
}
static void reboot_to_userspace_fastboot() {
- if (!fb_reboot_to_userspace()) {
- die("Must reboot to userspace fastboot to flash logical partitions");
- }
+ fb->RebootTo("fastboot");
+
+ auto* old_transport = fb->set_transport(nullptr);
+ delete old_transport;
// Give the current connection time to close.
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
- fb_reinit(open_device());
+ fb->set_transport(open_device());
}
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;
};
@@ -1133,6 +1198,7 @@
}
void FlashAllTool::Flash() {
+ DumpInfo();
CheckRequirements();
DetermineSecondarySlot();
CollectImages();
@@ -1149,7 +1215,7 @@
for (const auto& [image, slot] : os_images_) {
auto resize_partition = [](const std::string& partition) -> void {
if (is_logical(partition)) {
- fb_resize_partition(partition, "0");
+ fb->ResizePartition(partition, "0");
}
};
do_for_partitions(image->part_name, slot, resize_partition, false);
@@ -1166,12 +1232,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,15 +1289,14 @@
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);
- fb_command("signature", "installing signature");
+ std::vector<char> signature_data;
+ if (source_.ReadFile(image.sig_name, &signature_data)) {
+ fb->Download("signature", signature_data);
+ fb->RawCommand("signature", "installing signature");
}
if (is_logical(partition_name)) {
- fb_resize_partition(partition_name, std::to_string(buf->image_size));
+ fb->ResizePartition(partition_name, std::to_string(buf->image_size));
}
flash_buf(partition_name.c_str(), buf);
};
@@ -1251,27 +1315,27 @@
if (!is_userspace_fastboot()) {
reboot_to_userspace_fastboot();
}
- fb_download_fd("super", fd, get_file_size(fd));
+ fb->Download("super", fd, get_file_size(fd));
std::string command = "update-super:super";
if (wipe_) {
command += ":wipe";
}
- fb_command(command, "Updating super partition");
+ fb->RawCommand(command, "Updating super partition");
}
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 {
@@ -1279,10 +1343,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 +1357,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 {
@@ -1315,11 +1375,6 @@
}
static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
- std::string fname;
- dump_info();
-
- fb_query_save("product", cur_product, sizeof(cur_product));
-
FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe);
tool.Flash();
}
@@ -1338,7 +1393,7 @@
while (!args->empty()) {
command += " " + next_arg(args);
}
- fb_command(command, "");
+ fb->RawCommand(command, "");
}
static std::string fb_fix_numeric_var(std::string var) {
@@ -1352,7 +1407,7 @@
static unsigned fb_get_flash_block_size(std::string name) {
std::string sizeString;
- if (!fb_getvar(name, &sizeString) || sizeString.empty()) {
+ if (fb->GetVar(name, &sizeString) != fastboot::SUCCESS || sizeString.empty()) {
// This device does not report flash block sizes, so return 0.
return 0;
}
@@ -1390,7 +1445,7 @@
limit = sparse_limit;
}
- if (!fb_getvar("partition-type:" + partition, &partition_type)) {
+ if (fb->GetVar("partition-type:" + partition, &partition_type) != fastboot::SUCCESS) {
errMsg = "Can't determine partition type.\n";
goto failed;
}
@@ -1402,7 +1457,7 @@
partition_type = type_override;
}
- if (!fb_getvar("partition-size:" + partition, &partition_size)) {
+ if (fb->GetVar("partition-size:" + partition, &partition_size) != fastboot::SUCCESS) {
errMsg = "Unable to get partition size\n";
goto failed;
}
@@ -1460,7 +1515,7 @@
fprintf(stderr, "Erase successful, but not automatically formatting.\n");
if (errMsg) fprintf(stderr, "%s", errMsg);
}
- fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str());
+ fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
}
int FastBootTool::Main(int argc, char* argv[]) {
@@ -1473,8 +1528,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;
@@ -1612,8 +1665,13 @@
if (transport == nullptr) {
return 1;
}
- fastboot::FastBootDriver fb(transport);
- fb_init(fb);
+ fastboot::DriverCallbacks driver_callbacks = {
+ .prolog = Status,
+ .epilog = Epilog,
+ .info = InfoMessage,
+ };
+ fastboot::FastBootDriver fastboot_driver(transport, driver_callbacks, false);
+ fb = &fastboot_driver;
const double start = now();
@@ -1624,7 +1682,7 @@
if (next_active == "") {
if (slot_override == "") {
std::string current_slot;
- if (fb_getvar("current-slot", ¤t_slot)) {
+ if (fb->GetVar("current-slot", ¤t_slot) == fastboot::SUCCESS) {
next_active = verify_slot(current_slot, false);
} else {
wants_set_active = false;
@@ -1641,19 +1699,18 @@
if (command == "getvar") {
std::string variable = next_arg(&args);
- fb_display(variable, variable);
+ DisplayVarOrError(variable, variable);
} else if (command == "erase") {
std::string partition = next_arg(&args);
auto erase = [&](const std::string& partition) {
std::string partition_type;
- if (fb_getvar(std::string("partition-type:") + partition,
- &partition_type) &&
+ if (fb->GetVar("partition-type:" + partition, &partition_type) == fastboot::SUCCESS &&
fs_get_generator(partition_type) != nullptr) {
fprintf(stderr, "******** Did you mean to fastboot format this %s partition?\n",
partition_type.c_str());
}
- fb_erase(partition);
+ fb->Erase(partition);
};
do_for_partitions(partition, slot_override, erase, true);
} else if (android::base::StartsWith(command, "format")) {
@@ -1678,11 +1735,13 @@
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);
- fb_command("signature", "installing signature");
+ 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->RawCommand("signature", "installing signature");
} else if (command == "reboot") {
wants_reboot = true;
@@ -1710,7 +1769,7 @@
} else if (command == "reboot-fastboot") {
wants_reboot_fastboot = true;
} else if (command == "continue") {
- fb_command("continue", "resuming boot");
+ fb->Continue();
} else if (command == "boot") {
std::string kernel = next_arg(&args);
std::string ramdisk;
@@ -1718,9 +1777,9 @@
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);
- fb_command("boot", "booting");
+ auto data = LoadBootableImage(kernel, ramdisk, second_stage);
+ fb->Download("boot.img", data);
+ fb->Boot();
} else if (command == "flash") {
std::string pname = next_arg(&args);
@@ -1744,9 +1803,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->FlashPartition(partition, data);
};
do_for_partitions(partition, slot_override, flashraw, true);
} else if (command == "flashall") {
@@ -1770,7 +1829,7 @@
wants_reboot = true;
} else if (command == "set_active") {
std::string slot = verify_slot(next_arg(&args), false);
- fb_set_active(slot);
+ fb->SetActive(slot);
} else if (command == "stage") {
std::string filename = next_arg(&args);
@@ -1778,10 +1837,10 @@
if (!load_buf(filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
die("cannot load '%s'", filename.c_str());
}
- fb_download_fd(filename, buf.fd, buf.sz);
+ fb->Download(filename, buf.fd, buf.sz);
} else if (command == "get_staged") {
std::string filename = next_arg(&args);
- fb_upload(filename);
+ fb->Upload(filename);
} else if (command == "oem") {
do_oem_command("oem", &args);
} else if (command == "flashing") {
@@ -1798,14 +1857,14 @@
} else if (command == "create-logical-partition") {
std::string partition = next_arg(&args);
std::string size = next_arg(&args);
- fb_create_partition(partition, size);
+ fb->CreatePartition(partition, size);
} else if (command == "delete-logical-partition") {
std::string partition = next_arg(&args);
- fb_delete_partition(partition);
+ fb->DeletePartition(partition);
} else if (command == "resize-logical-partition") {
std::string partition = next_arg(&args);
std::string size = next_arg(&args);
- fb_resize_partition(partition, size);
+ fb->ResizePartition(partition, size);
} else {
syntax_error("unknown command %s", command.c_str());
}
@@ -1815,9 +1874,11 @@
std::vector<std::string> partitions = { "userdata", "cache", "metadata" };
for (const auto& partition : partitions) {
std::string partition_type;
- if (!fb_getvar(std::string{"partition-type:"} + partition, &partition_type)) continue;
+ if (fb->GetVar("partition-type:" + partition, &partition_type) != fastboot::SUCCESS) {
+ continue;
+ }
if (partition_type.empty()) continue;
- fb_erase(partition);
+ fb->Erase(partition);
if (partition == "userdata" && set_fbe_marker) {
fprintf(stderr, "setting FBE marker on initial userdata...\n");
std::string initial_userdata_dir = create_fbemarker_tmpdir();
@@ -1829,27 +1890,27 @@
}
}
if (wants_set_active) {
- fb_set_active(next_active);
+ fb->SetActive(next_active);
}
if (wants_reboot && !skip_reboot) {
- fb_reboot();
- fb_wait_for_disconnect();
+ fb->Reboot();
+ fb->WaitForDisconnect();
} else if (wants_reboot_bootloader) {
- fb_command("reboot-bootloader", "rebooting into bootloader");
- fb_wait_for_disconnect();
+ fb->RebootTo("bootloader");
+ fb->WaitForDisconnect();
} else if (wants_reboot_recovery) {
- fb_command("reboot-recovery", "rebooting into recovery");
- fb_wait_for_disconnect();
+ fb->RebootTo("recovery");
+ fb->WaitForDisconnect();
} else if (wants_reboot_fastboot) {
- fb_command("reboot-fastboot", "rebooting into fastboot");
- fb_wait_for_disconnect();
+ fb->RebootTo("fastboot");
+ fb->WaitForDisconnect();
}
fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
- if (Transport* old_transport = fb.set_transport(nullptr)) {
- delete old_transport;
- }
+ auto* old_transport = fb->set_transport(nullptr);
+ delete old_transport;
+
return 0;
}
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
new file mode 100644
index 0000000..9f18253
--- /dev/null
+++ b/fastboot/fastboot.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <bootimg.h>
+
+class FastBootTool {
+ public:
+ int Main(int argc, char* argv[]);
+
+ void ParseOsPatchLevel(boot_img_hdr_v1*, const char*);
+ void ParseOsVersion(boot_img_hdr_v1*, const char*);
+};
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index 4a14131..b1f3bc9 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#include "fastboot_driver.h"
#include <errno.h>
@@ -44,43 +45,56 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <utils/FileMap.h>
-#include "fastboot_driver.h"
+
+#include "constants.h"
#include "transport.h"
+using android::base::StringPrintf;
+
namespace fastboot {
/*************************** PUBLIC *******************************/
-FastBootDriver::FastBootDriver(Transport* transport, std::function<void(std::string&)> info,
+FastBootDriver::FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks,
bool no_checks)
- : transport_(transport) {
- info_cb_ = info;
- disable_checks_ = no_checks;
-}
+ : transport_(transport),
+ prolog_(std::move(driver_callbacks.prolog)),
+ epilog_(std::move(driver_callbacks.epilog)),
+ info_(std::move(driver_callbacks.info)),
+ disable_checks_(no_checks) {}
FastBootDriver::~FastBootDriver() {
}
RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
- return RawCommand(Commands::BOOT, response, info);
+ return RawCommand(FB_CMD_BOOT, "Booting", response, info);
}
RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
- return RawCommand(Commands::CONTINUE, response, info);
+ return RawCommand(FB_CMD_CONTINUE, "Resuming boot", response, info);
}
-RetCode FastBootDriver::Erase(const std::string& part, std::string* response,
- std::vector<std::string>* info) {
- return RawCommand(Commands::ERASE + part, response, info);
+RetCode FastBootDriver::CreatePartition(const std::string& partition, const std::string& size) {
+ return RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size,
+ "Creating '" + partition + "'");
}
-RetCode FastBootDriver::Flash(const std::string& part, std::string* response,
+RetCode FastBootDriver::DeletePartition(const std::string& partition) {
+ return RawCommand(FB_CMD_DELETE_PARTITION ":" + partition, "Deleting '" + partition + "'");
+}
+
+RetCode FastBootDriver::Erase(const std::string& partition, std::string* response,
std::vector<std::string>* info) {
- return RawCommand(Commands::FLASH + part, response, info);
+ return RawCommand(FB_CMD_ERASE ":" + partition, "Erasing '" + partition + "'", response, info);
+}
+
+RetCode FastBootDriver::Flash(const std::string& partition, std::string* response,
+ std::vector<std::string>* info) {
+ return RawCommand(FB_CMD_FLASH ":" + partition, "Writing '" + partition + "'", response, info);
}
RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
std::vector<std::string>* info) {
- return RawCommand(Commands::GET_VAR + key, val, info);
+ return RawCommand(FB_CMD_GETVAR ":" + key, val, info);
}
RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
@@ -89,44 +103,52 @@
}
RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
- return RawCommand(Commands::REBOOT, response, info);
+ return RawCommand(FB_CMD_REBOOT, "Rebooting", response, info);
}
RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
std::vector<std::string>* info) {
- return RawCommand("reboot-" + target, response, info);
+ return RawCommand("reboot-" + target, "Rebooting into " + target, response, info);
+}
+
+RetCode FastBootDriver::ResizePartition(const std::string& partition, const std::string& size) {
+ return RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size,
+ "Resizing '" + partition + "'");
}
RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
std::vector<std::string>* info) {
- return RawCommand(Commands::SET_ACTIVE + slot, response, info);
+ return RawCommand(FB_CMD_SET_ACTIVE ":" + slot, "Setting current slot to '" + slot + "'",
+ response, info);
}
-RetCode FastBootDriver::FlashPartition(const std::string& part, const std::vector<char>& data) {
+RetCode FastBootDriver::FlashPartition(const std::string& partition,
+ const std::vector<char>& data) {
RetCode ret;
- if ((ret = Download(data))) {
+ if ((ret = Download(partition, data))) {
return ret;
}
- return RawCommand(Commands::FLASH + part);
+ return Flash(partition);
}
-RetCode FastBootDriver::FlashPartition(const std::string& part, int fd, uint32_t sz) {
+RetCode FastBootDriver::FlashPartition(const std::string& partition, int fd, uint32_t size) {
RetCode ret;
- if ((ret = Download(fd, sz))) {
+ if ((ret = Download(partition, fd, size))) {
return ret;
}
- return RawCommand(Commands::FLASH + part);
+ return Flash(partition);
}
-RetCode FastBootDriver::FlashPartition(const std::string& part, sparse_file* s) {
+RetCode FastBootDriver::FlashPartition(const std::string& partition, sparse_file* s, uint32_t size,
+ size_t current, size_t total) {
RetCode ret;
- if ((ret = Download(s))) {
+ if ((ret = Download(partition, s, size, current, total, false))) {
return ret;
}
- return RawCommand(Commands::FLASH + part);
+ return Flash(partition);
}
-RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* parts) {
+RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions) {
std::vector<std::string> all;
RetCode ret;
if ((ret = GetVarAll(&all))) {
@@ -141,32 +163,18 @@
std::string m1(sm[1]);
std::string m2(sm[2]);
uint64_t tmp = strtoll(m2.c_str(), 0, 16);
- parts->push_back(std::make_tuple(m1, tmp));
+ partitions->push_back(std::make_tuple(m1, tmp));
}
}
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(const std::string& name, int fd, size_t size,
+ std::string* response, std::vector<std::string>* info) {
+ prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), size / 1024));
+ auto result = Download(fd, size, response, info);
+ epilog_(result);
+ return result;
}
RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
@@ -192,26 +200,29 @@
return HandleResponse(response, info);
}
-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 std::string& name, const std::vector<char>& buf,
+ std::string* response, std::vector<std::string>* info) {
+ prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), buf.size() / 1024));
+ auto result = Download(buf, response, info);
+ epilog_(result);
+ return result;
}
-RetCode FastBootDriver::Download(const char* buf, uint32_t size, std::string* response,
+RetCode FastBootDriver::Download(const std::vector<char>& buf, 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;
}
@@ -219,6 +230,16 @@
return HandleResponse(response, info);
}
+RetCode FastBootDriver::Download(const std::string& partition, struct sparse_file* s, uint32_t size,
+ size_t current, size_t total, bool use_crc, std::string* response,
+ std::vector<std::string>* info) {
+ prolog_(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
+ size / 1024));
+ auto result = Download(s, use_crc, response, info);
+ epilog_(result);
+ return result;
+}
+
RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
std::vector<std::string>* info) {
error_ = "";
@@ -261,9 +282,17 @@
RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
std::vector<std::string>* info) {
+ prolog_("Uploading '" + outfile + "'");
+ auto result = UploadInner(outfile, response, info);
+ epilog_(result);
+ return result;
+}
+
+RetCode FastBootDriver::UploadInner(const std::string& outfile, std::string* response,
+ std::vector<std::string>* info) {
RetCode ret;
int dsize;
- if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize))) {
+ if ((ret = RawCommand(FB_CMD_UPLOAD, response, info, &dsize))) {
error_ = "Upload request failed: " + error_;
return ret;
}
@@ -297,8 +326,8 @@
}
// Helpers
-void FastBootDriver::SetInfoCallback(std::function<void(std::string&)> info) {
- info_cb_ = info;
+void FastBootDriver::SetInfoCallback(std::function<void(const std::string&)> info) {
+ info_ = info;
}
const std::string FastBootDriver::RCString(RetCode rc) {
@@ -335,6 +364,15 @@
}
/****************************** PROTECTED *************************************/
+RetCode FastBootDriver::RawCommand(const std::string& cmd, const std::string& message,
+ std::string* response, std::vector<std::string>* info,
+ int* dsize) {
+ prolog_(message);
+ auto result = RawCommand(cmd, response, info, dsize);
+ epilog_(result);
+ return result;
+}
+
RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
std::vector<std::string>* info, int* dsize) {
error_ = ""; // Clear any pending error
@@ -354,7 +392,7 @@
RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
std::vector<std::string>* info) {
- std::string cmd(android::base::StringPrintf("%s%08" PRIx32, Commands::DOWNLOAD.c_str(), size));
+ std::string cmd(android::base::StringPrintf("%s:%08" PRIx32, FB_CMD_DOWNLOAD, size));
RetCode ret;
if ((ret = RawCommand(cmd, response, info))) {
return ret;
@@ -387,7 +425,7 @@
std::string input(status);
if (android::base::StartsWith(input, "INFO")) {
std::string tmp = input.substr(strlen("INFO"));
- info_cb_(tmp);
+ info_(tmp);
add_info(std::move(tmp));
} else if (android::base::StartsWith(input, "OKAY")) {
set_response(input.substr(strlen("OKAY")));
@@ -420,16 +458,6 @@
return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
}
-const std::string FastBootDriver::Commands::BOOT = "boot";
-const std::string FastBootDriver::Commands::CONTINUE = "continue";
-const std::string FastBootDriver::Commands::DOWNLOAD = "download:";
-const std::string FastBootDriver::Commands::ERASE = "erase:";
-const std::string FastBootDriver::Commands::FLASH = "flash:";
-const std::string FastBootDriver::Commands::GET_VAR = "getvar:";
-const std::string FastBootDriver::Commands::REBOOT = "reboot";
-const std::string FastBootDriver::Commands::SET_ACTIVE = "set_active:";
-const std::string FastBootDriver::Commands::UPLOAD = "upload";
-
/******************************* PRIVATE **************************************/
RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index 4d85ba0..62bbe52 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -55,6 +55,12 @@
TIMEOUT,
};
+struct DriverCallbacks {
+ std::function<void(const std::string&)> prolog = [](const std::string&) {};
+ std::function<void(int)> epilog = [](int) {};
+ std::function<void(const std::string&)> info = [](const std::string&) {};
+};
+
class FastBootDriver {
friend class FastBootTest;
@@ -63,25 +69,30 @@
static constexpr uint32_t MAX_DOWNLOAD_SIZE = std::numeric_limits<uint32_t>::max();
static constexpr size_t TRANSPORT_CHUNK_SIZE = 1024;
- FastBootDriver(Transport* transport,
- std::function<void(std::string&)> info = [](std::string&) {},
+ FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks = {},
bool no_checks = false);
~FastBootDriver();
RetCode Boot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
RetCode Continue(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+ RetCode CreatePartition(const std::string& partition, const std::string& size);
+ RetCode DeletePartition(const std::string& partition);
+ RetCode Download(const std::string& name, int fd, size_t size, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
RetCode Download(int fd, size_t size, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
+ RetCode Download(const std::string& name, const std::vector<char>& buf,
+ std::string* response = nullptr, 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,
+ RetCode Download(const std::string& partition, struct sparse_file* s, uint32_t sz,
+ size_t current, size_t total, bool use_crc, 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,
+ RetCode Erase(const std::string& partition, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
- RetCode Flash(const std::string& part, std::string* response = nullptr,
+ RetCode Flash(const std::string& partition, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode GetVar(const std::string& key, std::string* val,
std::vector<std::string>* info = nullptr);
@@ -89,22 +100,24 @@
RetCode Reboot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
RetCode RebootTo(std::string target, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
+ RetCode ResizePartition(const std::string& partition, const std::string& size);
RetCode SetActive(const std::string& slot, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode Upload(const std::string& outfile, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
/* HIGHER LEVEL COMMANDS -- Composed of the commands above */
- RetCode FlashPartition(const std::string& part, const std::vector<char>& data);
- RetCode FlashPartition(const std::string& part, int fd, uint32_t sz);
- RetCode FlashPartition(const std::string& part, sparse_file* s);
+ RetCode FlashPartition(const std::string& partition, const std::vector<char>& data);
+ RetCode FlashPartition(const std::string& partition, int fd, uint32_t sz);
+ RetCode FlashPartition(const std::string& partition, sparse_file* s, uint32_t sz,
+ size_t current, size_t total);
- RetCode Partitions(std::vector<std::tuple<std::string, uint64_t>>* parts);
+ RetCode Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions);
RetCode Require(const std::string& var, const std::vector<std::string>& allowed, bool* reqmet,
bool invert = false);
/* HELPERS */
- void SetInfoCallback(std::function<void(std::string&)> info);
+ void SetInfoCallback(std::function<void(const std::string&)> info);
static const std::string RCString(RetCode rc);
std::string Error();
RetCode WaitForDisconnect();
@@ -113,7 +126,10 @@
Transport* set_transport(Transport* transport);
Transport* transport() const { return transport_; }
- // This is temporarily public for engine.cpp
+ RetCode RawCommand(const std::string& cmd, const std::string& message,
+ std::string* response = nullptr, std::vector<std::string>* info = nullptr,
+ int* dsize = nullptr);
+
RetCode RawCommand(const std::string& cmd, std::string* response = nullptr,
std::vector<std::string>* info = nullptr, int* dsize = nullptr);
@@ -125,19 +141,6 @@
std::string ErrnoStr(const std::string& msg);
- // More like a namespace...
- struct Commands {
- static const std::string BOOT;
- static const std::string CONTINUE;
- static const std::string DOWNLOAD;
- static const std::string ERASE;
- static const std::string FLASH;
- static const std::string GET_VAR;
- static const std::string REBOOT;
- static const std::string SET_ACTIVE;
- static const std::string UPLOAD;
- };
-
Transport* transport_;
private:
@@ -148,10 +151,15 @@
RetCode ReadBuffer(std::vector<char>& buf);
RetCode ReadBuffer(void* buf, size_t size);
+ RetCode UploadInner(const std::string& outfile, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+
int SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len);
std::string error_;
- std::function<void(std::string&)> info_cb_;
+ std::function<void(const std::string&)> prolog_;
+ std::function<void(int)> epilog_;
+ std::function<void(const std::string&)> info_;
bool disable_checks_;
};
diff --git a/fastboot/fastboot_test.cpp b/fastboot/fastboot_test.cpp
index 43201fa..9c3ab6e 100644
--- a/fastboot/fastboot_test.cpp
+++ b/fastboot/fastboot_test.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "engine.h"
+#include "fastboot.h"
#include <gtest/gtest.h>
@@ -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/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index 4da71ca..c18af1d 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -121,8 +121,7 @@
} else {
ASSERT_EQ(device_path, cb_scratch); // The path can not change
}
- fb = std::unique_ptr<FastBootDriver>(
- new FastBootDriver(transport.get(), [](std::string&) {}, true));
+ fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
}
void FastBootTest::TearDown() {
@@ -204,8 +203,7 @@
putchar('.');
}
device_path = cb_scratch;
- fb = std::unique_ptr<FastBootDriver>(
- new FastBootDriver(transport.get(), [](std::string&) {}, true));
+ fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
if (assert_change) {
ASSERT_EQ(fb->GetVar("unlocked", &resp), SUCCESS) << "getvar:unlocked failed";
ASSERT_EQ(resp, unlock ? "yes" : "no")
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index 8fb5a6a..90a2e74 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -441,9 +441,6 @@
ASSERT_TRUE(*sparse) << "Sparse file creation failed on: " << bs;
EXPECT_EQ(fb->Download(*sparse), SUCCESS) << "Download sparse failed: " << sparse.Rep();
EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
- EXPECT_EQ(fb->Download(*sparse, true), SUCCESS)
- << "Download sparse with crc failed: " << sparse.Rep();
- EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
}
}
@@ -462,9 +459,6 @@
<< "Adding data failed to sparse file: " << sparse.Rep();
EXPECT_EQ(fb->Download(*sparse), SUCCESS) << "Download sparse failed: " << sparse.Rep();
EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
- EXPECT_EQ(fb->Download(*sparse, true), SUCCESS)
- << "Download sparse with crc failed: " << sparse.Rep();
- EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
}
}
@@ -474,9 +468,6 @@
ASSERT_TRUE(*sparse) << "Sparse image creation failed";
EXPECT_EQ(fb->Download(*sparse), SUCCESS) << "Download sparse failed: " << sparse.Rep();
EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
- EXPECT_EQ(fb->Download(*sparse, true), SUCCESS)
- << "Download sparse with crc failed: " << sparse.Rep();
- EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
}
TEST_F(Conformance, SparseDownload1) {
@@ -487,9 +478,6 @@
<< "Adding data failed to sparse file: " << sparse.Rep();
EXPECT_EQ(fb->Download(*sparse), SUCCESS) << "Download sparse failed: " << sparse.Rep();
EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
- EXPECT_EQ(fb->Download(*sparse, true), SUCCESS)
- << "Download sparse with crc failed: " << sparse.Rep();
- EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
}
TEST_F(Conformance, SparseDownload2) {
@@ -503,9 +491,6 @@
<< "Adding data failed to sparse file: " << sparse.Rep();
EXPECT_EQ(fb->Download(*sparse), SUCCESS) << "Download sparse failed: " << sparse.Rep();
EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
- EXPECT_EQ(fb->Download(*sparse, true), SUCCESS)
- << "Download sparse with crc failed: " << sparse.Rep();
- EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
}
TEST_F(Conformance, SparseDownload3) {
@@ -537,9 +522,6 @@
}
EXPECT_EQ(fb->Download(*sparse), SUCCESS) << "Download sparse failed: " << sparse.Rep();
EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
- EXPECT_EQ(fb->Download(*sparse, true), SUCCESS)
- << "Download sparse with crc failed: " << sparse.Rep();
- EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
}
TEST_F(Conformance, SparseVersionCheck) {
@@ -559,24 +541,6 @@
}
}
-TEST_F(Conformance, SparseCRCCheck) {
- SparseWrapper sparse(4096, 4096);
- ASSERT_TRUE(*sparse) << "Sparse image creation failed";
- std::vector<char> buf = RandomBuf(4096);
- ASSERT_EQ(sparse_file_add_data(*sparse, buf.data(), buf.size(), 0), 0)
- << "Adding data failed to sparse file: " << sparse.Rep();
- ASSERT_TRUE(SparseToBuf(*sparse, &buf, true)) << "Sparse buffer creation failed";
- // Flip a bit in the crc
- buf.back() = buf.back() ^ 0x01;
- ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command";
- ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed";
- // It can either reject this download or reject it during flash
- if (HandleResponse() != DEVICE_FAIL) {
- EXPECT_EQ(fb->Flash("userdata"), DEVICE_FAIL)
- << "Flashing an invalid sparse version should fail " << sparse.Rep();
- }
-}
-
TEST_F(UnlockPermissions, Download) {
std::vector<char> buf{'a', 'o', 's', 'p'};
EXPECT_EQ(fb->Download(buf), SUCCESS) << "Download 4-byte payload failed";
diff --git a/fastboot/main.cpp b/fastboot/main.cpp
index c3683f7..35f4218 100644
--- a/fastboot/main.cpp
+++ b/fastboot/main.cpp
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
-#include "engine.h"
+#include "fastboot.h"
int main(int argc, char* argv[]) {
FastBootTool fb;
diff --git a/fastboot/util.cpp b/fastboot/util.cpp
index 125182d..d02b37f 100644
--- a/fastboot/util.cpp
+++ b/fastboot/util.cpp
@@ -69,14 +69,3 @@
}
fprintf(stderr, "\n");
}
-
-void Status(const std::string& message) {
- 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..2535414 100644
--- a/fastboot/util.h
+++ b/fastboot/util.h
@@ -9,11 +9,8 @@
/* util stuff */
double now();
-char* xstrdup(const char*);
void set_verbose();
-void Status(const std::string& message);
-
// These printf-like functions are implemented in terms of vsnprintf, so they
// use the same attribute for compile-time format string checking.
void die(const char* fmt, ...) __attribute__((__noreturn__))
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 38ecc31..208162e 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -529,8 +529,18 @@
errno = 0;
ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
save_errno = errno;
- PINFO << __FUNCTION__ << "(source=" << source << ",target=" << target
- << ",type=" << rec->fs_type << ")=" << ret;
+ const char* target_missing = "";
+ const char* source_missing = "";
+ if (save_errno == ENOENT) {
+ if (access(target, F_OK)) {
+ target_missing = "(missing)";
+ } else if (access(source, F_OK)) {
+ source_missing = "(missing)";
+ }
+ errno = save_errno;
+ }
+ PINFO << __FUNCTION__ << "(source=" << source << source_missing << ",target=" << target
+ << target_missing << ",type=" << rec->fs_type << ")=" << ret;
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
fs_mgr_set_blk_ro(source);
}
@@ -569,8 +579,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 +814,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 +849,70 @@
return true;
}
+bool fs_mgr_update_checkpoint_partition(struct fstab_rec* rec) {
+ if (fs_mgr_is_checkpoint_fs(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 (fs_mgr_is_checkpoint_blk(rec)) {
+ call_vdc({"checkpoint", "restoreCheckpoint", rec->blk_device});
+
+ android::base::unique_fd fd(
+ TEMP_FAILURE_RETRY(open(rec->blk_device, O_RDONLY | O_CLOEXEC)));
+ if (!fd) {
+ PERROR << "Cannot open device " << rec->blk_device;
+ return false;
+ }
+
+ uint64_t size = get_block_device_size(fd) / 512;
+ if (!size) {
+ PERROR << "Cannot get device size";
+ return false;
+ }
+
+ android::dm::DmTable table;
+ if (!table.AddTarget(
+ std::make_unique<android::dm::DmTargetBow>(0, size, rec->blk_device))) {
+ LERROR << "Failed to add Bow target";
+ return false;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ if (!dm.CreateDevice("bow", table)) {
+ PERROR << "Failed to create bow device";
+ return false;
+ }
+
+ std::string name;
+ if (!dm.GetDmDevicePathByName("bow", &name)) {
+ PERROR << "Failed to get bow device name";
+ return false;
+ }
+
+ rec->blk_device = strdup(name.c_str());
+ }
+ 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 +959,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 +1134,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 +1170,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 +1204,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 +1285,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 +1316,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;
@@ -1294,7 +1402,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) {
@@ -1318,7 +1426,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 1585b4c..fc3a05c 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
@@ -1002,3 +1004,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..07b2a7a 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,32 +123,32 @@
!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) {
auto candidate = fs_mgr_get_overlayfs_candidate(mount_point);
if (candidate.empty()) return "";
- 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;
}
bool fs_mgr_system_root_image(const fstab* fstab) {
@@ -192,6 +192,40 @@
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_overlayfs_verity_enabled(const std::string& basename_mount_point) {
+ auto found = false;
+ fs_mgr_update_verity_state(
+ [&basename_mount_point, &found](fstab_rec*, const char* mount_point, int, int) {
+ if (mount_point && (basename_mount_point == mount_point)) found = true;
+ });
+ return found;
+}
+
bool fs_mgr_wants_overlayfs(const fstab_rec* fsrec) {
if (!fsrec) return false;
@@ -215,14 +249,7 @@
if (!fs_mgr_overlayfs_enabled(fsrec)) return false;
- // Verity enabled?
- const auto basename_mount_point(android::base::Basename(fsrec_mount_point));
- auto found = false;
- fs_mgr_update_verity_state(
- [&basename_mount_point, &found](fstab_rec*, const char* mount_point, int, int) {
- if (mount_point && (basename_mount_point == mount_point)) found = true;
- });
- return !found;
+ return !fs_mgr_overlayfs_verity_enabled(android::base::Basename(fsrec_mount_point));
}
bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr) {
@@ -233,7 +260,7 @@
errno = save_errno;
return true;
}
- PERROR << "overlayfs open " << path;
+ PERROR << "opendir " << path;
return false;
}
dirent* entry;
@@ -251,7 +278,7 @@
if (change) *change = true;
} else {
ret = false;
- PERROR << "overlayfs rmdir " << file;
+ PERROR << "rmdir " << file;
}
continue;
}
@@ -259,39 +286,39 @@
if (change) *change = true;
} else {
ret = false;
- PERROR << "overlayfs rm " << file;
+ PERROR << "rm " << file;
}
}
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 << "setfscreatecon " << kOverlayfsFileContext;
}
auto save_errno = errno;
if (!mkdir(fsrec_mount_point.c_str(), 0755)) {
if (change) *change = true;
} else if (errno != EEXIST) {
ret = false;
- PERROR << "overlayfs mkdir " << fsrec_mount_point;
+ PERROR << "mkdir " << fsrec_mount_point;
} else {
errno = save_errno;
}
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 << "mkdir " << fsrec_mount_point << kWorkName;
} else {
errno = save_errno;
}
@@ -300,15 +327,15 @@
auto new_context = fs_mgr_get_context(mount_point);
if (!new_context.empty() && setfscreatecon(new_context.c_str())) {
ret = false;
- PERROR << "overlayfs setfscreatecon " << new_context;
+ PERROR << "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;
} else if (errno != EEXIST) {
ret = false;
- PERROR << "overlayfs mkdir " << upper;
+ PERROR << "mkdir " << upper;
} else {
errno = save_errno;
}
@@ -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;
@@ -393,21 +395,28 @@
}
if (!duplicate_or_more_specific) mounts.emplace_back(new_mount_point);
}
+ // if not itemized /system or /, system as root, fake up
+ // fs_mgr_wants_overlayfs evaluation of /system as candidate.
+
+ if ((std::find(mounts.begin(), mounts.end(), "/system") == mounts.end()) &&
+ !fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/") &&
+ !fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/system") &&
+ !fs_mgr_overlayfs_verity_enabled("system")) {
+ mounts.emplace_back("/system");
+ }
return mounts;
}
} // 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;
}
@@ -426,25 +435,25 @@
if (!fs_mgr_wants_overlayfs()) return ret;
if (!fs_mgr_boot_completed()) {
errno = EBUSY;
- PERROR << "overlayfs setup";
+ PERROR << "setup";
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 << "setfscreatecon " << kOverlayfsFileContext;
}
- auto overlay = kOverlayMountPoint + "/overlay/";
+ auto overlay = kOverlayMountPoint + kOverlayTopDir;
auto save_errno = errno;
if (!mkdir(overlay.c_str(), 0755)) {
if (change) *change = true;
} else if (errno != EEXIST) {
- PERROR << "overlayfs mkdir " << overlay;
+ PERROR << "mkdir " << overlay;
} else {
errno = save_errno;
}
@@ -462,13 +471,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;
@@ -476,7 +485,7 @@
if (change) *change = true;
} else if (errno != ENOENT) {
ret = false;
- PERROR << "overlayfs mv " << oldpath << " " << newpath;
+ PERROR << "mv " << oldpath << " " << newpath;
} else {
errno = save_errno;
}
@@ -486,7 +495,7 @@
if (change) *change = true;
} else if (errno != ENOENT) {
ret = false;
- PERROR << "overlayfs rmdir " << newpath;
+ PERROR << "rmdir " << newpath;
} else {
errno = save_errno;
}
@@ -496,7 +505,7 @@
if (change) *change = true;
} else if ((errno != ENOENT) && (errno != ENOTEMPTY)) {
ret = false;
- PERROR << "overlayfs rmdir " << overlay;
+ PERROR << "rmdir " << overlay;
} else {
errno = save_errno;
}
@@ -511,7 +520,7 @@
// caller that there may still be more to do.
if (!fs_mgr_boot_completed()) {
errno = EBUSY;
- PERROR << "overlayfs teardown";
+ PERROR << "teardown";
ret = false;
}
return ret;
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/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index aab89e5..175b0f0 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -156,6 +156,20 @@
std::string target_string_;
};
+// dm-bow is the backup on write target that can provide checkpoint capability
+// for file systems that do not support checkpoints natively
+class DmTargetBow final : public DmTarget {
+ public:
+ DmTargetBow(uint64_t start, uint64_t length, const std::string& target_string)
+ : DmTarget(start, length), target_string_(target_string) {}
+
+ std::string name() const override { return "bow"; }
+ std::string GetParameterString() const override { return target_string_; }
+
+ private:
+ std::string target_string_;
+};
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 018c280..d9a0e9c 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -79,8 +79,9 @@
out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_ZERO, 0});
}
-Partition::Partition(const std::string& name, const std::string& guid, uint32_t attributes)
- : name_(name), guid_(guid), attributes_(attributes), size_(0) {}
+Partition::Partition(const std::string& name, const std::string& group_name,
+ const std::string& guid, uint32_t attributes)
+ : name_(name), group_name_(group_name), guid_(guid), attributes_(attributes), size_(0) {}
void Partition::AddExtent(std::unique_ptr<Extent>&& extent) {
size_ += extent->num_sectors() * LP_SECTOR_SIZE;
@@ -128,6 +129,17 @@
DCHECK(size_ == aligned_size);
}
+uint64_t Partition::BytesOnDisk() const {
+ uint64_t sectors = 0;
+ for (const auto& extent : extents_) {
+ if (!extent->AsLinearExtent()) {
+ continue;
+ }
+ sectors += extent->num_sectors();
+ }
+ return sectors * LP_SECTOR_SIZE;
+}
+
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device,
uint32_t slot_number) {
std::unique_ptr<LpMetadata> metadata = ReadMetadata(block_device.c_str(), slot_number);
@@ -175,14 +187,23 @@
header_.header_size = sizeof(header_);
header_.partitions.entry_size = sizeof(LpMetadataPartition);
header_.extents.entry_size = sizeof(LpMetadataExtent);
+ header_.groups.entry_size = sizeof(LpMetadataPartitionGroup);
}
bool MetadataBuilder::Init(const LpMetadata& metadata) {
geometry_ = metadata.geometry;
+ for (const auto& group : metadata.groups) {
+ std::string group_name = GetPartitionGroupName(group);
+ if (!AddGroup(group_name, group.maximum_size)) {
+ return false;
+ }
+ }
+
for (const auto& partition : metadata.partitions) {
- Partition* builder = AddPartition(GetPartitionName(partition), GetPartitionGuid(partition),
- partition.attributes);
+ std::string group_name = GetPartitionGroupName(metadata.groups[partition.group_index]);
+ Partition* builder = AddPartition(GetPartitionName(partition), group_name,
+ GetPartitionGuid(partition), partition.attributes);
if (!builder) {
return false;
}
@@ -292,11 +313,29 @@
geometry_.alignment_offset = device_info_.alignment_offset;
geometry_.block_device_size = device_info_.size;
geometry_.logical_block_size = device_info.logical_block_size;
+
+ if (!AddGroup("default", 0)) {
+ return false;
+ }
+ return true;
+}
+
+bool MetadataBuilder::AddGroup(const std::string& group_name, uint64_t maximum_size) {
+ if (FindGroup(group_name)) {
+ LERROR << "Group already exists: " << group_name;
+ return false;
+ }
+ groups_.push_back(std::make_unique<PartitionGroup>(group_name, maximum_size));
return true;
}
Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& guid,
uint32_t attributes) {
+ return AddPartition(name, "default", guid, attributes);
+}
+
+Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& group_name,
+ const std::string& guid, uint32_t attributes) {
if (name.empty()) {
LERROR << "Partition must have a non-empty name.";
return nullptr;
@@ -305,7 +344,11 @@
LERROR << "Attempting to create duplication partition with name: " << name;
return nullptr;
}
- partitions_.push_back(std::make_unique<Partition>(name, guid, attributes));
+ if (!FindGroup(group_name)) {
+ LERROR << "Could not find partition group: " << group_name;
+ return nullptr;
+ }
+ partitions_.push_back(std::make_unique<Partition>(name, group_name, guid, attributes));
return partitions_.back().get();
}
@@ -318,6 +361,26 @@
return nullptr;
}
+PartitionGroup* MetadataBuilder::FindGroup(const std::string& group_name) const {
+ for (const auto& group : groups_) {
+ if (group->name() == group_name) {
+ return group.get();
+ }
+ }
+ return nullptr;
+}
+
+uint64_t MetadataBuilder::TotalSizeOfGroup(PartitionGroup* group) const {
+ uint64_t total = 0;
+ for (const auto& partition : partitions_) {
+ if (partition->group_name() != group->name()) {
+ continue;
+ }
+ total += partition->BytesOnDisk();
+ }
+ return total;
+}
+
void MetadataBuilder::RemovePartition(const std::string& name) {
for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) {
if ((*iter)->name() == name) {
@@ -328,8 +391,23 @@
}
bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size) {
- // Figure out how much we need to allocate.
+ PartitionGroup* group = FindGroup(partition->group_name());
+ CHECK(group);
+
+ // Figure out how much we need to allocate, and whether our group has
+ // enough space remaining.
uint64_t space_needed = aligned_size - partition->size();
+ if (group->maximum_size() > 0) {
+ uint64_t group_size = TotalSizeOfGroup(group);
+ if (group_size >= group->maximum_size() ||
+ group->maximum_size() - group_size < space_needed) {
+ LERROR << "Partition " << partition->name() << " is part of group " << group->name()
+ << " which does not have enough space free (" << space_needed << "requested, "
+ << group_size << " used out of " << group->maximum_size();
+ return false;
+ }
+ }
+
uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed);
@@ -441,6 +519,20 @@
metadata->header = header_;
metadata->geometry = geometry_;
+ std::map<std::string, size_t> group_indices;
+ for (const auto& group : groups_) {
+ LpMetadataPartitionGroup out = {};
+
+ if (group->name().size() > sizeof(out.name)) {
+ LERROR << "Partition group name is too long: " << group->name();
+ return nullptr;
+ }
+ strncpy(out.name, group->name().c_str(), sizeof(out.name));
+ out.maximum_size = group->maximum_size();
+
+ metadata->groups.push_back(out);
+ }
+
// Flatten the partition and extent structures into an LpMetadata, which
// makes it very easy to validate, serialize, or pass on to device-mapper.
for (const auto& partition : partitions_) {
@@ -475,6 +567,7 @@
metadata->header.partitions.num_entries = static_cast<uint32_t>(metadata->partitions.size());
metadata->header.extents.num_entries = static_cast<uint32_t>(metadata->extents.size());
+ metadata->header.groups.num_entries = static_cast<uint32_t>(metadata->groups.size());
return metadata;
}
@@ -482,6 +575,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.
@@ -522,8 +623,10 @@
ShrinkPartition(partition, aligned_size);
}
- LINFO << "Partition " << partition->name() << " will resize from " << old_size << " bytes to "
- << aligned_size << " bytes";
+ if (partition->size() != old_size) {
+ LINFO << "Partition " << partition->name() << " will resize from " << old_size
+ << " bytes to " << aligned_size << " bytes";
+ }
return true;
}
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index da9c8f3..711cc64 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) {
@@ -481,3 +495,28 @@
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 512, 1);
ASSERT_EQ(builder, nullptr);
}
+
+TEST(liblp, HasDefaultGroup) {
+ BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+ ASSERT_NE(builder, nullptr);
+
+ EXPECT_FALSE(builder->AddGroup("default", 0));
+}
+
+TEST(liblp, GroupSizeLimits) {
+ BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+ ASSERT_NE(builder, nullptr);
+
+ ASSERT_TRUE(builder->AddGroup("google", 16384));
+
+ Partition* partition = builder->AddPartition("system", "google", TEST_GUID, 0);
+ ASSERT_NE(partition, nullptr);
+ EXPECT_TRUE(builder->ResizePartition(partition, 8192));
+ EXPECT_EQ(partition->size(), 8192);
+ EXPECT_TRUE(builder->ResizePartition(partition, 16384));
+ EXPECT_EQ(partition->size(), 16384);
+ EXPECT_FALSE(builder->ResizePartition(partition, 32768));
+ EXPECT_EQ(partition->size(), 16384);
+}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 38842a4..f1edee7 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -95,11 +95,25 @@
void AddTo(LpMetadata* out) const override;
};
+class PartitionGroup final {
+ public:
+ explicit PartitionGroup(const std::string& name, uint64_t maximum_size)
+ : name_(name), maximum_size_(maximum_size) {}
+
+ const std::string& name() const { return name_; }
+ uint64_t maximum_size() const { return maximum_size_; }
+
+ private:
+ std::string name_;
+ uint64_t maximum_size_;
+};
+
class Partition final {
friend class MetadataBuilder;
public:
- Partition(const std::string& name, const std::string& guid, uint32_t attributes);
+ Partition(const std::string& name, const std::string& group_name, const std::string& guid,
+ uint32_t attributes);
// Add a raw extent.
void AddExtent(std::unique_ptr<Extent>&& extent);
@@ -107,7 +121,12 @@
// Remove all extents from this partition.
void RemoveExtents();
+ // Compute the size used by linear extents. This is the same as size(),
+ // but does not factor in extents which do not take up space.
+ uint64_t BytesOnDisk() const;
+
const std::string& name() const { return name_; }
+ const std::string& group_name() const { return group_name_; }
uint32_t attributes() const { return attributes_; }
const std::string& guid() const { return guid_; }
const std::vector<std::unique_ptr<Extent>>& extents() const { return extents_; }
@@ -117,6 +136,7 @@
void ShrinkTo(uint64_t aligned_size);
std::string name_;
+ std::string group_name_;
std::string guid_;
std::vector<std::unique_ptr<Extent>> extents_;
uint32_t attributes_;
@@ -156,12 +176,24 @@
return New(device_info, metadata_max_size, metadata_slot_count);
}
+ // Define a new partition group. By default there is one group called
+ // "default", with an unrestricted size. A non-zero size will restrict the
+ // total space used by all partitions in the group.
+ //
+ // This can fail and return false if the group already exists.
+ bool AddGroup(const std::string& group_name, uint64_t maximum_size);
+
// Export metadata so it can be serialized to an image, to disk, or mounted
// via device-mapper.
std::unique_ptr<LpMetadata> Export();
// Add a partition, returning a handle so it can be sized as needed. If a
// partition with the given name already exists, nullptr is returned.
+ Partition* AddPartition(const std::string& name, const std::string& group_name,
+ const std::string& guid, uint32_t attributes);
+
+ // Same as AddPartition above, but uses the default partition group which
+ // has no size restrictions.
Partition* AddPartition(const std::string& name, const std::string& guid, uint32_t attributes);
// Delete a partition by name if it exists.
@@ -184,6 +216,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.
@@ -201,10 +234,13 @@
bool GrowPartition(Partition* partition, uint64_t aligned_size);
void ShrinkPartition(Partition* partition, uint64_t aligned_size);
uint64_t AlignSector(uint64_t sector);
+ PartitionGroup* FindGroup(const std::string& group_name) const;
+ uint64_t TotalSizeOfGroup(PartitionGroup* group) const;
LpMetadataGeometry geometry_;
LpMetadataHeader header_;
std::vector<std::unique_ptr<Partition>> partitions_;
+ std::vector<std::unique_ptr<PartitionGroup>> groups_;
BlockDeviceInfo device_info_;
};
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 6da24f6..51d262b 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -36,6 +36,7 @@
LpMetadataHeader header;
std::vector<LpMetadataPartition> partitions;
std::vector<LpMetadataExtent> extents;
+ std::vector<LpMetadataPartitionGroup> groups;
};
// Place an initial partition table on the device. This will overwrite the
@@ -68,6 +69,7 @@
// Helper to extract safe C++ strings from partition info.
std::string GetPartitionName(const LpMetadataPartition& partition);
std::string GetPartitionGuid(const LpMetadataPartition& partition);
+std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group);
// Helper to return a slot number for a slot suffix.
uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 52c80f7..79ef2ab 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@
#define LP_METADATA_HEADER_MAGIC 0x414C5030
/* Current metadata version. */
-#define LP_METADATA_MAJOR_VERSION 1
+#define LP_METADATA_MAJOR_VERSION 2
#define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field.
@@ -216,6 +216,8 @@
LpMetadataTableDescriptor partitions;
/* 92: Extent table descriptor. */
LpMetadataTableDescriptor extents;
+ /* 104: Updateable group descriptor. */
+ LpMetadataTableDescriptor groups;
} __attribute__((packed)) LpMetadataHeader;
/* This struct defines a logical partition entry, similar to what would be
@@ -245,6 +247,9 @@
* least one extent.
*/
uint32_t num_extents;
+
+ /* 64: Group this partition belongs to. */
+ uint32_t group_index;
} __attribute__((packed)) LpMetadataPartition;
/* This extent is a dm-linear target, and the index is an index into the
@@ -271,6 +276,19 @@
uint64_t target_data;
} __attribute__((packed)) LpMetadataExtent;
+/* This struct defines an entry in the groups table. Each group has a maximum
+ * size, and partitions in a group must not exceed that size. There is always
+ * a "default" group of unlimited size, which is used when not using update
+ * groups or when using overlayfs or fastbootd.
+ */
+typedef struct LpMetadataPartitionGroup {
+ /* 0: Name of this group. Any unused characters must be 0. */
+ char name[36];
+
+ /* 36: Maximum size in bytes. If 0, the group has no maximum size. */
+ uint64_t maximum_size;
+} LpMetadataPartitionGroup;
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 329a901..f93852b 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));
@@ -343,9 +343,6 @@
ASSERT_NE(partition, nullptr);
}
ASSERT_NE(partition, nullptr);
- // Add one extent to any partition to fill up more space - we're at 508
- // bytes after this, out of 512.
- ASSERT_TRUE(builder->ResizePartition(partition, 1024));
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 190c650..005d493 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -188,7 +188,8 @@
return false;
}
if (!ValidateTableBounds(header, header.partitions) ||
- !ValidateTableBounds(header, header.extents)) {
+ !ValidateTableBounds(header, header.extents) ||
+ !ValidateTableBounds(header, header.groups)) {
LERROR << "Logical partition metadata has invalid table bounds.";
return false;
}
@@ -202,6 +203,10 @@
LERROR << "Logical partition metadata has invalid extent table entry size.";
return false;
}
+ if (header.groups.entry_size != sizeof(LpMetadataPartitionGroup)) {
+ LERROR << "Logical partition metadata has invalid group table entry size.";
+ return false;
+ }
return true;
}
@@ -257,6 +262,10 @@
LERROR << "Logical partition has invalid extent list.";
return nullptr;
}
+ if (partition.group_index >= header.groups.num_entries) {
+ LERROR << "Logical partition has invalid group index.";
+ return nullptr;
+ }
metadata->partitions.push_back(partition);
}
@@ -269,6 +278,16 @@
metadata->extents.push_back(extent);
}
+
+ cursor = buffer.get() + header.groups.offset;
+ for (size_t i = 0; i < header.groups.num_entries; i++) {
+ LpMetadataPartitionGroup group = {};
+ memcpy(&group, cursor, sizeof(group));
+ cursor += header.groups.entry_size;
+
+ metadata->groups.push_back(group);
+ }
+
return metadata;
}
@@ -345,5 +364,9 @@
return NameFromFixedArray(partition.name, sizeof(partition.name));
}
+std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group) {
+ return NameFromFixedArray(group.name, sizeof(group.name));
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index ad84b22..2415629 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -56,14 +56,17 @@
metadata.partitions.size() * sizeof(LpMetadataPartition));
std::string extents(reinterpret_cast<const char*>(metadata.extents.data()),
metadata.extents.size() * sizeof(LpMetadataExtent));
+ std::string groups(reinterpret_cast<const char*>(metadata.groups.data()),
+ metadata.groups.size() * sizeof(LpMetadataPartitionGroup));
// Compute positions of tables.
header.partitions.offset = 0;
header.extents.offset = header.partitions.offset + partitions.size();
- header.tables_size = header.extents.offset + extents.size();
+ header.groups.offset = header.extents.offset + extents.size();
+ header.tables_size = header.groups.offset + groups.size();
// Compute payload checksum.
- std::string tables = partitions + extents;
+ std::string tables = partitions + extents + groups;
SHA256(tables.data(), tables.size(), header.tables_checksum);
// Compute header checksum.
@@ -94,7 +97,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/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 879ba21..f78093b 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -42,6 +42,7 @@
using DmTargetLinear = ::android::dm::DmTargetLinear;
using DmTargetZero = ::android::dm::DmTargetZero;
using DmTargetAndroidVerity = ::android::dm::DmTargetAndroidVerity;
+using DmTargetBow = ::android::dm::DmTargetBow;
using DmTargetTypeInfo = ::android::dm::DmTargetTypeInfo;
using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
@@ -108,6 +109,13 @@
std::string block_device = NextArg();
return std::make_unique<DmTargetAndroidVerity>(start_sector, num_sectors, keyid,
block_device);
+ } else if (target_type == "bow") {
+ if (!HasArgs(1)) {
+ std::cerr << "Expected \"bow\" <block_device>" << std::endl;
+ return nullptr;
+ }
+ std::string block_device = NextArg();
+ return std::make_unique<DmTargetBow>(start_sector, num_sectors, block_device);
} else {
std::cerr << "Unrecognized target type: " << target_type << std::endl;
return nullptr;
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 9096f79..80bf84a 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -97,6 +97,7 @@
android.hardware.health@2.0 \
android.hardware.health@1.0 \
android.hardware.health@1.0-convert \
+ libbinderthreadstate \
libhidltransport \
libhidlbase \
libhwbinder_noltopgo \
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 79cfbcb..6f97d19 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -68,6 +68,7 @@
bool CreateLogicalPartitions();
bool MountPartition(fstab_rec* fstab_rec);
bool MountPartitions();
+ bool IsDmLinearEnabled();
bool GetBackingDmLinearDevices();
virtual ListenerAction UeventCallback(const Uevent& uevent);
@@ -120,30 +121,18 @@
return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
}
-static bool IsRecoveryMode() {
+static bool ForceNormalBoot() {
static bool force_normal_boot = []() {
std::string cmdline;
android::base::ReadFileToString("/proc/cmdline", &cmdline);
return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
}();
- return !force_normal_boot && access("/system/bin/recovery", F_OK) == 0;
+ return force_normal_boot;
}
-static inline bool IsDmLinearEnabled() {
- static bool checked = false;
- static bool enabled = false;
- if (checked) {
- return enabled;
- }
- import_kernel_cmdline(false,
- [](const std::string& key, const std::string& value, bool in_qemu) {
- if (key == "androidboot.logical_partitions" && value == "1") {
- enabled = true;
- }
- });
- checked = true;
- return enabled;
+static bool IsRecoveryMode() {
+ return !ForceNormalBoot() && access("/system/bin/recovery", F_OK) == 0;
}
// Class Definitions
@@ -194,6 +183,13 @@
return GetBackingDmLinearDevices() && GetDmVerityDevices() && InitRequiredDevices();
}
+bool FirstStageMount::IsDmLinearEnabled() {
+ for (auto fstab_rec : mount_fstab_recs_) {
+ if (fs_mgr_is_logical(fstab_rec)) return true;
+ }
+ return false;
+}
+
bool FirstStageMount::GetBackingDmLinearDevices() {
// Add any additional devices required for dm-linear mappings.
if (!IsDmLinearEnabled()) {
@@ -368,11 +364,15 @@
// this case, we mount system first then pivot to it. From that point on,
// we are effectively identical to a system-as-root device.
auto system_partition =
- std::find_if(mount_fstab_recs_.begin(), mount_fstab_recs_.end(), [](const auto& rec) {
- return rec->mount_point == "/system"s ||
- rec->mount_point == "/system_recovery_mount"s;
- });
+ std::find_if(mount_fstab_recs_.begin(), mount_fstab_recs_.end(),
+ [](const auto& rec) { return rec->mount_point == "/system"s; });
+
if (system_partition != mount_fstab_recs_.end()) {
+ if (ForceNormalBoot()) {
+ free((*system_partition)->mount_point);
+ (*system_partition)->mount_point = strdup("/system_recovery_mount");
+ }
+
if (!MountPartition(*system_partition)) {
return false;
}
@@ -388,7 +388,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/init_first_stage.cpp b/init/init_first_stage.cpp
index 0c4a110..40706a1 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -84,6 +84,9 @@
CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
+ // These below mounts are done in first stage init so that first stage mount can mount
+ // subdirectories of /mnt/{vendor,product}/. Other mounts, not required by first stage mount,
+ // should be done in rc files.
// Mount staging areas for devices managed by vold
// See storage config details at http://source.android.com/devices/storage/
CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 908c67f..866f40e 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/libbacktrace/Android.bp b/libbacktrace/Android.bp
index c42ae49..43bcd98 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -27,15 +27,6 @@
enabled: false,
},
},
-
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
}
libbacktrace_sources = [
@@ -108,7 +99,7 @@
whole_static_libs: ["libdemangle"],
}
-cc_library_shared {
+cc_test_library {
name: "libbacktrace_test",
defaults: ["libbacktrace_common"],
host_supported: true,
@@ -121,6 +112,21 @@
shared_libs: [
"libunwindstack",
],
+ relative_install_path: "backtrace_test_libs",
+
+ target: {
+ linux_glibc: {
+ // The host uses rosegment, which isn't supported yet.
+ ldflags: [
+ "-Wl,--no-rosegment",
+ ],
+ // This forces the creation of eh_frame with unwind information
+ // for host.
+ cflags: [
+ "-fcxx-exceptions"
+ ],
+ },
+ },
}
//-------------------------------------------------------------------------
@@ -128,12 +134,12 @@
//-------------------------------------------------------------------------
cc_test {
name: "backtrace_test",
+ isolated: true,
defaults: ["libbacktrace_common"],
host_supported: true,
srcs: [
"backtrace_offline_test.cpp",
"backtrace_test.cpp",
- "GetPss.cpp",
],
cflags: [
@@ -143,7 +149,6 @@
],
shared_libs: [
- "libbacktrace_test",
"libbacktrace",
"libbase",
"liblog",
@@ -152,17 +157,10 @@
group_static_libs: true,
- target: {
- android: {
- cflags: ["-DENABLE_PSS_TESTS"],
- shared_libs: [
- "libutils",
- ],
- },
- linux_glibc: {
- static_libs: ["libutils"],
- },
- },
+ // So that the dlopen can find the libbacktrace_test.so.
+ ldflags: [
+ "-Wl,--rpath,${ORIGIN}/../backtrace_test_libs",
+ ],
test_suites: ["device-tests"],
data: [
diff --git a/libbacktrace/BacktraceTest.h b/libbacktrace/BacktraceTest.h
new file mode 100644
index 0000000..c38af04
--- /dev/null
+++ b/libbacktrace/BacktraceTest.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_BACKTRACE_TEST_H
+#define _LIBBACKTRACE_BACKTRACE_TEST_H
+
+#include <dlfcn.h>
+
+#include <gtest/gtest.h>
+
+class BacktraceTest : public ::testing::Test {
+ protected:
+ static void SetUpTestCase() {
+ dl_handle_ = dlopen("libbacktrace_test.so", RTLD_NOW | RTLD_LOCAL);
+
+ test_level_one_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+ dlsym(dl_handle_, "test_level_one"));
+
+ test_level_two_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+ dlsym(dl_handle_, "test_level_two"));
+
+ test_level_three_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+ dlsym(dl_handle_, "test_level_three"));
+
+ test_level_four_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
+ dlsym(dl_handle_, "test_level_four"));
+
+ test_recursive_call_ = reinterpret_cast<int (*)(int, void (*)(void*), void*)>(
+ dlsym(dl_handle_, "test_recursive_call"));
+
+ test_get_context_and_wait_ = reinterpret_cast<void (*)(void*, volatile int*)>(
+ dlsym(dl_handle_, "test_get_context_and_wait"));
+
+ test_signal_action_ =
+ reinterpret_cast<void (*)(int, siginfo_t*, void*)>(dlsym(dl_handle_, "test_signal_action"));
+
+ test_signal_handler_ =
+ reinterpret_cast<void (*)(int)>(dlsym(dl_handle_, "test_signal_handler"));
+ }
+
+ void SetUp() override {
+ ASSERT_TRUE(dl_handle_ != nullptr);
+ ASSERT_TRUE(test_level_one_ != nullptr);
+ ASSERT_TRUE(test_level_two_ != nullptr);
+ ASSERT_TRUE(test_level_three_ != nullptr);
+ ASSERT_TRUE(test_level_four_ != nullptr);
+ ASSERT_TRUE(test_recursive_call_ != nullptr);
+ ASSERT_TRUE(test_get_context_and_wait_ != nullptr);
+ ASSERT_TRUE(test_signal_action_ != nullptr);
+ ASSERT_TRUE(test_signal_handler_ != nullptr);
+ }
+
+ public:
+ static void* dl_handle_;
+ static int (*test_level_one_)(int, int, int, int, void (*)(void*), void*);
+ static int (*test_level_two_)(int, int, int, int, void (*)(void*), void*);
+ static int (*test_level_three_)(int, int, int, int, void (*)(void*), void*);
+ static int (*test_level_four_)(int, int, int, int, void (*)(void*), void*);
+ static int (*test_recursive_call_)(int, void (*)(void*), void*);
+ static void (*test_get_context_and_wait_)(void*, volatile int*);
+ static void (*test_signal_action_)(int, siginfo_t*, void*);
+ static void (*test_signal_handler_)(int);
+};
+
+#endif // _LIBBACKTRACE_BACKTRACE_TEST_H
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
deleted file mode 100644
index 6d750ea..0000000
--- a/libbacktrace/GetPss.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-// This is an extremely simplified version of libpagemap.
-
-#define _BITS(x, offset, bits) (((x) >> (offset)) & ((1LL << (bits)) - 1))
-
-#define PAGEMAP_PRESENT(x) (_BITS(x, 63, 1))
-#define PAGEMAP_SWAPPED(x) (_BITS(x, 62, 1))
-#define PAGEMAP_SHIFT(x) (_BITS(x, 55, 6))
-#define PAGEMAP_PFN(x) (_BITS(x, 0, 55))
-#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
-#define PAGEMAP_SWAP_TYPE(x) (_BITS(x, 0, 5))
-
-static bool ReadData(int fd, off_t place, uint64_t *data) {
- if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
- return false;
- }
- if (read(fd, (void*)data, sizeof(uint64_t)) != (ssize_t)sizeof(uint64_t)) {
- return false;
- }
- return true;
-}
-
-size_t GetPssBytes() {
- FILE* maps = fopen("/proc/self/maps", "r");
- if (maps == nullptr) {
- return 0;
- }
-
- int pagecount_fd = open("/proc/kpagecount", O_RDONLY);
- if (pagecount_fd == -1) {
- fclose(maps);
- return 0;
- }
-
- int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
- if (pagemap_fd == -1) {
- fclose(maps);
- close(pagecount_fd);
- return 0;
- }
-
- char line[4096];
- size_t total_pss = 0;
- int pagesize = getpagesize();
- while (fgets(line, sizeof(line), maps)) {
- uintptr_t start, end;
- if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " ", &start, &end) != 2) {
- total_pss = 0;
- break;
- }
- for (off_t page = static_cast<off_t>(start/pagesize);
- page < static_cast<off_t>(end/pagesize); page++) {
- uint64_t data;
- if (ReadData(pagemap_fd, page, &data)) {
- if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
- uint64_t count;
- if (ReadData(pagecount_fd, static_cast<off_t>(PAGEMAP_PFN(data)), &count)) {
- total_pss += (count >= 1) ? pagesize / count : 0;
- }
- }
- }
- }
- }
-
- fclose(maps);
-
- close(pagecount_fd);
- close(pagemap_fd);
-
- return total_pss;
-}
diff --git a/libbacktrace/GetPss.h b/libbacktrace/GetPss.h
deleted file mode 100644
index 787c33d..0000000
--- a/libbacktrace/GetPss.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBBACKTRACE_GET_PSS_H
-#define _LIBBACKTRACE_GET_PSS_H
-
-size_t GetPssBytes();
-
-#endif // _LIBBACKTRACE_GET_PSS_H
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 7d1027e..662fb99 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -37,15 +37,7 @@
#include <gtest/gtest.h>
-extern "C" {
-// Prototypes for functions in the test library.
-int test_level_one(int, int, int, int, void (*)(void*), void*);
-int test_level_two(int, int, int, int, void (*)(void*), void*);
-int test_level_three(int, int, int, int, void (*)(void*), void*);
-int test_level_four(int, int, int, int, void (*)(void*), void*);
-int test_recursive_call(int, void (*)(void*), void*);
-void test_get_context_and_wait(void* context, volatile int* exit_flag);
-}
+#include "BacktraceTest.h"
struct FunctionSymbol {
std::string name;
@@ -56,12 +48,13 @@
static std::vector<FunctionSymbol> GetFunctionSymbols() {
std::vector<FunctionSymbol> symbols = {
{"unknown_start", 0, 0},
- {"test_level_one", reinterpret_cast<uint64_t>(&test_level_one), 0},
- {"test_level_two", reinterpret_cast<uint64_t>(&test_level_two), 0},
- {"test_level_three", reinterpret_cast<uint64_t>(&test_level_three), 0},
- {"test_level_four", reinterpret_cast<uint64_t>(&test_level_four), 0},
- {"test_recursive_call", reinterpret_cast<uint64_t>(&test_recursive_call), 0},
- {"test_get_context_and_wait", reinterpret_cast<uint64_t>(&test_get_context_and_wait), 0},
+ {"test_level_one", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_one_), 0},
+ {"test_level_two", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_two_), 0},
+ {"test_level_three", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_three_), 0},
+ {"test_level_four", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_four_), 0},
+ {"test_recursive_call", reinterpret_cast<uint64_t>(&BacktraceTest::test_recursive_call_), 0},
+ {"test_get_context_and_wait",
+ reinterpret_cast<uint64_t>(&BacktraceTest::test_get_context_and_wait_), 0},
{"unknown_end", static_cast<uint64_t>(-1), static_cast<uint64_t>(-1)},
};
std::sort(
@@ -100,7 +93,7 @@
static void* OfflineThreadFunc(void* arg) {
OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
fn_arg->tid = android::base::GetThreadId();
- test_get_context_and_wait(&fn_arg->ucontext, &fn_arg->exit_flag);
+ BacktraceTest::test_get_context_and_wait_(&fn_arg->ucontext, &fn_arg->exit_flag);
return nullptr;
}
@@ -109,7 +102,7 @@
}
// This test is disable because it is for generating test data.
-TEST(libbacktrace, DISABLED_generate_offline_testdata) {
+TEST_F(BacktraceTest, DISABLED_generate_offline_testdata) {
// Create a thread to generate the needed stack and registers information.
const size_t stack_size = 16 * 1024;
void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -304,22 +297,22 @@
}
// For now, these tests can only run on the given architectures.
-TEST(libbacktrace, offline_eh_frame) {
+TEST_F(BacktraceTest, offline_eh_frame) {
BacktraceOfflineTest("arm64", "libbacktrace_test_eh_frame.so");
BacktraceOfflineTest("x86_64", "libbacktrace_test_eh_frame.so");
}
-TEST(libbacktrace, offline_debug_frame) {
+TEST_F(BacktraceTest, offline_debug_frame) {
BacktraceOfflineTest("arm", "libbacktrace_test_debug_frame.so");
BacktraceOfflineTest("x86", "libbacktrace_test_debug_frame.so");
}
-TEST(libbacktrace, offline_gnu_debugdata) {
+TEST_F(BacktraceTest, offline_gnu_debugdata) {
BacktraceOfflineTest("arm", "libbacktrace_test_gnu_debugdata.so");
BacktraceOfflineTest("x86", "libbacktrace_test_gnu_debugdata.so");
}
-TEST(libbacktrace, offline_arm_exidx) {
+TEST_F(BacktraceTest, offline_arm_exidx) {
BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
}
@@ -373,32 +366,32 @@
// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
// overlap with each other, which appears in /system/lib/libart.so.
-TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
+TEST_F(BacktraceTest, offline_unwind_mix_eh_frame_and_arm_exidx) {
LibUnwindingTest("arm", "offline_testdata_for_libart", "libart.so");
}
-TEST(libbacktrace, offline_debug_frame_with_load_bias) {
+TEST_F(BacktraceTest, offline_debug_frame_with_load_bias) {
LibUnwindingTest("arm", "offline_testdata_for_libandroid_runtime", "libandroid_runtime.so");
}
-TEST(libbacktrace, offline_try_armexidx_after_debug_frame) {
+TEST_F(BacktraceTest, offline_try_armexidx_after_debug_frame) {
LibUnwindingTest("arm", "offline_testdata_for_libGLESv2_adreno", "libGLESv2_adreno.so");
}
-TEST(libbacktrace, offline_cie_with_P_augmentation) {
+TEST_F(BacktraceTest, offline_cie_with_P_augmentation) {
// Make sure we can unwind through functions with CIE entry containing P augmentation, which
// makes unwinding library reading personality handler from memory. One example is
// /system/lib64/libskia.so.
LibUnwindingTest("arm64", "offline_testdata_for_libskia", "libskia.so");
}
-TEST(libbacktrace, offline_empty_eh_frame_hdr) {
+TEST_F(BacktraceTest, offline_empty_eh_frame_hdr) {
// Make sure we can unwind through libraries with empty .eh_frame_hdr section. One example is
// /vendor/lib64/egl/eglSubDriverAndroid.so.
LibUnwindingTest("arm64", "offline_testdata_for_eglSubDriverAndroid", "eglSubDriverAndroid.so");
}
-TEST(libbacktrace, offline_max_frames_limit) {
+TEST_F(BacktraceTest, offline_max_frames_limit) {
// The length of callchain can reach 256 when recording an application.
ASSERT_GE(MAX_BACKTRACE_FRAMES, 256);
}
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 06a32c7..f4191b9 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <malloc.h>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
@@ -55,6 +56,7 @@
// For the THREAD_SIGNAL definition.
#include "BacktraceCurrent.h"
+#include "BacktraceTest.h"
#include "backtrace_testlib.h"
// Number of microseconds per milliseconds.
@@ -95,6 +97,23 @@
static void VerifyMaxDump(Backtrace* backtrace, create_func_t create_func = nullptr,
map_create_func_t map_func = nullptr);
+void* BacktraceTest::dl_handle_;
+int (*BacktraceTest::test_level_one_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_level_two_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_level_three_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_level_four_)(int, int, int, int, void (*)(void*), void*);
+int (*BacktraceTest::test_recursive_call_)(int, void (*)(void*), void*);
+void (*BacktraceTest::test_get_context_and_wait_)(void*, volatile int*);
+void (*BacktraceTest::test_signal_action_)(int, siginfo_t*, void*);
+void (*BacktraceTest::test_signal_handler_)(int);
+
+extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
+ static const char* initial_args[] = {"--slow_threshold_ms=8000", "--deadline_threshold_ms=15000"};
+ *args = initial_args;
+ *num_args = 2;
+ return true;
+}
+
static uint64_t NanoTime() {
struct timespec t = { 0, 0 };
clock_gettime(CLOCK_MONOTONIC, &t);
@@ -250,7 +269,7 @@
return false;
}
-TEST(libbacktrace, local_no_unwind_frames) {
+TEST_F(BacktraceTest, local_no_unwind_frames) {
// Verify that a local unwind does not include any frames within
// libunwind or libbacktrace.
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
@@ -270,7 +289,7 @@
}
}
-TEST(libbacktrace, local_unwind_frames) {
+TEST_F(BacktraceTest, local_unwind_frames) {
// Verify that a local unwind with the skip frames disabled does include
// frames within the backtrace libraries.
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
@@ -302,8 +321,8 @@
<< DumpFrames(backtrace.get());
}
-TEST(libbacktrace, local_trace) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
+TEST_F(BacktraceTest, local_trace) {
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
}
static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2,
@@ -357,12 +376,12 @@
VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
}
-TEST(libbacktrace, local_trace_ignore_frames) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
+TEST_F(BacktraceTest, local_trace_ignore_frames) {
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
}
-TEST(libbacktrace, local_max_trace) {
- ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0);
+TEST_F(BacktraceTest, local_max_trace) {
+ ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, VerifyMaxBacktrace, nullptr), 0);
}
static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*),
@@ -402,10 +421,10 @@
ASSERT_TRUE(verified) << "Last backtrace:\n" << last_dump;
}
-TEST(libbacktrace, ptrace_trace) {
+TEST_F(BacktraceTest, ptrace_trace) {
pid_t pid;
if ((pid = fork()) == 0) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
@@ -416,10 +435,10 @@
ASSERT_EQ(waitpid(pid, &status, 0), pid);
}
-TEST(libbacktrace, ptrace_max_trace) {
+TEST_F(BacktraceTest, ptrace_max_trace) {
pid_t pid;
if ((pid = fork()) == 0) {
- ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, nullptr, nullptr), 0);
+ ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump, Backtrace::Create,
@@ -446,10 +465,10 @@
VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr);
}
-TEST(libbacktrace, ptrace_ignore_frames) {
+TEST_F(BacktraceTest, ptrace_ignore_frames) {
pid_t pid;
if ((pid = fork()) == 0) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
@@ -462,7 +481,7 @@
// Create a process with multiple threads and dump all of the threads.
static void* PtraceThreadLevelRun(void*) {
- EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+ EXPECT_NE(BacktraceTest::test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
return nullptr;
}
@@ -483,7 +502,7 @@
}
}
-TEST(libbacktrace, ptrace_threads) {
+TEST_F(BacktraceTest, ptrace_threads) {
pid_t pid;
if ((pid = fork()) == 0) {
for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
@@ -494,7 +513,7 @@
pthread_t thread;
ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
}
- ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
@@ -532,8 +551,8 @@
VerifyLevelDump(backtrace.get());
}
-TEST(libbacktrace, thread_current_level) {
- ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
+TEST_F(BacktraceTest, thread_current_level) {
+ ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
}
static void VerifyMaxThread(void*) {
@@ -545,19 +564,19 @@
VerifyMaxDump(backtrace.get());
}
-TEST(libbacktrace, thread_current_max) {
- ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, nullptr), 0);
+TEST_F(BacktraceTest, thread_current_max) {
+ ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, VerifyMaxThread, nullptr), 0);
}
static void* ThreadLevelRun(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data);
thread->tid = android::base::GetThreadId();
- EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
+ EXPECT_NE(BacktraceTest::test_level_one_(1, 2, 3, 4, ThreadSetState, data), 0);
return nullptr;
}
-TEST(libbacktrace, thread_level_trace) {
+TEST_F(BacktraceTest, thread_level_trace) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -607,7 +626,7 @@
EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
}
-TEST(libbacktrace, thread_ignore_frames) {
+TEST_F(BacktraceTest, thread_ignore_frames) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -644,11 +663,12 @@
thread_t* thread = reinterpret_cast<thread_t*>(data);
thread->tid = android::base::GetThreadId();
- EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
+ EXPECT_NE(BacktraceTest::test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, ThreadSetState, data),
+ 0);
return nullptr;
}
-TEST(libbacktrace, thread_max_trace) {
+TEST_F(BacktraceTest, thread_max_trace) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -742,17 +762,17 @@
}
}
-TEST(libbacktrace, thread_multiple_dump) {
+TEST_F(BacktraceTest, thread_multiple_dump) {
MultipleThreadDumpTest(false);
}
-TEST(libbacktrace, thread_multiple_dump_same_map) {
+TEST_F(BacktraceTest, thread_multiple_dump_same_map) {
MultipleThreadDumpTest(true);
}
// This test is for UnwindMaps that should share the same map cursor when
// multiple maps are created for the current process at the same time.
-TEST(libbacktrace, simultaneous_maps) {
+TEST_F(BacktraceTest, simultaneous_maps) {
BacktraceMap* map1 = BacktraceMap::Create(getpid());
BacktraceMap* map2 = BacktraceMap::Create(getpid());
BacktraceMap* map3 = BacktraceMap::Create(getpid());
@@ -779,7 +799,7 @@
delete map3;
}
-TEST(libbacktrace, fillin_erases) {
+TEST_F(BacktraceTest, fillin_erases) {
BacktraceMap* back_map = BacktraceMap::Create(getpid());
backtrace_map_t map;
@@ -798,7 +818,7 @@
ASSERT_EQ("", map.name);
}
-TEST(libbacktrace, format_test) {
+TEST_F(BacktraceTest, format_test) {
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
@@ -969,7 +989,7 @@
ASSERT_TRUE(test_it == test_maps.end());
}
-TEST(libbacktrace, verify_map_remote) {
+TEST_F(BacktraceTest, verify_map_remote) {
pid_t pid;
CreateRemoteProcess(&pid);
@@ -1069,7 +1089,7 @@
delete[] expected;
}
-TEST(libbacktrace, thread_read) {
+TEST_F(BacktraceTest, thread_read) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -1120,7 +1140,7 @@
}
}
-TEST(libbacktrace, process_read) {
+TEST_F(BacktraceTest, process_read) {
g_ready = 0;
pid_t pid;
if ((pid = fork()) == 0) {
@@ -1187,29 +1207,23 @@
}
static void CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
- std::string system_dir;
-
-#if defined(__BIONIC__)
- system_dir = "/system/lib";
-#else
- const char* host_out_env = getenv("ANDROID_HOST_OUT");
- ASSERT_TRUE(host_out_env != nullptr);
- system_dir = std::string(host_out_env) + "/lib";
-#endif
-
-#if defined(__LP64__)
- system_dir += "64";
-#endif
+ std::string test_lib(testing::internal::GetArgvs()[0]);
+ auto const value = test_lib.find_last_of('/');
+ if (value == std::string::npos) {
+ test_lib = "../backtrace_test_libs/";
+ } else {
+ test_lib = test_lib.substr(0, value + 1) + "../backtrace_test_libs/";
+ }
+ test_lib += "libbacktrace_test.so";
*tmp_so_name = std::string(tmp_dir) + "/libbacktrace_test.so";
- std::string cp_cmd =
- android::base::StringPrintf("cp %s/libbacktrace_test.so %s", system_dir.c_str(), tmp_dir);
+ std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
// Copy the shared so to a tempory directory.
ASSERT_EQ(0, system(cp_cmd.c_str()));
}
-TEST(libbacktrace, check_unreadable_elf_local) {
+TEST_F(BacktraceTest, check_unreadable_elf_local) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1251,7 +1265,7 @@
VerifyFunctionsFound(found_functions);
}
-TEST(libbacktrace, check_unreadable_elf_remote) {
+TEST_F(BacktraceTest, check_unreadable_elf_remote) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1390,7 +1404,7 @@
typedef int (*test_func_t)(int, int, int, int, void (*)(void*), void*);
-TEST(libbacktrace, unwind_through_unreadable_elf_local) {
+TEST_F(BacktraceTest, unwind_through_unreadable_elf_local) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1405,11 +1419,9 @@
ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace, reinterpret_cast<void*>(test_func)),
0);
-
- ASSERT_TRUE(dlclose(lib_handle) == 0);
}
-TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
+TEST_F(BacktraceTest, unwind_through_unreadable_elf_remote) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@@ -1428,7 +1440,6 @@
exit(0);
}
ASSERT_TRUE(pid > 0);
- ASSERT_TRUE(dlclose(lib_handle) == 0);
uint64_t start = NanoTime();
bool done = false;
@@ -1465,7 +1476,7 @@
ASSERT_TRUE(done) << "Test function never found in unwind.";
}
-TEST(libbacktrace, unwind_thread_doesnt_exist) {
+TEST_F(BacktraceTest, unwind_thread_doesnt_exist) {
std::unique_ptr<Backtrace> backtrace(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 99999999));
ASSERT_TRUE(backtrace.get() != nullptr);
@@ -1473,18 +1484,18 @@
ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError().error_code);
}
-TEST(libbacktrace, local_get_function_name_before_unwind) {
+TEST_F(BacktraceTest, local_get_function_name_before_unwind) {
std::unique_ptr<Backtrace> backtrace(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
// Verify that trying to get a function name before doing an unwind works.
- uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+ uint64_t cur_func_offset = reinterpret_cast<uint64_t>(test_level_one_) + 1;
uint64_t offset;
ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
}
-TEST(libbacktrace, remote_get_function_name_before_unwind) {
+TEST_F(BacktraceTest, remote_get_function_name_before_unwind) {
pid_t pid;
CreateRemoteProcess(&pid);
@@ -1492,7 +1503,7 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
// Verify that trying to get a function name before doing an unwind works.
- uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+ uint64_t cur_func_offset = reinterpret_cast<uint64_t>(test_level_one_) + 1;
uint64_t offset;
ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
@@ -1579,7 +1590,7 @@
ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
ASSERT_EQ(std::string(""), backtrace->GetFunctionName(0, &offset));
- uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+ uint64_t cur_func_offset = reinterpret_cast<uint64_t>(BacktraceTest::test_level_one_) + 1;
// Now verify the device map flag actually causes the function name to be empty.
backtrace->FillInMap(cur_func_offset, &map);
ASSERT_TRUE((map.flags & PROT_DEVICE_MAP) == 0);
@@ -1628,7 +1639,7 @@
ASSERT_EQ(0U, backtrace->NumFrames());
}
-TEST(libbacktrace, unwind_disallow_device_map_local) {
+TEST_F(BacktraceTest, unwind_disallow_device_map_local) {
void* device_map;
SetupDeviceMap(&device_map);
@@ -1642,7 +1653,7 @@
munmap(device_map, DEVICE_MAP_SIZE);
}
-TEST(libbacktrace, unwind_disallow_device_map_remote) {
+TEST_F(BacktraceTest, unwind_disallow_device_map_remote) {
void* device_map;
SetupDeviceMap(&device_map);
@@ -1698,13 +1709,13 @@
pid_t pid;
if ((pid = fork()) == 0) {
if (use_action) {
- ScopedSignalHandler ssh(SIGUSR1, test_signal_action);
+ ScopedSignalHandler ssh(SIGUSR1, BacktraceTest::test_signal_action_);
- test_level_one(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
+ BacktraceTest::test_level_one_(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
} else {
- ScopedSignalHandler ssh(SIGUSR1, test_signal_handler);
+ ScopedSignalHandler ssh(SIGUSR1, BacktraceTest::test_signal_handler_);
- test_level_one(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
+ BacktraceTest::test_level_one_(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
}
}
ASSERT_NE(-1, pid);
@@ -1805,11 +1816,11 @@
FinishRemoteProcess(pid);
}
-TEST(libbacktrace, unwind_remote_through_signal_using_handler) {
+TEST_F(BacktraceTest, unwind_remote_through_signal_using_handler) {
UnwindThroughSignal(false, Backtrace::Create, BacktraceMap::Create);
}
-TEST(libbacktrace, unwind_remote_through_signal_using_action) {
+TEST_F(BacktraceTest, unwind_remote_through_signal_using_action) {
UnwindThroughSignal(true, Backtrace::Create, BacktraceMap::Create);
}
@@ -1822,49 +1833,41 @@
ASSERT_EQ(0U, backtrace->GetFrame(0)->num);
}
-TEST(libbacktrace, unwind_frame_skip_numbering) {
+TEST_F(BacktraceTest, unwind_frame_skip_numbering) {
TestFrameSkipNumbering(Backtrace::Create, BacktraceMap::Create);
}
-#if defined(ENABLE_PSS_TESTS)
-#include "GetPss.h"
-
#define MAX_LEAK_BYTES (32*1024UL)
static void CheckForLeak(pid_t pid, pid_t tid) {
std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
- // Do a few runs to get the PSS stable.
- for (size_t i = 0; i < 100; i++) {
- Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
- ASSERT_TRUE(backtrace != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- VERIFY_NO_ERROR(backtrace->GetError().error_code);
- delete backtrace;
- }
- size_t stable_pss = GetPssBytes();
- ASSERT_TRUE(stable_pss != 0);
-
// Loop enough that even a small leak should be detectable.
+ size_t first_allocated_bytes = 0;
+ size_t last_allocated_bytes = 0;
for (size_t i = 0; i < 4096; i++) {
Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
ASSERT_TRUE(backtrace != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
VERIFY_NO_ERROR(backtrace->GetError().error_code);
delete backtrace;
- }
- size_t new_pss = GetPssBytes();
- ASSERT_TRUE(new_pss != 0);
- if (new_pss > stable_pss) {
- ASSERT_LE(new_pss - stable_pss, MAX_LEAK_BYTES);
+
+ size_t allocated_bytes = mallinfo().uordblks;
+ if (first_allocated_bytes == 0) {
+ first_allocated_bytes = allocated_bytes;
+ } else if (last_allocated_bytes > first_allocated_bytes) {
+ // Check that the memory did not increase too much over the first loop.
+ ASSERT_LE(last_allocated_bytes - first_allocated_bytes, MAX_LEAK_BYTES);
+ }
+ last_allocated_bytes = allocated_bytes;
}
}
-TEST(libbacktrace, check_for_leak_local) {
+TEST_F(BacktraceTest, check_for_leak_local) {
CheckForLeak(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD);
}
-TEST(libbacktrace, check_for_leak_local_thread) {
+TEST_F(BacktraceTest, check_for_leak_local_thread) {
thread_t thread_data = { 0, 0, 0, nullptr };
pthread_t thread;
ASSERT_TRUE(pthread_create(&thread, nullptr, ThreadLevelRun, &thread_data) == 0);
@@ -1880,7 +1883,7 @@
ASSERT_TRUE(pthread_join(thread, nullptr) == 0);
}
-TEST(libbacktrace, check_for_leak_remote) {
+TEST_F(BacktraceTest, check_for_leak_remote) {
pid_t pid;
CreateRemoteProcess(&pid);
@@ -1888,4 +1891,3 @@
FinishRemoteProcess(pid);
}
-#endif
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/include/log/log_main.h b/liblog/include/log/log_main.h
index e7b1728..53653de 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -56,15 +56,24 @@
/*
* Use __VA_ARGS__ if running a static analyzer,
* to avoid warnings of unused variables in __VA_ARGS__.
- * __FAKE_USE_VA_ARGS is undefined at link time,
- * so don't link with __clang_analyzer__ defined.
+ * Use contexpr function in C++ mode, so these macros can be used
+ * in other constexpr functions without warning.
*/
#ifdef __clang_analyzer__
-extern void __fake_use_va_args(int, ...);
-#define __FAKE_USE_VA_ARGS(...) __fake_use_va_args(0, ##__VA_ARGS__)
+#ifdef __cplusplus
+extern "C++" {
+template <typename... Ts>
+constexpr int __fake_use_va_args(Ts...) {
+ return 0;
+}
+}
+#else
+extern int __fake_use_va_args(int, ...);
+#endif /* __cplusplus */
+#define __FAKE_USE_VA_ARGS(...) ((void)__fake_use_va_args(0, ##__VA_ARGS__))
#else
#define __FAKE_USE_VA_ARGS(...) ((void)(0))
-#endif
+#endif /* __clang_analyzer__ */
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
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/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 5c7ec13..92a8325 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -52,7 +52,7 @@
allocation_bytes_(0),
roots_(allocator),
root_vals_(allocator),
- segv_handler_(allocator),
+ segv_handler_(),
walking_ptr_(0) {
valid_allocations_range_.end = 0;
valid_allocations_range_.begin = ~valid_allocations_range_.end;
diff --git a/libmemunreachable/LeakFolding.cpp b/libmemunreachable/LeakFolding.cpp
index 69f320c..074dc48 100644
--- a/libmemunreachable/LeakFolding.cpp
+++ b/libmemunreachable/LeakFolding.cpp
@@ -57,7 +57,7 @@
}
void LeakFolding::AccumulateLeaks(SCCInfo* dominator) {
- std::function<void(SCCInfo*)> walk(std::allocator_arg, allocator_, [&](SCCInfo* scc) {
+ std::function<void(SCCInfo*)> walk([&](SCCInfo* scc) {
if (scc->accumulator != dominator) {
scc->accumulator = dominator;
dominator->cuumulative_size += scc->size;
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index ff53fad..9e08a8e 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -32,15 +32,14 @@
public:
using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
- explicit ScopedSignalHandler(Allocator<Fn> allocator) : allocator_(allocator), signal_(-1) {}
+ explicit ScopedSignalHandler() : signal_(-1) {}
~ScopedSignalHandler() { reset(); }
template <class F>
void install(int signal, F&& f) {
if (signal_ != -1) MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed");
- handler_ = SignalFn(std::allocator_arg, allocator_,
- [=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
+ handler_ = SignalFn([=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
struct sigaction act {};
act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) { handler_(signal, si, uctx); };
@@ -68,7 +67,6 @@
private:
using SignalFn = std::function<void(int, siginfo_t*, void*)>;
DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler);
- Allocator<Fn> allocator_;
int signal_;
struct sigaction old_act_;
// TODO(ccross): to support multiple ScopedSignalHandlers handler_ would need
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp
index e6e17ce..1551b5b 100644
--- a/libmetricslogger/Android.bp
+++ b/libmetricslogger/Android.bp
@@ -54,12 +54,12 @@
// -----------------------------------------------------------------------------
cc_test {
name: "metricslogger_tests",
+ isolated: true,
defaults: ["metricslogger_defaults"],
shared_libs: [
"libbase",
"libmetricslogger_debug",
],
- static_libs: ["libBionicGtestMain"],
srcs: [
"metrics_logger_test.cpp",
],
diff --git a/mkbootimg/Android.bp b/mkbootimg/Android.bp
index 576a677..c3cf746 100644
--- a/mkbootimg/Android.bp
+++ b/mkbootimg/Android.bp
@@ -31,3 +31,34 @@
header_libs: ["libmkbootimg_abi_headers"],
export_header_lib_headers: ["libmkbootimg_abi_headers"],
}
+
+python_defaults {
+ name: "mkbootimg_defaults",
+
+ version: {
+ py2: {
+ enabled: true,
+ embedded_launcher: true,
+ },
+ py3: {
+ enabled: false,
+ embedded_launcher: false,
+ },
+ },
+}
+
+python_binary_host {
+ name: "mkbootimg",
+ defaults: ["mkbootimg_defaults"],
+ srcs: [
+ "mkbootimg.py",
+ ],
+}
+
+python_binary_host {
+ name: "unpack_bootimg",
+ defaults: ["mkbootimg_defaults"],
+ srcs: [
+ "unpack_bootimg.py",
+ ],
+}
diff --git a/mkbootimg/Android.mk b/mkbootimg/Android.mk
deleted file mode 100644
index 92e1e27..0000000
--- a/mkbootimg/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := mkbootimg
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_IS_HOST_MODULE := true
-
-LOCAL_MODULE := mkbootimg
-
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := unpack_bootimg
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_IS_HOST_MODULE := true
-
-LOCAL_MODULE := unpack_bootimg
-
-include $(BUILD_PREBUILT)
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.py
old mode 100755
new mode 100644
similarity index 95%
rename from mkbootimg/mkbootimg
rename to mkbootimg/mkbootimg.py
index fda9af0..2eb2bab
--- a/mkbootimg/mkbootimg
+++ b/mkbootimg/mkbootimg.py
@@ -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/mkbootimg/unpack_bootimg b/mkbootimg/unpack_bootimg.py
old mode 100755
new mode 100644
similarity index 100%
rename from mkbootimg/unpack_bootimg
rename to mkbootimg/unpack_bootimg.py
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 915540e..2a70a4a 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -400,6 +400,7 @@
# Make sure we have the device encryption key.
start vold
+ exec - system system -- /system/bin/vdc checkpoint prepareDriveForCheckpoint /data
installkey /data
# Start bootcharting as soon as possible after the data partition is
@@ -407,6 +408,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
diff --git a/storaged/Android.bp b/storaged/Android.bp
index 7466728..733b60f 100644
--- a/storaged/Android.bp
+++ b/storaged/Android.bp
@@ -62,7 +62,7 @@
"uid_info.cpp",
"storaged.proto",
":storaged_aidl",
- "binder/android/os/storaged/IStoragedPrivate.aidl",
+ ":storaged_aidl_private",
],
static_libs: ["libhealthhalutils"],
@@ -116,4 +116,13 @@
srcs: [
"binder/android/os/IStoraged.aidl",
],
+ path: "binder",
+}
+
+filegroup {
+ name: "storaged_aidl_private",
+ srcs: [
+ "binder/android/os/storaged/IStoragedPrivate.aidl",
+ ],
+ path: "binder",
}
diff --git a/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp b/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
index 8e3b3b1..0849ee9 100644
--- a/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
+++ b/trusty/keymaster/3.0/TrustyKeymaster3Device.cpp
@@ -21,6 +21,7 @@
#include <cutils/log.h>
#include <keymaster/android_keymaster_messages.h>
#include <trusty_keymaster/TrustyKeymaster3Device.h>
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
using ::keymaster::AbortOperationRequest;
using ::keymaster::AbortOperationResponse;
@@ -393,20 +394,32 @@
const hidl_vec<KeyParameter>& inParams,
const hidl_vec<uint8_t>& input, update_cb _hidl_cb) {
UpdateOperationRequest request;
- request.op_handle = operationHandle;
- request.input.Reinitialize(input.data(), input.size());
- request.additional_params.Reinitialize(KmParamSet(inParams));
-
UpdateOperationResponse response;
- impl_->UpdateOperation(request, &response);
-
- uint32_t resultConsumed = 0;
hidl_vec<KeyParameter> resultParams;
hidl_vec<uint8_t> resultBlob;
- if (response.error == KM_ERROR_OK) {
- resultConsumed = response.input_consumed;
- resultParams = kmParamSet2Hidl(response.output_params);
- resultBlob = kmBuffer2hidlVec(response.output);
+ uint32_t resultConsumed = 0;
+
+ request.op_handle = operationHandle;
+ request.additional_params.Reinitialize(KmParamSet(inParams));
+
+ size_t inp_size = input.size();
+ size_t ser_size = request.SerializedSize();
+
+ if (ser_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
+ response.error = KM_ERROR_INVALID_INPUT_LENGTH;
+ } else {
+ if (ser_size + inp_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
+ inp_size = TRUSTY_KEYMASTER_SEND_BUF_SIZE - ser_size;
+ }
+ request.input.Reinitialize(input.data(), inp_size);
+
+ impl_->UpdateOperation(request, &response);
+
+ if (response.error == KM_ERROR_OK) {
+ resultConsumed = response.input_consumed;
+ resultParams = kmParamSet2Hidl(response.output_params);
+ resultBlob = kmBuffer2hidlVec(response.output);
+ }
}
_hidl_cb(legacy_enum_conversion(response.error), resultConsumed, resultParams, resultBlob);
return Void();