Merge "init: Format userdata_gsi if needed."
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 7c57258..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-LOCAL_PATH := $(my-dir)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/TEST_MAPPING b/TEST_MAPPING
index f9c3b4a..bc5685b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -7,6 +7,9 @@
"name": "debuggerd_test"
},
{
+ "name": "fs_mgr_unit_test"
+ },
+ {
"name": "init_tests"
},
{
diff --git a/adb/Android.bp b/adb/Android.bp
index 36bfad4..8199fff 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -22,35 +22,16 @@
"-Wexit-time-destructors",
"-Wno-unused-parameter",
"-Wno-missing-field-initializers",
+ "-Wthread-safety",
"-Wvla",
+ "-DADB_HOST=1", // overridden by adbd_defaults
],
cpp_std: "experimental",
use_version_lib: true,
-
compile_multilib: "first",
- product_variables: {
- debuggable: {
- cflags: [
- "-DALLOW_ADBD_ROOT",
- "-DALLOW_ADBD_DISABLE_VERITY",
- "-DALLOW_ADBD_NO_AUTH",
- ],
- },
- },
target: {
- android: {
- cflags: [
- "-DADB_HOST=0",
- "-Wthread-safety",
- ],
- },
-
- host: {
- cflags: ["-DADB_HOST=1"],
- },
-
darwin: {
host_ldlibs: [
"-lpthread",
@@ -76,6 +57,9 @@
// MinGW hides some things behind _POSIX_SOURCE.
"-D_POSIX_SOURCE",
+
+ // Not supported yet.
+ "-Wno-thread-safety",
],
host_ldlibs: [
@@ -84,15 +68,46 @@
"-luserenv",
],
},
+ },
+}
- not_windows: {
+cc_defaults {
+ name: "adbd_defaults",
+ defaults: ["adb_defaults"],
+
+ cflags: ["-UADB_HOST", "-DADB_HOST=0"],
+ product_variables: {
+ debuggable: {
cflags: [
- "-Wthread-safety",
+ "-DALLOW_ADBD_ROOT",
+ "-DALLOW_ADBD_DISABLE_VERITY",
+ "-DALLOW_ADBD_NO_AUTH",
],
},
},
}
+cc_defaults {
+ name: "host_adbd_supported",
+
+ host_supported: true,
+ target: {
+ linux: {
+ enabled: true,
+ host_ldlibs: [
+ "-lresolv", // b64_pton
+ "-lutil", // forkpty
+ ],
+ },
+ darwin: {
+ enabled: false,
+ },
+ windows: {
+ enabled: false,
+ },
+ },
+}
+
// libadb
// =========================================================
// These files are compiled for both the host and the device.
@@ -313,7 +328,7 @@
// libadbd_core contains the common sources to build libadbd and libadbd_services.
cc_library_static {
name: "libadbd_core",
- defaults: ["adb_defaults"],
+ defaults: ["adbd_defaults", "host_adbd_supported"],
recovery_available: true,
// libminadbd wants both, as it's used to build native tests.
@@ -322,9 +337,6 @@
srcs: libadb_srcs + libadb_posix_srcs + [
"daemon/auth.cpp",
"daemon/jdwp_service.cpp",
- "daemon/usb.cpp",
- "daemon/usb_ffs.cpp",
- "daemon/usb_legacy.cpp",
],
local_include_dirs: [
@@ -335,7 +347,6 @@
static_libs: [
"libdiagnose_usb",
- "libqemu_pipe",
],
shared_libs: [
@@ -346,22 +357,36 @@
"libcutils",
"liblog",
],
+
+ target: {
+ android: {
+ whole_static_libs: [
+ "libqemu_pipe",
+ ],
+ srcs: [
+ "daemon/transport_qemu.cpp",
+ "daemon/usb.cpp",
+ "daemon/usb_ffs.cpp",
+ "daemon/usb_legacy.cpp",
+ ]
+ },
+ linux_glibc: {
+ srcs: [
+ "daemon/usb_dummy.cpp",
+ ]
+ }
+ },
}
cc_library {
name: "libadbd_services",
- defaults: ["adb_defaults"],
+ defaults: ["adbd_defaults", "host_adbd_supported"],
recovery_available: true,
compile_multilib: "both",
srcs: [
- "daemon/abb_service.cpp",
"daemon/file_sync_service.cpp",
- "daemon/framebuffer_service.cpp",
- "daemon/mdns.cpp",
- "daemon/remount_service.cpp",
"daemon/services.cpp",
- "daemon/set_verity_enable_state_service.cpp",
"daemon/shell_service.cpp",
"shell_service_protocol.cpp",
],
@@ -373,27 +398,41 @@
static_libs: [
"libadbd_core",
- "libavb_user",
"libdiagnose_usb",
- "libqemu_pipe",
],
shared_libs: [
"libasyncio",
"libbase",
- "libbootloader_message",
"libcrypto",
"libcrypto_utils",
"libcutils",
- "libext4_utils",
- "libfec",
- "libfs_mgr",
"liblog",
- "libmdnssd",
- "libselinux",
],
target: {
+ android: {
+ srcs: [
+ "daemon/abb_service.cpp",
+ "daemon/framebuffer_service.cpp",
+ "daemon/mdns.cpp",
+ "daemon/reboot_service.cpp",
+ "daemon/remount_service.cpp",
+ "daemon/restart_service.cpp",
+ "daemon/set_verity_enable_state_service.cpp",
+ ],
+ static_libs: [
+ "libavb_user",
+ ],
+ shared_libs: [
+ "libbootloader_message",
+ "libmdnssd",
+ "libext4_utils",
+ "libfec",
+ "libfs_mgr",
+ "libselinux",
+ ],
+ },
recovery: {
exclude_srcs: [
"daemon/abb_service.cpp",
@@ -404,7 +443,7 @@
cc_library {
name: "libadbd",
- defaults: ["adb_defaults"],
+ defaults: ["adbd_defaults", "host_adbd_supported"],
recovery_available: true,
// Avoid getting duplicate symbol of android::build::GetBuildNumber().
@@ -435,7 +474,7 @@
cc_binary {
name: "adbd",
- defaults: ["adb_defaults"],
+ defaults: ["adbd_defaults", "host_adbd_supported"],
recovery_available: true,
srcs: [
@@ -467,7 +506,7 @@
cc_binary {
name: "abb",
- defaults: ["adb_defaults"],
+ defaults: ["adbd_defaults"],
recovery_available: false,
srcs: [
@@ -500,7 +539,7 @@
cc_test {
name: "adbd_test",
- defaults: ["adb_defaults"],
+ defaults: ["adbd_defaults"],
srcs: libadb_test_srcs + [
"daemon/services.cpp",
"daemon/shell_service.cpp",
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index 2bd6a3e..80f146c 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -32,7 +32,9 @@
#if !ADB_HOST
const char* adb_device_banner = "device";
+#if defined(__ANDROID__)
static android::base::LogdLogger gLogdLogger;
+#endif
#else
const char* adb_device_banner = "host";
#endif
@@ -46,7 +48,7 @@
fflush(stderr);
#endif
-#if !ADB_HOST
+#if !ADB_HOST && defined(__ANDROID__)
// Only print logs of INFO or higher to logcat, so that `adb logcat` with adbd tracing on
// doesn't result in exponential logging.
if (severity >= android::base::INFO) {
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 21e0874..d56a25f 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -35,7 +35,6 @@
#include "client/file_sync_client.h"
#include "commandline.h"
#include "fastdeploy.h"
-#include "sysdeps.h"
static constexpr int kFastDeployMinApi = 24;
@@ -161,17 +160,23 @@
if (use_fastdeploy == true) {
TemporaryFile metadataTmpFile;
- TemporaryFile patchTmpFile;
+ std::string patchTmpFilePath;
+ {
+ TemporaryFile patchTmpFile;
+ patchTmpFile.DoNotRemove();
+ patchTmpFilePath = patchTmpFile.path;
+ }
FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
extract_metadata(file, metadataFile);
fclose(metadataFile);
- create_patch(file, metadataTmpFile.path, patchTmpFile.path);
+ create_patch(file, metadataTmpFile.path, patchTmpFilePath.c_str());
// pass all but 1st (command) and last (apk path) parameters through to pm for
// session creation
std::vector<const char*> pm_args{argv + 1, argv + argc - 1};
- install_patch(file, patchTmpFile.path, pm_args.size(), pm_args.data());
+ install_patch(file, patchTmpFilePath.c_str(), pm_args.size(), pm_args.data());
+ adb_unlink(patchTmpFilePath.c_str());
delete_device_patch_file(file);
return 0;
} else {
diff --git a/adb/client/line_printer.cpp b/adb/client/line_printer.cpp
index 4dc2d28..50c03e8 100644
--- a/adb/client/line_printer.cpp
+++ b/adb/client/line_printer.cpp
@@ -31,6 +31,8 @@
// Stuff from ninja's util.h that's needed below.
#include <vector>
using namespace std;
+// This does not account for multiple UTF-8 bytes corresponding to a single Unicode code point, or
+// multiple code points corresponding to a single grapheme cluster (user-perceived character).
string ElideMiddle(const string& str, size_t width) {
const int kMargin = 3; // Space for "...".
string result = str;
@@ -85,9 +87,10 @@
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(console_, &csbi);
- // TODO: std::wstring to_print_wide; if (!android::base::UTF8ToWide(to_print, &to_print_wide)...
- // TODO: wstring ElideMiddle.
to_print = ElideMiddle(to_print, static_cast<size_t>(csbi.dwSize.X));
+ std::wstring to_print_wide;
+ // ElideMiddle may create invalid UTF-8, so ignore conversion errors.
+ (void)android::base::UTF8ToWide(to_print, &to_print_wide);
// We don't want to have the cursor spamming back and forth, so instead of
// printf use WriteConsoleOutput which updates the contents of the buffer,
// but doesn't move the cursor position.
@@ -100,12 +103,10 @@
};
vector<CHAR_INFO> char_data(csbi.dwSize.X);
for (size_t i = 0; i < static_cast<size_t>(csbi.dwSize.X); ++i) {
- // TODO: UnicodeChar instead of AsciiChar, to_print_wide[i].
- char_data[i].Char.AsciiChar = i < to_print.size() ? to_print[i] : ' ';
- char_data[i].Attributes = csbi.wAttributes;
+ char_data[i].Char.UnicodeChar = i < to_print_wide.size() ? to_print_wide[i] : L' ';
+ char_data[i].Attributes = csbi.wAttributes;
}
- // TODO: WriteConsoleOutputW.
- WriteConsoleOutput(console_, &char_data[0], buf_size, zero_zero, &target);
+ WriteConsoleOutputW(console_, &char_data[0], buf_size, zero_zero, &target);
#else
// Limit output to width of the terminal if provided so we don't cause
// line-wrapping.
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index 180df8f..1800f84 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -67,7 +67,7 @@
// b64_pton requires one additional byte in the target buffer for
// decoding to succeed. See http://b/28035006 for details.
uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
- if (__b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
+ if (b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
LOG(ERROR) << "Invalid base64 key " << line.c_str() << " in " << path;
continue;
}
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index d55096a..62c18c5 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -22,13 +22,11 @@
#include <dirent.h>
#include <errno.h>
-#include <linux/xattr.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/xattr.h>
#include <unistd.h>
#include <utime.h>
@@ -37,11 +35,17 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
+
+#if defined(__ANDROID__)
#include <selinux/android.h>
+#include <sys/xattr.h>
+#endif
#include "adb.h"
#include "adb_io.h"
@@ -55,11 +59,17 @@
using android::base::StringPrintf;
static bool should_use_fs_config(const std::string& path) {
+#if defined(__ANDROID__)
// TODO: use fs_config to configure permissions on /data too.
return !android::base::StartsWith(path, "/data/");
+#else
+ UNUSED(path);
+ return false;
+#endif
}
static bool update_capabilities(const char* path, uint64_t capabilities) {
+#if defined(__ANDROID__)
if (capabilities == 0) {
// Ensure we clean up in case the capabilities weren't 0 in the past.
removexattr(path, XATTR_NAME_CAPS);
@@ -73,6 +83,10 @@
cap_data.data[1].permitted = (capabilities >> 32);
cap_data.data[1].inheritable = 0;
return setxattr(path, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) != -1;
+#else
+ UNUSED(path, capabilities);
+ return true;
+#endif
}
static bool secure_mkdirs(const std::string& path) {
@@ -105,8 +119,10 @@
} else {
if (chown(partial_path.c_str(), uid, gid) == -1) return false;
+#if defined(__ANDROID__)
// Not all filesystems support setting SELinux labels. http://b/23530370.
selinux_android_restorecon(partial_path.c_str(), 0);
+#endif
if (!update_capabilities(partial_path.c_str(), capabilities)) return false;
}
@@ -242,8 +258,10 @@
goto fail;
}
+#if defined(__ANDROID__)
// Not all filesystems support setting SELinux labels. http://b/23530370.
selinux_android_restorecon(path, 0);
+#endif
// fchown clears the setuid bit - restore it if present.
// Ignore the result of calling fchmod. It's not supported
diff --git a/adb/daemon/framebuffer_service.h b/adb/daemon/framebuffer_service.h
index 264da59..bab44be 100644
--- a/adb/daemon/framebuffer_service.h
+++ b/adb/daemon/framebuffer_service.h
@@ -18,4 +18,6 @@
#include "adb_unique_fd.h"
+#if defined(__ANDROID__)
void framebuffer_service(unique_fd fd);
+#endif
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index f6f1acc..fce3a4f 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -18,7 +18,10 @@
#include "sysdeps.h"
+#if defined(__BIONIC__)
#include <android/fdsan.h>
+#endif
+
#include <errno.h>
#include <getopt.h>
#include <malloc.h>
@@ -34,12 +37,15 @@
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+
+#if defined(__ANDROID__)
#include <libminijail.h>
#include <log/log_properties.h>
#include <scoped_minijail.h>
#include <private/android_filesystem_config.h>
#include "selinux/android.h"
+#endif
#include "adb.h"
#include "adb_auth.h"
@@ -49,6 +55,7 @@
#include "mdns.h"
+#if defined(__ANDROID__)
static const char* root_seclabel = nullptr;
static bool should_drop_capabilities_bounding_set() {
@@ -167,10 +174,14 @@
}
}
}
+#endif
static void setup_port(int port) {
+ LOG(INFO) << "adbd listening on port " << port;
local_init(port);
+#if defined(__ANDROID__)
setup_mdns(port);
+#endif
}
int adbd_main(int server_port) {
@@ -178,10 +189,12 @@
signal(SIGPIPE, SIG_IGN);
+#if defined(__BIONIC__)
auto fdsan_level = android_fdsan_get_error_level();
if (fdsan_level == ANDROID_FDSAN_ERROR_LEVEL_DISABLED) {
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
}
+#endif
init_transport_registration();
@@ -206,14 +219,19 @@
" unchanged.\n");
}
+#if defined(__ANDROID__)
drop_privileges(server_port);
+#endif
bool is_usb = false;
+
+#if defined(__ANDROID__)
if (access(USB_FFS_ADB_EP0, F_OK) == 0) {
// Listen on USB.
usb_init();
is_usb = true;
}
+#endif
// If one of these properties is set, also listen on that port.
// If one of the properties isn't set and we couldn't listen on usb, listen
@@ -244,8 +262,10 @@
}
int main(int argc, char** argv) {
+#if defined(__BIONIC__)
// Set M_DECAY_TIME so that our allocations aren't immediately purged on free.
mallopt(M_DECAY_TIME, 1);
+#endif
while (true) {
static struct option opts[] = {
@@ -261,19 +281,21 @@
}
switch (c) {
- case 's':
- root_seclabel = optarg;
- break;
- case 'b':
- adb_device_banner = optarg;
- break;
- case 'v':
- printf("Android Debug Bridge Daemon version %d.%d.%d\n", ADB_VERSION_MAJOR,
- ADB_VERSION_MINOR, ADB_SERVER_VERSION);
- return 0;
- default:
- // getopt already prints "adbd: invalid option -- %c" for us.
- return 1;
+#if defined(__ANDROID__)
+ case 's':
+ root_seclabel = optarg;
+ break;
+#endif
+ case 'b':
+ adb_device_banner = optarg;
+ break;
+ case 'v':
+ printf("Android Debug Bridge Daemon version %d.%d.%d\n", ADB_VERSION_MAJOR,
+ ADB_VERSION_MINOR, ADB_SERVER_VERSION);
+ return 0;
+ default:
+ // getopt already prints "adbd: invalid option -- %c" for us.
+ return 1;
}
}
diff --git a/adb/daemon/reboot_service.cpp b/adb/daemon/reboot_service.cpp
new file mode 100644
index 0000000..a5a11b8
--- /dev/null
+++ b/adb/daemon/reboot_service.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TRACE_TAG SERVICES
+
+#include "sysdeps.h"
+
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <bootloader_message/bootloader_message.h>
+#include <cutils/android_reboot.h>
+
+#include "adb_io.h"
+#include "adb_unique_fd.h"
+
+void reboot_service(unique_fd fd, const std::string& arg) {
+ std::string reboot_arg = arg;
+ sync();
+
+ if (reboot_arg.empty()) reboot_arg = "adb";
+ std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
+
+ if (reboot_arg == "fastboot" &&
+ android::base::GetBoolProperty("ro.boot.dynamic_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
+ * fastboot.
+ */
+ android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
+ if (sock < 0) {
+ WriteFdFmt(fd, "reboot (%s) create\n", strerror(errno));
+ PLOG(ERROR) << "Creating recovery socket failed";
+ return;
+ }
+
+ sockaddr_un addr = {.sun_family = AF_UNIX};
+ strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
+ if (connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
+ WriteFdFmt(fd, "reboot (%s) connect\n", strerror(errno));
+ PLOG(ERROR) << "Couldn't connect to recovery socket";
+ return;
+ }
+ const char msg_switch_to_fastboot = 'f';
+ auto ret = adb_write(sock, &msg_switch_to_fastboot, sizeof(msg_switch_to_fastboot));
+ if (ret != sizeof(msg_switch_to_fastboot)) {
+ WriteFdFmt(fd, "reboot (%s) write\n", strerror(errno));
+ PLOG(ERROR) << "Couldn't write message to recovery socket to switch to fastboot";
+ return;
+ }
+ } else {
+ if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
+ WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str());
+ return;
+ }
+ }
+ // Don't return early. Give the reboot command time to take effect
+ // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
+ while (true) {
+ pause();
+ }
+}
diff --git a/adb/daemon/reboot_service.h b/adb/daemon/reboot_service.h
new file mode 100644
index 0000000..f68913e
--- /dev/null
+++ b/adb/daemon/reboot_service.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include "adb_unique_fd.h"
+
+#if defined(__ANDROID__)
+void reboot_service(unique_fd fd, const std::string& arg);
+#endif
diff --git a/adb/daemon/remount_service.h b/adb/daemon/remount_service.h
index e4e2550..c847403 100644
--- a/adb/daemon/remount_service.h
+++ b/adb/daemon/remount_service.h
@@ -20,5 +20,7 @@
#include "adb_unique_fd.h"
+#if defined(__ANDROID__)
bool make_block_device_writable(const std::string&);
void remount_service(unique_fd, const std::string&);
+#endif
diff --git a/adb/daemon/restart_service.cpp b/adb/daemon/restart_service.cpp
new file mode 100644
index 0000000..6803d93
--- /dev/null
+++ b/adb/daemon/restart_service.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TRACE_TAG SERVICES
+
+#include "sysdeps.h"
+
+#include <unistd.h>
+
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <log/log_properties.h>
+
+#include "adb_io.h"
+#include "adb_unique_fd.h"
+
+void restart_root_service(unique_fd fd) {
+ if (getuid() == 0) {
+ WriteFdExactly(fd.get(), "adbd is already running as root\n");
+ return;
+ }
+ if (!__android_log_is_debuggable()) {
+ WriteFdExactly(fd.get(), "adbd cannot run as root in production builds\n");
+ return;
+ }
+
+ android::base::SetProperty("service.adb.root", "1");
+ WriteFdExactly(fd.get(), "restarting adbd as root\n");
+}
+
+void restart_unroot_service(unique_fd fd) {
+ if (getuid() != 0) {
+ WriteFdExactly(fd.get(), "adbd not running as root\n");
+ return;
+ }
+ android::base::SetProperty("service.adb.root", "0");
+ WriteFdExactly(fd.get(), "restarting adbd as non root\n");
+}
+
+void restart_tcp_service(unique_fd fd, int port) {
+ if (port <= 0) {
+ WriteFdFmt(fd.get(), "invalid port %d\n", port);
+ return;
+ }
+
+ android::base::SetProperty("service.adb.tcp.port", android::base::StringPrintf("%d", port));
+ WriteFdFmt(fd.get(), "restarting in TCP mode port: %d\n", port);
+}
+
+void restart_usb_service(unique_fd fd) {
+ android::base::SetProperty("service.adb.tcp.port", "0");
+ WriteFdExactly(fd.get(), "restarting in USB mode\n");
+}
diff --git a/adb/daemon/restart_service.h b/adb/daemon/restart_service.h
new file mode 100644
index 0000000..19840bd
--- /dev/null
+++ b/adb/daemon/restart_service.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include "adb_unique_fd.h"
+
+#if defined(__ANDROID__)
+void restart_root_service(unique_fd fd);
+void restart_unroot_service(unique_fd fd);
+void restart_tcp_service(unique_fd fd, int port);
+void restart_usb_service(unique_fd fd);
+#endif
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 5ae210f..d1f0345 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -39,8 +39,6 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <bootloader_message/bootloader_message.h>
-#include <cutils/android_reboot.h>
#include <cutils/sockets.h>
#include <log/log_properties.h>
@@ -55,96 +53,12 @@
#include "daemon/file_sync_service.h"
#include "daemon/framebuffer_service.h"
+#include "daemon/reboot_service.h"
#include "daemon/remount_service.h"
+#include "daemon/restart_service.h"
#include "daemon/set_verity_enable_state_service.h"
#include "daemon/shell_service.h"
-void restart_root_service(unique_fd fd) {
- if (getuid() == 0) {
- WriteFdExactly(fd.get(), "adbd is already running as root\n");
- return;
- }
- if (!__android_log_is_debuggable()) {
- WriteFdExactly(fd.get(), "adbd cannot run as root in production builds\n");
- return;
- }
-
- android::base::SetProperty("service.adb.root", "1");
- WriteFdExactly(fd.get(), "restarting adbd as root\n");
-}
-
-void restart_unroot_service(unique_fd fd) {
- if (getuid() != 0) {
- WriteFdExactly(fd.get(), "adbd not running as root\n");
- return;
- }
- android::base::SetProperty("service.adb.root", "0");
- WriteFdExactly(fd.get(), "restarting adbd as non root\n");
-}
-
-void restart_tcp_service(unique_fd fd, int port) {
- if (port <= 0) {
- WriteFdFmt(fd.get(), "invalid port %d\n", port);
- return;
- }
-
- android::base::SetProperty("service.adb.tcp.port", android::base::StringPrintf("%d", port));
- WriteFdFmt(fd.get(), "restarting in TCP mode port: %d\n", port);
-}
-
-void restart_usb_service(unique_fd fd) {
- android::base::SetProperty("service.adb.tcp.port", "0");
- WriteFdExactly(fd.get(), "restarting in USB mode\n");
-}
-
-void reboot_service(unique_fd fd, const std::string& arg) {
- std::string reboot_arg = arg;
- sync();
-
- if (reboot_arg.empty()) reboot_arg = "adb";
- std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
-
- if (reboot_arg == "fastboot" &&
- android::base::GetBoolProperty("ro.boot.dynamic_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
- * fastboot.
- */
- android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
- if (sock < 0) {
- WriteFdFmt(fd, "reboot (%s) create\n", strerror(errno));
- PLOG(ERROR) << "Creating recovery socket failed";
- return;
- }
-
- sockaddr_un addr = {.sun_family = AF_UNIX};
- strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
- if (connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
- WriteFdFmt(fd, "reboot (%s) connect\n", strerror(errno));
- PLOG(ERROR) << "Couldn't connect to recovery socket";
- return;
- }
- const char msg_switch_to_fastboot = 'f';
- auto ret = adb_write(sock, &msg_switch_to_fastboot, sizeof(msg_switch_to_fastboot));
- if (ret != sizeof(msg_switch_to_fastboot)) {
- WriteFdFmt(fd, "reboot (%s) write\n", strerror(errno));
- PLOG(ERROR) << "Couldn't write message to recovery socket to switch to fastboot";
- return;
- }
- } else {
- if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
- WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str());
- return;
- }
- }
- // Don't return early. Give the reboot command time to take effect
- // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
- while (true) {
- pause();
- }
-}
void reconnect_service(unique_fd fd, atransport* t) {
WriteFdExactly(fd.get(), "done");
@@ -221,7 +135,8 @@
}
fdevent_run_on_main_thread([fd = pipe_read.release()]() {
- fdevent* fde = fdevent_create(fd, [](int, unsigned, void*) {}, nullptr);
+ fdevent* fde = fdevent_create(
+ fd, [](int, unsigned, void*) {}, nullptr);
fdevent_add(fde, FDE_READ);
});
@@ -328,31 +243,16 @@
}
unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
-#ifndef __ANDROID_RECOVERY__
+#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
if (name.starts_with("abb:")) {
name.remove_prefix(strlen("abb:"));
return execute_binder_command(name);
}
#endif
- if (name.starts_with("dev:")) {
- name.remove_prefix(strlen("dev:"));
- return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)};
- } else if (name.starts_with("framebuffer:")) {
+#if defined(__ANDROID__)
+ if (name.starts_with("framebuffer:")) {
return create_service_thread("fb", framebuffer_service);
- } else if (name.starts_with("jdwp:")) {
- name.remove_prefix(strlen("jdwp:"));
- std::string str(name);
- return create_jdwp_connection_fd(atoi(str.c_str()));
- } else if (name.starts_with("shell")) {
- name.remove_prefix(strlen("shell"));
- return ShellService(name, transport);
- } else if (name.starts_with("exec:")) {
- name.remove_prefix(strlen("exec:"));
- return StartSubprocess(std::string(name), nullptr, SubprocessType::kRaw,
- SubprocessProtocol::kNone);
- } else if (name.starts_with("sync:")) {
- return create_service_thread("sync", file_sync_service);
} else if (name.starts_with("remount:")) {
std::string arg(name.begin() + strlen("remount:"), name.end());
return create_service_thread("remount",
@@ -373,6 +273,12 @@
} else if (name.starts_with("restore:")) {
return StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw,
SubprocessProtocol::kNone);
+ } else if (name.starts_with("disable-verity:")) {
+ return create_service_thread("verity-on", std::bind(set_verity_enabled_state_service,
+ std::placeholders::_1, false));
+ } else if (name.starts_with("enable-verity:")) {
+ return create_service_thread("verity-off", std::bind(set_verity_enabled_state_service,
+ std::placeholders::_1, true));
} else if (name.starts_with("tcpip:")) {
name.remove_prefix(strlen("tcpip:"));
std::string str(name);
@@ -385,15 +291,28 @@
std::bind(restart_tcp_service, std::placeholders::_1, port));
} else if (name.starts_with("usb:")) {
return create_service_thread("usb", restart_usb_service);
+ }
+#endif
+
+ if (name.starts_with("dev:")) {
+ name.remove_prefix(strlen("dev:"));
+ return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)};
+ } else if (name.starts_with("jdwp:")) {
+ name.remove_prefix(strlen("jdwp:"));
+ std::string str(name);
+ return create_jdwp_connection_fd(atoi(str.c_str()));
+ } else if (name.starts_with("shell")) {
+ name.remove_prefix(strlen("shell"));
+ return ShellService(name, transport);
+ } else if (name.starts_with("exec:")) {
+ name.remove_prefix(strlen("exec:"));
+ return StartSubprocess(std::string(name), nullptr, SubprocessType::kRaw,
+ SubprocessProtocol::kNone);
+ } else if (name.starts_with("sync:")) {
+ return create_service_thread("sync", file_sync_service);
} else if (name.starts_with("reverse:")) {
name.remove_prefix(strlen("reverse:"));
return reverse_service(name, transport);
- } else if (name.starts_with("disable-verity:")) {
- return create_service_thread("verity-on", std::bind(set_verity_enabled_state_service,
- std::placeholders::_1, false));
- } else if (name.starts_with("enable-verity:")) {
- return create_service_thread("verity-off", std::bind(set_verity_enabled_state_service,
- std::placeholders::_1, true));
} else if (name == "reconnect") {
return create_service_thread(
"reconnect", std::bind(reconnect_service, std::placeholders::_1, transport));
diff --git a/adb/daemon/set_verity_enable_state_service.h b/adb/daemon/set_verity_enable_state_service.h
index c1413c8..c0ed98e 100644
--- a/adb/daemon/set_verity_enable_state_service.h
+++ b/adb/daemon/set_verity_enable_state_service.h
@@ -18,4 +18,6 @@
#include "adb_unique_fd.h"
+#if defined(__ANDROID__)
void set_verity_enabled_state_service(unique_fd fd, bool enable);
+#endif
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index 455595f..0794bcd 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -98,7 +98,10 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <private/android_logger.h>
+
+#if defined(__ANDROID__)
#include <selinux/android.h>
+#endif
#include "adb.h"
#include "adb_io.h"
diff --git a/adb/daemon/transport_qemu.cpp b/adb/daemon/transport_qemu.cpp
new file mode 100644
index 0000000..8ad2572
--- /dev/null
+++ b/adb/daemon/transport_qemu.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2019 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 qemu_pipe.h before sysdeps, since it has inlined references to open, read, write.
+#include <qemu_pipe.h>
+
+#define TRACE_TAG TRANSPORT
+#include "sysdeps.h"
+#include "transport.h"
+
+#include <android-base/properties.h>
+
+#include "adb_io.h"
+#include "adb_trace.h"
+#include "adb_unique_fd.h"
+
+/* A worker thread that monitors host connections, and registers a transport for
+ * every new host connection. This thread replaces server_socket_thread on
+ * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD
+ * pipe to communicate with adbd daemon inside the guest. This is done in order
+ * to provide more robust communication channel between ADB host and guest. The
+ * main issue with server_socket_thread approach is that it runs on top of TCP,
+ * and thus is sensitive to network disruptions. For instance, the
+ * ConnectionManager may decide to reset all network connections, in which case
+ * the connection between ADB host and guest will be lost. To make ADB traffic
+ * independent from the network, we use here 'adb' QEMUD service to transfer data
+ * between the host, and the guest. See external/qemu/android/adb-*.* that
+ * implements the emulator's side of the protocol. Another advantage of using
+ * QEMUD approach is that ADB will be up much sooner, since it doesn't depend
+ * anymore on network being set up.
+ * The guest side of the protocol contains the following phases:
+ * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service
+ * is opened, and it becomes clear whether or not emulator supports that
+ * protocol.
+ * - Wait for the ADB host to create connection with the guest. This is done by
+ * sending an 'accept' request to the adb QEMUD service, and waiting on
+ * response.
+ * - When new ADB host connection is accepted, the connection with adb QEMUD
+ * service is registered as the transport, and a 'start' request is sent to the
+ * adb QEMUD service, indicating that the guest is ready to receive messages.
+ * Note that the guest will ignore messages sent down from the emulator before
+ * the transport registration is completed. That's why we need to send the
+ * 'start' request after the transport is registered.
+ */
+void qemu_socket_thread(int port) {
+ /* 'accept' request to the adb QEMUD service. */
+ static const char _accept_req[] = "accept";
+ /* 'start' request to the adb QEMUD service. */
+ static const char _start_req[] = "start";
+ /* 'ok' reply from the adb QEMUD service. */
+ static const char _ok_resp[] = "ok";
+
+ char tmp[256];
+ char con_name[32];
+
+ adb_thread_setname("qemu socket");
+ D("transport: qemu_socket_thread() starting");
+
+ /* adb QEMUD service connection request. */
+ snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port);
+
+ /* Connect to the adb QEMUD service. */
+ unique_fd fd(qemu_pipe_open(con_name));
+ if (fd < 0) {
+ /* This could be an older version of the emulator, that doesn't
+ * implement adb QEMUD service. Fall back to the old TCP way. */
+ D("adb service is not available. Falling back to TCP socket.");
+ std::thread(server_socket_thread, port).detach();
+ return;
+ }
+
+ while (true) {
+ /*
+ * Wait till the host creates a new connection.
+ */
+
+ /* Send the 'accept' request. */
+ if (WriteFdExactly(fd.get(), _accept_req, strlen(_accept_req))) {
+ /* Wait for the response. In the response we expect 'ok' on success,
+ * or 'ko' on failure. */
+ if (!ReadFdExactly(fd.get(), tmp, 2) || memcmp(tmp, _ok_resp, 2)) {
+ D("Accepting ADB host connection has failed.");
+ } else {
+ /* Host is connected. Register the transport, and start the
+ * exchange. */
+ std::string serial = android::base::StringPrintf("host-%d", fd.get());
+ WriteFdExactly(fd.get(), _start_req, strlen(_start_req));
+ register_socket_transport(std::move(fd), std::move(serial), port, 1,
+ [](atransport*) { return ReconnectResult::Abort; });
+ }
+
+ /* Prepare for accepting of the next ADB host connection. */
+ fd.reset(qemu_pipe_open(con_name));
+ if (fd < 0) {
+ D("adb service become unavailable.");
+ return;
+ }
+ } else {
+ D("Unable to send the '%s' request to ADB service.", _accept_req);
+ return;
+ }
+ }
+ D("transport: qemu_socket_thread() exiting");
+ return;
+}
+
+// If adbd is running inside the emulator, it will normally use QEMUD pipe (aka
+// goldfish) as the transport. This can either be explicitly set by the
+// service.adb.transport property, or be inferred from ro.kernel.qemu that is
+// set to "1" for ranchu/goldfish.
+bool use_qemu_goldfish() {
+ // Legacy way to detect if adbd should use the goldfish pipe is to check for
+ // ro.kernel.qemu, keep that behaviour for backward compatibility.
+ if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
+ return true;
+ }
+ // If service.adb.transport is present and is set to "goldfish", use the
+ // QEMUD pipe.
+ if (android::base::GetProperty("service.adb.transport", "") == "goldfish") {
+ return true;
+ }
+ return false;
+}
diff --git a/adb/daemon/usb_dummy.cpp b/adb/daemon/usb_dummy.cpp
new file mode 100644
index 0000000..984bc25
--- /dev/null
+++ b/adb/daemon/usb_dummy.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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 <adbd/usb.h>
+
+#include <android-base/logging.h>
+
+int usb_write(usb_handle*, const void*, int) {
+ LOG(FATAL) << "unimplemented";
+ return -1;
+}
+
+int usb_read(usb_handle*, void*, int) {
+ LOG(FATAL) << "unimplemented";
+ return -1;
+}
+
+int usb_close(usb_handle*) {
+ LOG(FATAL) << "unimplemented";
+ return -1;
+}
+
+void usb_kick(usb_handle*) {
+ LOG(FATAL) << "unimplemented";
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index dbc8920..d587589 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -719,7 +719,7 @@
/**************************************************************************/
/**************************************************************************/
-static int _init_winsock(void) {
+static void _init_winsock() {
static std::once_flag once;
std::call_once(once, []() {
WSADATA wsaData;
@@ -743,11 +743,8 @@
// crypt32.dll which calls atexit() which tries to acquire the C
// Runtime lock that the other thread holds.
});
- return 0;
}
-static int _winsock_init = _init_winsock();
-
// Map a socket type to an explicit socket protocol instead of using the socket
// protocol of 0. Explicit socket protocols are used by most apps and we should
// do the same to reduce the chance of exercising uncommon code-paths that might
@@ -2621,14 +2618,13 @@
}
// Shadow UTF-8 environment variable name/value pairs that are created from
-// _wenviron the first time that adb_getenv() is called. Note that this is not
-// currently updated if putenv, setenv, unsetenv are called. Note that no
-// thread synchronization is done, but we're called early enough in
+// _wenviron by _init_env(). Note that this is not currently updated if putenv, setenv, unsetenv are
+// called. Note that no thread synchronization is done, but we're called early enough in
// single-threaded startup that things work ok.
static auto& g_environ_utf8 = *new std::unordered_map<std::string, char*>();
-// Make sure that shadow UTF-8 environment variables are setup.
-static void _ensure_env_setup() {
+// Setup shadow UTF-8 environment variables.
+static void _init_env() {
// If some name/value pairs exist, then we've already done the setup below.
if (g_environ_utf8.size() != 0) {
return;
@@ -2681,8 +2677,6 @@
// Version of getenv() that takes a UTF-8 environment variable name and
// retrieves a UTF-8 value. Case-insensitive to match getenv() on Windows.
char* adb_getenv(const char* name) {
- _ensure_env_setup();
-
// Case-insensitive search by searching for lowercase name in a map of
// lowercase names.
const auto it = g_environ_utf8.find(ToLower(std::string(name)));
@@ -2757,3 +2751,65 @@
return 0;
}
+
+#if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+#endif
+
+#if !defined(DISABLE_NEWLINE_AUTO_RETURN)
+#define DISABLE_NEWLINE_AUTO_RETURN 0x0008
+#endif
+
+static void _init_console() {
+ DWORD old_out_console_mode;
+
+ const HANDLE out = _get_console_handle(STDOUT_FILENO, &old_out_console_mode);
+ if (out == nullptr) {
+ return;
+ }
+
+ // Try to use ENABLE_VIRTUAL_TERMINAL_PROCESSING on the output console to process virtual
+ // terminal sequences on newer versions of Windows 10 and later.
+ // https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
+ // On older OSes that don't support the flag, SetConsoleMode() will return an error.
+ // ENABLE_VIRTUAL_TERMINAL_PROCESSING also solves a problem where the last column of the
+ // console cannot be overwritten.
+ //
+ // Note that we don't use DISABLE_NEWLINE_AUTO_RETURN because it doesn't seem to be necessary.
+ // If we use DISABLE_NEWLINE_AUTO_RETURN, _console_write_utf8() would need to be modified to
+ // translate \n to \r\n.
+ if (!SetConsoleMode(out, old_out_console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
+ return;
+ }
+
+ // If SetConsoleMode() succeeded, the console supports virtual terminal processing, so we
+ // should set the TERM env var to match so that it will be propagated to adbd on devices.
+ //
+ // Below's direct manipulation of env vars and not g_environ_utf8 assumes that _init_env() has
+ // not yet been called. If this fails, _init_env() should be called after _init_console().
+ if (g_environ_utf8.size() > 0) {
+ LOG(FATAL) << "environment variables have already been converted to UTF-8";
+ }
+
+#pragma push_macro("getenv")
+#undef getenv
+#pragma push_macro("putenv")
+#undef putenv
+ if (getenv("TERM") == nullptr) {
+ // This is the same TERM value used by Gnome Terminal and the version of ssh included with
+ // Windows.
+ putenv("TERM=xterm-256color");
+ }
+#pragma pop_macro("putenv")
+#pragma pop_macro("getenv")
+}
+
+static bool _init_sysdeps() {
+ // _init_console() depends on _init_env() not being called yet.
+ _init_console();
+ _init_env();
+ _init_winsock();
+ return true;
+}
+
+static bool _sysdeps_init = _init_sysdeps();
diff --git a/adb/transport.h b/adb/transport.h
index 6f53e6ec..3baeb1c 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -399,4 +399,14 @@
asocket* create_device_tracker(bool long_output);
+#if !ADB_HOST
+void server_socket_thread(int port);
+
+#if defined(__ANDROID__)
+void qemu_socket_thread(int port);
+bool use_qemu_goldfish();
+#endif
+
+#endif
+
#endif /* __TRANSPORT_H */
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index b384085..8885db4 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -229,9 +229,9 @@
}
}
-#else // ADB_HOST
+#else // !ADB_HOST
-static void server_socket_thread(int port) {
+void server_socket_thread(int port) {
unique_fd serverfd;
adb_thread_setname("server socket");
@@ -263,143 +263,19 @@
D("transport: server_socket_thread() exiting");
}
-/* This is relevant only for ADB daemon running inside the emulator. */
-/*
- * Redefine open and write for qemu_pipe.h that contains inlined references
- * to those routines. We will redefine them back after qemu_pipe.h inclusion.
- */
-#undef open
-#undef read
-#undef write
-#define open adb_open
-#define read adb_read
-#define write adb_write
-#include <qemu_pipe.h>
-#undef open
-#undef read
-#undef write
-#define open ___xxx_open
-#define read ___xxx_read
-#define write ___xxx_write
+#endif
-/* A worker thread that monitors host connections, and registers a transport for
- * every new host connection. This thread replaces server_socket_thread on
- * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD
- * pipe to communicate with adbd daemon inside the guest. This is done in order
- * to provide more robust communication channel between ADB host and guest. The
- * main issue with server_socket_thread approach is that it runs on top of TCP,
- * and thus is sensitive to network disruptions. For instance, the
- * ConnectionManager may decide to reset all network connections, in which case
- * the connection between ADB host and guest will be lost. To make ADB traffic
- * independent from the network, we use here 'adb' QEMUD service to transfer data
- * between the host, and the guest. See external/qemu/android/adb-*.* that
- * implements the emulator's side of the protocol. Another advantage of using
- * QEMUD approach is that ADB will be up much sooner, since it doesn't depend
- * anymore on network being set up.
- * The guest side of the protocol contains the following phases:
- * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service
- * is opened, and it becomes clear whether or not emulator supports that
- * protocol.
- * - Wait for the ADB host to create connection with the guest. This is done by
- * sending an 'accept' request to the adb QEMUD service, and waiting on
- * response.
- * - When new ADB host connection is accepted, the connection with adb QEMUD
- * service is registered as the transport, and a 'start' request is sent to the
- * adb QEMUD service, indicating that the guest is ready to receive messages.
- * Note that the guest will ignore messages sent down from the emulator before
- * the transport registration is completed. That's why we need to send the
- * 'start' request after the transport is registered.
- */
-static void qemu_socket_thread(int port) {
- /* 'accept' request to the adb QEMUD service. */
- static const char _accept_req[] = "accept";
- /* 'start' request to the adb QEMUD service. */
- static const char _start_req[] = "start";
- /* 'ok' reply from the adb QEMUD service. */
- static const char _ok_resp[] = "ok";
-
- char tmp[256];
- char con_name[32];
-
- adb_thread_setname("qemu socket");
- D("transport: qemu_socket_thread() starting");
-
- /* adb QEMUD service connection request. */
- snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port);
-
- /* Connect to the adb QEMUD service. */
- unique_fd fd(qemu_pipe_open(con_name));
- if (fd < 0) {
- /* This could be an older version of the emulator, that doesn't
- * implement adb QEMUD service. Fall back to the old TCP way. */
- D("adb service is not available. Falling back to TCP socket.");
- std::thread(server_socket_thread, port).detach();
- return;
- }
-
- while (true) {
- /*
- * Wait till the host creates a new connection.
- */
-
- /* Send the 'accept' request. */
- if (WriteFdExactly(fd.get(), _accept_req, strlen(_accept_req))) {
- /* Wait for the response. In the response we expect 'ok' on success,
- * or 'ko' on failure. */
- if (!ReadFdExactly(fd.get(), tmp, 2) || memcmp(tmp, _ok_resp, 2)) {
- D("Accepting ADB host connection has failed.");
- } else {
- /* Host is connected. Register the transport, and start the
- * exchange. */
- std::string serial = android::base::StringPrintf("host-%d", fd.get());
- WriteFdExactly(fd.get(), _start_req, strlen(_start_req));
- register_socket_transport(std::move(fd), std::move(serial), port, 1,
- [](atransport*) { return ReconnectResult::Abort; });
- }
-
- /* Prepare for accepting of the next ADB host connection. */
- fd.reset(qemu_pipe_open(con_name));
- if (fd < 0) {
- D("adb service become unavailable.");
- return;
- }
- } else {
- D("Unable to send the '%s' request to ADB service.", _accept_req);
- return;
- }
- }
- D("transport: qemu_socket_thread() exiting");
- return;
-}
-
-// If adbd is running inside the emulator, it will normally use QEMUD pipe (aka
-// goldfish) as the transport. This can either be explicitly set by the
-// service.adb.transport property, or be inferred from ro.kernel.qemu that is
-// set to "1" for ranchu/goldfish.
-static bool use_qemu_goldfish() {
- // Legacy way to detect if adbd should use the goldfish pipe is to check for
- // ro.kernel.qemu, keep that behaviour for backward compatibility.
- if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
- return true;
- }
- // If service.adb.transport is present and is set to "goldfish", use the
- // QEMUD pipe.
- if (android::base::GetProperty("service.adb.transport", "") == "goldfish") {
- return true;
- }
- return false;
-}
-
-#endif // !ADB_HOST
-
-void local_init(int port)
-{
+void local_init(int port) {
void (*func)(int);
const char* debug_name = "";
#if ADB_HOST
func = client_socket_thread;
debug_name = "client";
+#elif !defined(__ANDROID__)
+ // Host adbd.
+ func = server_socket_thread;
+ debug_name = "server";
#else
// For the adbd daemon in the system image we need to distinguish
// between the device, and the emulator.
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 0f89467..2c4299a 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -137,9 +137,9 @@
bool fs_mgr_overlayfs_enabled(FstabEntry* entry) {
// readonly filesystem, can not be mount -o remount,rw
- // if squashfs or if free space is (near) zero making such a remount
+ // for squashfs, erofs or if free space is (near) zero making such a remount
// virtually useless, or if there are shared blocks that prevent remount,rw
- if ("squashfs" == entry->fs_type || !fs_mgr_filesystem_has_space(entry->mount_point)) {
+ if (!fs_mgr_filesystem_has_space(entry->mount_point)) {
return true;
}
if (entry->fs_mgr_flags.logical) {
@@ -626,8 +626,8 @@
// Only a suggestion for _first_ try during mounting
std::string fs_mgr_overlayfs_scratch_mount_type() {
- if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs";
- if (!access(kMkExt4.c_str(), X_OK)) return "ext4";
+ if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_access("/sys/fs/f2fs")) return "f2fs";
+ if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_access("/sys/fs/ext4")) return "ext4";
return "auto";
}
@@ -642,7 +642,11 @@
// Create from within single super device;
auto& dm = DeviceMapper::Instance();
const auto partition_name = android::base::Basename(kScratchMountPoint);
- if (!dm.GetDmDevicePathByName(partition_name, &path)) return "";
+ if (!dm.GetDmDevicePathByName(partition_name, &path)) {
+ // non-DAP A/B device?
+ if (fs_mgr_access(super_device)) return "";
+ path = kPhysicalDevice + "system" + (slot_number ? "_a" : "_b");
+ }
}
return scratch_device_cache = path;
}
@@ -829,8 +833,9 @@
true /* readonly */)) {
auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir);
fs_mgr_overlayfs_umount_scratch();
- if (has_overlayfs_dir)
+ if (has_overlayfs_dir) {
fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type);
+ }
}
}
}
@@ -882,10 +887,6 @@
for (const auto& overlay_mount_point : kOverlayMountPoints) {
if (backing && backing[0] && (overlay_mount_point != backing)) continue;
if (overlay_mount_point == kScratchMountPoint) {
- if (!fs_mgr_rw_access(fs_mgr_overlayfs_super_device(fs_mgr_overlayfs_slot_number())) ||
- !fs_mgr_overlayfs_has_logical(fstab)) {
- continue;
- }
if (!fs_mgr_overlayfs_setup_scratch(fstab, change)) continue;
} else {
if (std::find_if(fstab.begin(), fstab.end(), [&overlay_mount_point](const auto& entry) {
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 3cb718c..41cd7dd 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -34,6 +34,12 @@
return "";
}
+// Returns "_b" or "_a", which is *the other* slot of androidboot.slot_suffix
+// in kernel cmdline, or an empty string if that parameter does not exist.
+std::string fs_mgr_get_other_slot_suffix() {
+ return other_suffix(fs_mgr_get_slot_suffix());
+}
+
// Returns "_a" or "_b" based on androidboot.slot_suffix in kernel cmdline, or an empty string
// if that parameter does not exist.
std::string fs_mgr_get_slot_suffix() {
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 4a05949..38f96c0 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -98,6 +98,7 @@
int fs_mgr_is_fs_verity(const struct fstab_rec* fstab);
std::string fs_mgr_get_slot_suffix();
+std::string fs_mgr_get_other_slot_suffix();
std::set<std::string> fs_mgr_get_boot_devices();
struct FstabEntry {
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
index 164fc91..6ccdb57 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
@@ -359,6 +359,21 @@
return moved_blocks_nr == 0;
}
+bool FiemapWriter::HasPinnedExtents(const std::string& file_path) {
+ android::base::unique_fd fd(open(file_path.c_str(), O_NOFOLLOW | O_CLOEXEC | O_RDONLY));
+ if (fd < 0) {
+ PLOG(ERROR) << "open: " << file_path;
+ return false;
+ }
+
+ struct statfs64 sfs;
+ if (fstatfs64(fd, &sfs)) {
+ PLOG(ERROR) << "fstatfs64: " << file_path;
+ return false;
+ }
+ return IsFilePinned(fd, file_path, sfs.f_type);
+}
+
static void LogExtent(uint32_t num, const struct fiemap_extent& ext) {
LOG(INFO) << "Extent #" << num;
LOG(INFO) << " fe_logical: " << ext.fe_logical;
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
index 5101537..3d20ff3 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
@@ -51,6 +51,8 @@
testfile = ::android::base::StringPrintf("%s/testdata/%s", exec_dir.c_str(), tinfo->name());
}
+ void TearDown() override { unlink(testfile.c_str()); }
+
// name of the file we use for testing
std::string testfile;
};
@@ -102,6 +104,12 @@
EXPECT_EQ(invocations, 2);
}
+TEST_F(FiemapWriterTest, CheckPinning) {
+ auto ptr = FiemapWriter::Open(testfile, 4096);
+ ASSERT_NE(ptr, nullptr);
+ EXPECT_TRUE(FiemapWriter::HasPinnedExtents(testfile));
+}
+
TEST_F(FiemapWriterTest, CheckBlockDevicePath) {
FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 4096);
EXPECT_EQ(fptr->size(), 4096);
diff --git a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
index ab78f93..a0085cf 100644
--- a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
+++ b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
@@ -45,6 +45,18 @@
bool create = true,
std::function<bool(uint64_t, uint64_t)> progress = {});
+ // Check that a file still has the same extents since it was last opened with FiemapWriter,
+ // assuming the file was not resized outside of FiemapWriter. Returns false either on error
+ // or if the file was not pinned.
+ //
+ // This will always return true on Ext4. On F2FS, it will return true if either of the
+ // following cases are true:
+ // - The file was never pinned.
+ // - The file is pinned and has not been moved by the GC.
+ // Thus, this method should only be called for pinned files (such as those returned by
+ // FiemapWriter::Open).
+ static bool HasPinnedExtents(const std::string& file_path);
+
// Syncs block device writes.
bool Flush() const;
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index 6f368e4..191e803 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -56,6 +56,11 @@
"tests/data/*",
],
static_libs: [
+ "libavb",
+ "libavb_host_sysdeps",
+ "libdm",
+ "libfs_avb",
+ "libfstab",
"libgtest_host",
],
shared_libs: [
@@ -86,8 +91,12 @@
static_libs: [
"libfs_avb_test_util",
],
+ shared_libs: [
+ "libcrypto",
+ ],
srcs: [
"tests/basic_test.cpp",
+ "tests/fs_avb_test.cpp",
],
}
@@ -96,10 +105,11 @@
defaults: ["libfs_avb_host_test_defaults"],
static_libs: [
"libfs_avb_test_util",
- "libfstab",
],
srcs: [
+ "avb_util.cpp",
"util.cpp",
+ "tests/avb_util_test.cpp",
"tests/util_test.cpp",
],
}
diff --git a/fs_mgr/libfs_avb/avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp
index 3efa794..6a3e2c0 100644
--- a/fs_mgr/libfs_avb/avb_ops.cpp
+++ b/fs_mgr/libfs_avb/avb_ops.cpp
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+
#include <string>
#include <android-base/macros.h>
@@ -190,7 +191,8 @@
// Copies avb_slot_data->vbmeta_images[].
for (size_t i = 0; i < avb_slot_data->num_vbmeta_images; i++) {
out_vbmeta_images->emplace_back(VBMetaData(avb_slot_data->vbmeta_images[i].vbmeta_data,
- avb_slot_data->vbmeta_images[i].vbmeta_size));
+ avb_slot_data->vbmeta_images[i].vbmeta_size,
+ avb_slot_data->vbmeta_images[i].partition_name));
}
// Free the local resource.
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index 0ceb6ee..f57c9d6 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -16,19 +16,67 @@
#include "avb_util.h"
+#include <unistd.h>
+
#include <array>
#include <sstream>
#include <android-base/file.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include "util.h"
+using android::base::StartsWith;
using android::base::unique_fd;
namespace android {
namespace fs_mgr {
+// Helper functions to print enum class VBMetaVerifyResult.
+const char* VBMetaVerifyResultToString(VBMetaVerifyResult result) {
+ // clang-format off
+ static const char* const name[] = {
+ "ResultSuccess",
+ "ResultError",
+ "ResultErrorVerification",
+ "ResultUnknown",
+ };
+ // clang-format on
+
+ uint32_t index = static_cast<uint32_t>(result);
+ uint32_t unknown_index = sizeof(name) / sizeof(char*) - 1;
+ if (index >= unknown_index) {
+ index = unknown_index;
+ }
+
+ return name[index];
+}
+
+std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult result) {
+ os << VBMetaVerifyResultToString(result);
+ return os;
+}
+
+// class VBMetaData
+// ----------------
+std::unique_ptr<AvbVBMetaImageHeader> VBMetaData::GetVBMetaHeader(bool update_vbmeta_size) {
+ auto vbmeta_header(std::make_unique<AvbVBMetaImageHeader>());
+
+ if (!vbmeta_header) return nullptr;
+
+ /* Byteswap the header. */
+ avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_ptr_.get(),
+ vbmeta_header.get());
+ if (update_vbmeta_size) {
+ vbmeta_size_ = sizeof(AvbVBMetaImageHeader) +
+ vbmeta_header->authentication_data_block_size +
+ vbmeta_header->auxiliary_data_block_size;
+ }
+
+ return vbmeta_header;
+}
+
// Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel.
// See the following link for more details:
// https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
@@ -173,5 +221,300 @@
return true;
}
+// Converts a AVB partition_name (without A/B suffix) to a device partition name.
+// e.g., "system" => "system_a",
+// "system_other" => "system_b".
+//
+// If the device is non-A/B, converts it to a partition name without suffix.
+// e.g., "system" => "system",
+// "system_other" => "system".
+std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name,
+ const std::string& ab_suffix,
+ const std::string& ab_other_suffix) {
+ bool is_other_slot = false;
+ std::string sanitized_partition_name(avb_partition_name);
+
+ auto other_suffix = sanitized_partition_name.rfind("_other");
+ if (other_suffix != std::string::npos) {
+ sanitized_partition_name.erase(other_suffix); // converts system_other => system
+ is_other_slot = true;
+ }
+
+ auto append_suffix = is_other_slot ? ab_other_suffix : ab_suffix;
+ return sanitized_partition_name + append_suffix;
+}
+
+off64_t GetTotalSize(int fd) {
+ off64_t saved_current = lseek64(fd, 0, SEEK_CUR);
+ if (saved_current == -1) {
+ PERROR << "Failed to get current position";
+ return -1;
+ }
+
+ // lseek64() returns the resulting offset location from the beginning of the file.
+ off64_t total_size = lseek64(fd, 0, SEEK_END);
+ if (total_size == -1) {
+ PERROR << "Failed to lseek64 to end of the partition";
+ return -1;
+ }
+
+ // Restores the original offset.
+ if (lseek64(fd, saved_current, SEEK_SET) == -1) {
+ PERROR << "Failed to lseek64 to the original offset: " << saved_current;
+ }
+
+ return total_size;
+}
+
+std::unique_ptr<AvbFooter> GetAvbFooter(int fd) {
+ std::array<uint8_t, AVB_FOOTER_SIZE> footer_buf;
+ auto footer(std::make_unique<AvbFooter>());
+
+ off64_t footer_offset = GetTotalSize(fd) - AVB_FOOTER_SIZE;
+
+ ssize_t num_read =
+ TEMP_FAILURE_RETRY(pread64(fd, footer_buf.data(), AVB_FOOTER_SIZE, footer_offset));
+ if (num_read < 0 || num_read != AVB_FOOTER_SIZE) {
+ PERROR << "Failed to read AVB footer";
+ return nullptr;
+ }
+
+ if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf.data(), footer.get())) {
+ PERROR << "AVB footer verification failed.";
+ return nullptr;
+ }
+
+ return footer;
+}
+
+bool VerifyPublicKeyBlob(const uint8_t* key, size_t length, const std::string& expected_key_blob) {
+ if (expected_key_blob.empty()) { // no expectation of the key, return true.
+ return true;
+ }
+ if (expected_key_blob.size() != length) {
+ return false;
+ }
+ if (0 == memcmp(key, expected_key_blob.data(), length)) {
+ return true;
+ }
+ return false;
+}
+
+VBMetaVerifyResult VerifyVBMetaSignature(const VBMetaData& vbmeta,
+ const std::string& expected_public_key_blob) {
+ const uint8_t* pk_data;
+ size_t pk_len;
+ ::AvbVBMetaVerifyResult vbmeta_ret;
+
+ vbmeta_ret = avb_vbmeta_image_verify(vbmeta.data(), vbmeta.size(), &pk_data, &pk_len);
+
+ switch (vbmeta_ret) {
+ case AVB_VBMETA_VERIFY_RESULT_OK:
+ if (pk_data == nullptr || pk_len <= 0) {
+ LERROR << vbmeta.partition()
+ << ": Error verifying vbmeta image: failed to get public key";
+ return VBMetaVerifyResult::kError;
+ }
+ if (!VerifyPublicKeyBlob(pk_data, pk_len, expected_public_key_blob)) {
+ LERROR << vbmeta.partition() << ": Error verifying vbmeta image: public key used to"
+ << " sign data does not match key in chain descriptor";
+ return VBMetaVerifyResult::kErrorVerification;
+ }
+ return VBMetaVerifyResult::kSuccess;
+ case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
+ case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
+ case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
+ LERROR << vbmeta.partition() << ": Error verifying vbmeta image: "
+ << avb_vbmeta_verify_result_to_string(vbmeta_ret);
+ return VBMetaVerifyResult::kErrorVerification;
+ case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
+ // No way to continue this case.
+ LERROR << vbmeta.partition() << ": Error verifying vbmeta image: invalid vbmeta header";
+ break;
+ case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
+ // No way to continue this case.
+ LERROR << vbmeta.partition()
+ << ": Error verifying vbmeta image: unsupported AVB version";
+ break;
+ default:
+ LERROR << "Unknown vbmeta image verify return value: " << vbmeta_ret;
+ break;
+ }
+
+ return VBMetaVerifyResult::kError;
+}
+
+std::unique_ptr<VBMetaData> VerifyVBMetaData(int fd, const std::string& partition_name,
+ const std::string& expected_public_key_blob,
+ VBMetaVerifyResult* out_verify_result) {
+ uint64_t vbmeta_offset = 0;
+ uint64_t vbmeta_size = VBMetaData::kMaxVBMetaSize;
+ bool is_vbmeta_partition = StartsWith(partition_name, "vbmeta");
+
+ if (!is_vbmeta_partition) {
+ std::unique_ptr<AvbFooter> footer = GetAvbFooter(fd);
+ if (!footer) {
+ return nullptr;
+ }
+ vbmeta_offset = footer->vbmeta_offset;
+ vbmeta_size = footer->vbmeta_size;
+ }
+
+ if (vbmeta_size > VBMetaData::kMaxVBMetaSize) {
+ LERROR << "VbMeta size in footer exceeds kMaxVBMetaSize";
+ return nullptr;
+ }
+
+ auto vbmeta = std::make_unique<VBMetaData>(vbmeta_size, partition_name);
+ ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, vbmeta->data(), vbmeta_size, vbmeta_offset));
+ // Allows partial read for vbmeta partition, because its vbmeta_size is kMaxVBMetaSize.
+ if (num_read < 0 || (!is_vbmeta_partition && static_cast<uint64_t>(num_read) != vbmeta_size)) {
+ PERROR << partition_name << ": Failed to read vbmeta at offset " << vbmeta_offset
+ << " with size " << vbmeta_size;
+ return nullptr;
+ }
+
+ auto verify_result = VerifyVBMetaSignature(*vbmeta, expected_public_key_blob);
+ if (out_verify_result != nullptr) *out_verify_result = verify_result;
+
+ if (verify_result == VBMetaVerifyResult::kSuccess ||
+ verify_result == VBMetaVerifyResult::kErrorVerification) {
+ return vbmeta;
+ }
+
+ return nullptr;
+}
+
+bool RollbackDetected(const std::string& partition_name ATTRIBUTE_UNUSED,
+ uint64_t rollback_index ATTRIBUTE_UNUSED) {
+ // TODO(bowgotsai): Support rollback protection.
+ return false;
+}
+
+std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fatal_error) {
+ CHECK(fatal_error != nullptr);
+ std::vector<ChainInfo> chain_partitions;
+
+ size_t num_descriptors;
+ std::unique_ptr<const AvbDescriptor* [], decltype(&avb_free)> descriptors(
+ avb_descriptor_get_all(vbmeta.data(), vbmeta.size(), &num_descriptors), avb_free);
+
+ if (!descriptors || num_descriptors < 1) {
+ return {};
+ }
+
+ for (size_t i = 0; i < num_descriptors; i++) {
+ AvbDescriptor desc;
+ if (!avb_descriptor_validate_and_byteswap(descriptors[i], &desc)) {
+ LERROR << "Descriptor[" << i << "] is invalid in vbmeta: " << vbmeta.partition();
+ *fatal_error = true;
+ return {};
+ }
+ if (desc.tag == AVB_DESCRIPTOR_TAG_CHAIN_PARTITION) {
+ AvbChainPartitionDescriptor chain_desc;
+ if (!avb_chain_partition_descriptor_validate_and_byteswap(
+ (AvbChainPartitionDescriptor*)descriptors[i], &chain_desc)) {
+ LERROR << "Chain descriptor[" << i
+ << "] is invalid in vbmeta: " << vbmeta.partition();
+ *fatal_error = true;
+ return {};
+ }
+ const char* chain_partition_name =
+ ((const char*)descriptors[i]) + sizeof(AvbChainPartitionDescriptor);
+ const char* chain_public_key_blob =
+ chain_partition_name + chain_desc.partition_name_len;
+ chain_partitions.emplace_back(
+ std::string(chain_partition_name, chain_desc.partition_name_len),
+ std::string(chain_public_key_blob, chain_desc.public_key_len));
+ }
+ }
+
+ return chain_partitions;
+}
+
+VBMetaVerifyResult LoadAndVerifyVbmetaImpl(
+ const std::string& partition_name, const std::string& ab_suffix,
+ const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
+ bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
+ std::function<std::string(const std::string&)> device_path_constructor,
+ bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images) {
+ // Ensures the device path (might be a symlink created by init) is ready to access.
+ auto device_path = device_path_constructor(
+ AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix));
+ if (!WaitForFile(device_path, 1s)) {
+ PERROR << "No such partition: " << device_path;
+ return VBMetaVerifyResult::kError;
+ }
+
+ unique_fd fd(TEMP_FAILURE_RETRY(open(device_path.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (fd < 0) {
+ PERROR << "Failed to open: " << device_path;
+ return VBMetaVerifyResult::kError;
+ }
+
+ VBMetaVerifyResult verify_result;
+ std::unique_ptr<VBMetaData> vbmeta =
+ VerifyVBMetaData(fd, partition_name, expected_public_key_blob, &verify_result);
+ if (!vbmeta) {
+ LERROR << partition_name << ": Failed to load vbmeta, result: " << verify_result;
+ return VBMetaVerifyResult::kError;
+ }
+
+ if (!allow_verification_error && verify_result == VBMetaVerifyResult::kErrorVerification) {
+ LERROR << partition_name << ": allow verification error is not allowed";
+ return VBMetaVerifyResult::kError;
+ }
+
+ std::unique_ptr<AvbVBMetaImageHeader> vbmeta_header =
+ vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */);
+ if (!vbmeta_header) {
+ LERROR << partition_name << ": Failed to get vbmeta header";
+ return VBMetaVerifyResult::kError;
+ }
+
+ if (rollback_protection && RollbackDetected(partition_name, vbmeta_header->rollback_index)) {
+ return VBMetaVerifyResult::kError;
+ }
+
+ // vbmeta flags can only be set by the top-level vbmeta image.
+ if (is_chained_vbmeta && vbmeta_header->flags != 0) {
+ LERROR << partition_name << ": chained vbmeta image has non-zero flags";
+ return VBMetaVerifyResult::kError;
+ }
+
+ if (out_vbmeta_images) {
+ out_vbmeta_images->emplace_back(std::move(*vbmeta));
+ }
+
+ // If verification has been disabled by setting a bit in the image, we're done.
+ if (vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+ LWARNING << "VERIFICATION_DISABLED bit is set for partition: " << partition_name;
+ return verify_result;
+ }
+
+ if (load_chained_vbmeta) {
+ bool fatal_error = false;
+ auto chain_partitions = GetChainPartitionInfo(*out_vbmeta_images->rbegin(), &fatal_error);
+ if (fatal_error) {
+ return VBMetaVerifyResult::kError;
+ }
+ for (auto& chain : chain_partitions) {
+ auto sub_ret = LoadAndVerifyVbmetaImpl(
+ chain.partition_name, ab_suffix, ab_other_suffix, chain.public_key_blob,
+ allow_verification_error, load_chained_vbmeta, rollback_protection,
+ device_path_constructor, true, /* is_chained_vbmeta */
+ out_vbmeta_images);
+ if (sub_ret != VBMetaVerifyResult::kSuccess) {
+ verify_result = sub_ret; // might be 'ERROR' or 'ERROR VERIFICATION'.
+ if (verify_result == VBMetaVerifyResult::kError) {
+ return verify_result; // stop here if we got an 'ERROR'.
+ }
+ }
+ }
+ }
+
+ return verify_result;
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libfs_avb/avb_util.h b/fs_mgr/libfs_avb/avb_util.h
index b81e931..babbfef 100644
--- a/fs_mgr/libfs_avb/avb_util.h
+++ b/fs_mgr/libfs_avb/avb_util.h
@@ -16,9 +16,11 @@
#pragma once
+#include <ostream>
#include <string>
#include <vector>
+#include <fstab/fstab.h>
#include <libavb/libavb.h>
#include <libdm/dm.h>
@@ -27,6 +29,22 @@
namespace android {
namespace fs_mgr {
+enum class VBMetaVerifyResult {
+ kSuccess = 0,
+ kError = 1,
+ kErrorVerification = 2,
+};
+
+std::ostream& operator<<(std::ostream& os, VBMetaVerifyResult);
+
+struct ChainInfo {
+ std::string partition_name;
+ std::string public_key_blob;
+
+ ChainInfo(const std::string& chain_partition_name, const std::string& chain_public_key_blob)
+ : partition_name(chain_partition_name), public_key_blob(chain_public_key_blob) {}
+};
+
// AvbHashtreeDescriptor to dm-verity table setup.
bool GetHashtreeDescriptor(const std::string& partition_name,
const std::vector<VBMetaData>& vbmeta_images,
@@ -41,5 +59,37 @@
const std::string& salt, const std::string& root_digest,
bool wait_for_verity_dev);
+// Maps AVB partition name to a device partition name.
+std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name,
+ const std::string& ab_suffix,
+ const std::string& ab_other_suffix);
+
+// AvbFooter and AvbMetaImage maninpulations.
+off64_t GetTotalSize(int fd);
+
+std::unique_ptr<AvbFooter> GetAvbFooter(int fd);
+
+std::unique_ptr<VBMetaData> VerifyVBMetaData(int fd, const std::string& partition_name,
+ const std::string& expected_public_key_blob,
+ VBMetaVerifyResult* out_verify_result);
+
+VBMetaVerifyResult VerifyVBMetaSignature(const VBMetaData& vbmeta,
+ const std::string& expected_public_key_blob);
+
+bool VerifyPublicKeyBlob(const uint8_t* key, size_t length, const std::string& expected_key_blob);
+
+// Detects if whether a partition contains a rollback image.
+bool RollbackDetected(const std::string& partition_name, uint64_t rollback_index);
+
+// Extracts chain partition info.
+std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fatal_error);
+
+VBMetaVerifyResult LoadAndVerifyVbmetaImpl(
+ const std::string& partition_name, const std::string& ab_suffix,
+ const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
+ bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
+ std::function<std::string(const std::string&)> device_path_constructor,
+ bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index 957aa87..9f8ad53 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -39,6 +39,7 @@
using android::base::Basename;
using android::base::ParseUint;
+using android::base::ReadFileToString;
using android::base::StringPrintf;
namespace android {
@@ -59,6 +60,51 @@
return std::make_pair(total_size, matched);
}
+template <typename Hasher>
+std::pair<std::string, size_t> CalculateVbmetaDigest(const std::vector<VBMetaData>& vbmeta_images) {
+ std::string digest;
+ size_t total_size = 0;
+
+ Hasher hasher;
+ for (const auto& vbmeta : vbmeta_images) {
+ hasher.update(vbmeta.data(), vbmeta.size());
+ total_size += vbmeta.size();
+ }
+
+ // Converts digest bytes to a hex string.
+ digest = BytesToHex(hasher.finalize(), Hasher::DIGEST_SIZE);
+ return std::make_pair(digest, total_size);
+}
+
+// Helper functions to dump enum class AvbHandleStatus.
+const char* AvbHandleStatusToString(AvbHandleStatus status) {
+ // clang-format off
+ static const char* const name[] = {
+ "Success",
+ "Uninitialized",
+ "HashtreeDisabled",
+ "VerificationDisabled",
+ "VerificationError",
+ "Unknown",
+ };
+ // clang-format on
+
+ uint32_t index = static_cast<uint32_t>(status);
+ uint32_t unknown_index = sizeof(name) / sizeof(char*) - 1;
+ if (index >= unknown_index) {
+ index = unknown_index;
+ }
+
+ return name[index];
+}
+
+std::ostream& operator<<(std::ostream& os, AvbHandleStatus status) {
+ os << AvbHandleStatusToString(status);
+ return os;
+}
+
+// class AvbVerifier
+// -----------------
// Reads the following values from kernel cmdline and provides the
// VerifyVbmetaImages() to verify AvbSlotVerifyData.
// - androidboot.vbmeta.hash_alg
@@ -74,12 +120,6 @@
AvbVerifier() = default;
private:
- enum HashAlgorithm {
- kInvalid = 0,
- kSHA256 = 1,
- kSHA512 = 2,
- };
-
HashAlgorithm hash_alg_;
uint8_t digest_[SHA512_DIGEST_LENGTH];
size_t vbmeta_size_;
@@ -105,10 +145,10 @@
fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg);
if (hash_alg == "sha256") {
expected_digest_size = SHA256_DIGEST_LENGTH * 2;
- avb_verifier->hash_alg_ = kSHA256;
+ avb_verifier->hash_alg_ = HashAlgorithm::kSHA256;
} else if (hash_alg == "sha512") {
expected_digest_size = SHA512_DIGEST_LENGTH * 2;
- avb_verifier->hash_alg_ = kSHA512;
+ avb_verifier->hash_alg_ = HashAlgorithm::kSHA512;
} else {
LERROR << "Unknown hash algorithm: " << hash_alg.c_str();
return nullptr;
@@ -140,10 +180,10 @@
size_t total_size = 0;
bool digest_matched = false;
- if (hash_alg_ == kSHA256) {
+ if (hash_alg_ == HashAlgorithm::kSHA256) {
std::tie(total_size, digest_matched) =
VerifyVbmetaDigest<SHA256Hasher>(vbmeta_images, digest_);
- } else if (hash_alg_ == kSHA512) {
+ } else if (hash_alg_ == HashAlgorithm::kSHA512) {
std::tie(total_size, digest_matched) =
VerifyVbmetaDigest<SHA512Hasher>(vbmeta_images, digest_);
}
@@ -162,6 +202,98 @@
return true;
}
+// class AvbHandle
+// ---------------
+AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(
+ const std::string& partition_name, const std::string& ab_suffix,
+ const std::string& ab_other_suffix, const std::string& expected_public_key_path,
+ const HashAlgorithm& hash_algorithm, bool allow_verification_error,
+ bool load_chained_vbmeta, bool rollback_protection,
+ std::function<std::string(const std::string&)> custom_device_path) {
+ AvbUniquePtr avb_handle(new AvbHandle());
+ if (!avb_handle) {
+ LERROR << "Failed to allocate AvbHandle";
+ return nullptr;
+ }
+
+ std::string expected_key_blob;
+ if (!expected_public_key_path.empty()) {
+ if (access(expected_public_key_path.c_str(), F_OK) != 0) {
+ LERROR << "Expected public key path doesn't exist: " << expected_public_key_path;
+ return nullptr;
+ } else if (!ReadFileToString(expected_public_key_path, &expected_key_blob)) {
+ LERROR << "Failed to load: " << expected_public_key_path;
+ return nullptr;
+ }
+ }
+
+ auto android_by_name_symlink = [](const std::string& partition_name_with_ab) {
+ return "/dev/block/by-name/" + partition_name_with_ab;
+ };
+
+ auto device_path = custom_device_path ? custom_device_path : android_by_name_symlink;
+
+ auto verify_result = LoadAndVerifyVbmetaImpl(
+ partition_name, ab_suffix, ab_other_suffix, expected_key_blob, allow_verification_error,
+ load_chained_vbmeta, rollback_protection, device_path, false,
+ /* is_chained_vbmeta */ &avb_handle->vbmeta_images_);
+ switch (verify_result) {
+ case VBMetaVerifyResult::kSuccess:
+ avb_handle->status_ = AvbHandleStatus::kSuccess;
+ break;
+ case VBMetaVerifyResult::kErrorVerification:
+ avb_handle->status_ = AvbHandleStatus::kVerificationError;
+ break;
+ default:
+ LERROR << "LoadAndVerifyVbmetaImpl failed, result: " << verify_result;
+ return nullptr;
+ }
+
+ // Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version".
+ avb_handle->avb_version_ = StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
+
+ // Checks any disabled flag is set.
+ std::unique_ptr<AvbVBMetaImageHeader> vbmeta_header =
+ avb_handle->vbmeta_images_[0].GetVBMetaHeader();
+ bool verification_disabled = ((AvbVBMetaImageFlags)vbmeta_header->flags &
+ AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
+ bool hashtree_disabled =
+ ((AvbVBMetaImageFlags)vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
+ if (verification_disabled) {
+ avb_handle->status_ = AvbHandleStatus::kVerificationDisabled;
+ } else if (hashtree_disabled) {
+ avb_handle->status_ = AvbHandleStatus::kHashtreeDisabled;
+ }
+
+ // Calculates the summary info for all vbmeta_images_;
+ std::string digest;
+ size_t total_size;
+ if (hash_algorithm == HashAlgorithm::kSHA256) {
+ std::tie(digest, total_size) =
+ CalculateVbmetaDigest<SHA256Hasher>(avb_handle->vbmeta_images_);
+ } else if (hash_algorithm == HashAlgorithm::kSHA512) {
+ std::tie(digest, total_size) =
+ CalculateVbmetaDigest<SHA512Hasher>(avb_handle->vbmeta_images_);
+ } else {
+ LERROR << "Invalid hash algorithm";
+ return nullptr;
+ }
+ avb_handle->vbmeta_info_ = VBMetaInfo(digest, hash_algorithm, total_size);
+
+ LINFO << "Returning avb_handle with status: " << avb_handle->status_;
+ return avb_handle;
+}
+
+AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta() {
+ // Loads inline vbmeta images, starting from /vbmeta.
+ return LoadAndVerifyVbmeta("vbmeta", fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix(),
+ {} /* expected_public_key, already checked by bootloader */,
+ HashAlgorithm::kSHA256,
+ IsDeviceUnlocked(), /* allow_verification_error */
+ true, /* load_chained_vbmeta */
+ false, /* rollback_protection, already checked by bootloader */
+ nullptr /* custom_device_path */);
+}
AvbUniquePtr AvbHandle::Open() {
bool is_device_unlocked = IsDeviceUnlocked();
@@ -192,14 +324,14 @@
// for more details.
switch (verify_result) {
case AVB_SLOT_VERIFY_RESULT_OK:
- avb_handle->status_ = kAvbHandleSuccess;
+ avb_handle->status_ = AvbHandleStatus::kSuccess;
break;
case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
if (!is_device_unlocked) {
LERROR << "ERROR_VERIFICATION isn't allowed when the device is LOCKED";
return nullptr;
}
- avb_handle->status_ = kAvbHandleVerificationError;
+ avb_handle->status_ = AvbHandleStatus::kVerificationError;
break;
default:
LERROR << "avb_slot_verify failed, result: " << verify_result;
@@ -220,7 +352,7 @@
AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
if (verification_disabled) {
- avb_handle->status_ = kAvbHandleVerificationDisabled;
+ avb_handle->status_ = AvbHandleStatus::kVerificationDisabled;
} else {
// Verifies vbmeta structs against the digest passed from bootloader in kernel cmdline.
std::unique_ptr<AvbVerifier> avb_verifier = AvbVerifier::Create();
@@ -237,7 +369,7 @@
bool hashtree_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags &
AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
if (hashtree_disabled) {
- avb_handle->status_ = kAvbHandleHashtreeDisabled;
+ avb_handle->status_ = AvbHandleStatus::kHashtreeDisabled;
}
}
@@ -246,11 +378,12 @@
}
AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev) {
- if (!fstab_entry || status_ == kAvbHandleUninitialized || vbmeta_images_.size() < 1) {
+ if (!fstab_entry || status_ == AvbHandleStatus::kUninitialized || vbmeta_images_.size() < 1) {
return AvbHashtreeResult::kFail;
}
- if (status_ == kAvbHandleHashtreeDisabled || status_ == kAvbHandleVerificationDisabled) {
+ if (status_ == AvbHandleStatus::kHashtreeDisabled ||
+ status_ == AvbHandleStatus::kVerificationDisabled) {
LINFO << "AVB HASHTREE disabled on: " << fstab_entry->mount_point;
return AvbHashtreeResult::kDisabled;
}
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index eca6984..7af3c7e 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -32,23 +33,56 @@
kDisabled,
};
+enum class HashAlgorithm {
+ kInvalid = 0,
+ kSHA256 = 1,
+ kSHA512 = 2,
+};
+
+enum class AvbHandleStatus {
+ kSuccess = 0,
+ kUninitialized = 1,
+ kHashtreeDisabled = 2,
+ kVerificationDisabled = 3,
+ kVerificationError = 4,
+};
+
+struct VBMetaInfo {
+ std::string digest;
+ HashAlgorithm hash_algorithm;
+ size_t total_size;
+
+ VBMetaInfo() {}
+
+ VBMetaInfo(std::string digest_value, HashAlgorithm algorithm, size_t size)
+ : digest(std::move(digest_value)), hash_algorithm(algorithm), total_size(size) {}
+};
+
class VBMetaData {
public:
// Constructors
VBMetaData() : vbmeta_ptr_(nullptr), vbmeta_size_(0){};
- VBMetaData(const uint8_t* data, size_t size)
- : vbmeta_ptr_(new (std::nothrow) uint8_t[size]), vbmeta_size_(size) {
+ VBMetaData(const uint8_t* data, size_t size, const std::string& partition_name)
+ : vbmeta_ptr_(new (std::nothrow) uint8_t[size]),
+ vbmeta_size_(size),
+ partition_name_(partition_name) {
// The ownership of data is NOT transferred, i.e., the caller still
// needs to release the memory as we make a copy here.
memcpy(vbmeta_ptr_.get(), data, size * sizeof(uint8_t));
}
- explicit VBMetaData(size_t size)
- : vbmeta_ptr_(new (std::nothrow) uint8_t[size]), vbmeta_size_(size) {}
+ explicit VBMetaData(size_t size, const std::string& partition_name)
+ : vbmeta_ptr_(new (std::nothrow) uint8_t[size]),
+ vbmeta_size_(size),
+ partition_name_(partition_name) {}
+
+ // Extracts vbmeta header from the vbmeta buffer, set update_vbmeta_size to
+ // true to update vbmeta_size_ to the actual size with valid content.
+ std::unique_ptr<AvbVBMetaImageHeader> GetVBMetaHeader(bool update_vbmeta_size = false);
// Get methods for each data member.
- const std::string& device_path() const { return device_path_; }
+ const std::string& partition() const { return partition_name_; }
uint8_t* data() const { return vbmeta_ptr_.get(); }
const size_t& size() const { return vbmeta_size_; }
@@ -56,9 +90,9 @@
static const size_t kMaxVBMetaSize = 64 * 1024;
private:
- std::string device_path_;
std::unique_ptr<uint8_t[]> vbmeta_ptr_;
size_t vbmeta_size_;
+ std::string partition_name_;
};
class FsManagerAvbOps;
@@ -71,7 +105,7 @@
// descriptors to load verity table into kernel through ioctl.
class AvbHandle {
public:
- // The factory method to return a AvbUniquePtr that holds
+ // The factory methods to return a AvbUniquePtr that holds
// the verified AVB (external/avb) metadata of all verified partitions
// in vbmeta_images_.
//
@@ -79,31 +113,40 @@
// - androidboot.vbmeta.{hash_alg, size, digest}.
//
// A typical usage will be:
- // - AvbUniquePtr handle = AvbHandle::Open();
+ // - AvbUniquePtr handle = AvbHandle::Open(); or
+ // - AvbUniquePtr handle = AvbHandle::LoadAndVerifyVbmeta();
//
// Possible return values:
// - nullptr: any error when reading and verifying the metadata,
// e.g., I/O error, digest value mismatch, size mismatch, etc.
//
- // - a valid unique_ptr with status kAvbHandleHashtreeDisabled:
+ // - a valid unique_ptr with status AvbHandleStatus::HashtreeDisabled:
// to support the existing 'adb disable-verity' feature in Android.
// It's very helpful for developers to make the filesystem writable to
// allow replacing binaries on the device.
//
- // - a valid unique_ptr with status kAvbHandleVerificationDisabled:
+ // - a valid unique_ptr with status AvbHandleStatus::VerificationDisabled:
// to support 'avbctl disable-verification': only the top-level
// vbmeta is read, vbmeta structs in other partitions are not processed.
// It's needed to bypass AVB when using the generic system.img to run
// VTS for project Treble.
//
- // - a valid unique_ptr with status kAvbHandleVerificationError:
+ // - a valid unique_ptr with status AvbHandleStatus::VerificationError:
// there is verification error when libavb loads vbmeta from each
// partition. This is only allowed when the device is unlocked.
//
- // - a valid unique_ptr with status kAvbHandleSuccess: the metadata
+ // - a valid unique_ptr with status AvbHandleStatus::Success: the metadata
// is verified and can be trusted.
//
- static AvbUniquePtr Open();
+ // TODO(bowgotsai): remove Open() and switch to LoadAndVerifyVbmeta().
+ static AvbUniquePtr Open(); // loads inline vbmeta, via libavb.
+ static AvbUniquePtr LoadAndVerifyVbmeta(); // loads inline vbmeta.
+ static AvbUniquePtr LoadAndVerifyVbmeta( // loads offline vbmeta.
+ const std::string& partition_name, const std::string& ab_suffix,
+ const std::string& ab_other_suffix, const std::string& expected_public_key,
+ const HashAlgorithm& hash_algorithm, bool allow_verification_error,
+ bool load_chained_vbmeta, bool rollback_protection,
+ std::function<std::string(const std::string&)> custom_device_path = nullptr);
// Sets up dm-verity on the given fstab entry.
// The 'wait_for_verity_dev' parameter makes this function wait for the
@@ -118,6 +161,8 @@
AvbHashtreeResult SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev);
const std::string& avb_version() const { return avb_version_; }
+ const VBMetaInfo& vbmeta_info() const { return vbmeta_info_; }
+ AvbHandleStatus status() const { return status_; }
AvbHandle(const AvbHandle&) = delete; // no copy
AvbHandle& operator=(const AvbHandle&) = delete; // no assignment
@@ -126,17 +171,10 @@
AvbHandle& operator=(AvbHandle&&) noexcept = delete; // no move assignment
private:
- enum AvbHandleStatus {
- kAvbHandleSuccess = 0,
- kAvbHandleUninitialized,
- kAvbHandleHashtreeDisabled,
- kAvbHandleVerificationDisabled,
- kAvbHandleVerificationError,
- };
-
- AvbHandle() : status_(kAvbHandleUninitialized) {}
+ AvbHandle() : status_(AvbHandleStatus::kUninitialized) {}
std::vector<VBMetaData> vbmeta_images_;
+ VBMetaInfo vbmeta_info_; // A summary info for vbmeta_images_.
AvbHandleStatus status_;
std::string avb_version_;
};
diff --git a/fs_mgr/libfs_avb/tests/avb_util_test.cpp b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
new file mode 100644
index 0000000..26b3294
--- /dev/null
+++ b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
@@ -0,0 +1,1088 @@
+/*
+ * Copyright (C) 2019 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 <android-base/unique_fd.h>
+#include <base/files/file_util.h>
+#include <base/rand_util.h>
+#include <base/strings/string_util.h>
+
+#include "avb_util.h"
+#include "fs_avb_test_util.h"
+
+// Target classes or functions to test:
+using android::fs_mgr::AvbPartitionToDevicePatition;
+using android::fs_mgr::GetAvbFooter;
+using android::fs_mgr::GetChainPartitionInfo;
+using android::fs_mgr::GetTotalSize;
+using android::fs_mgr::LoadAndVerifyVbmetaImpl;
+using android::fs_mgr::VBMetaData;
+using android::fs_mgr::VBMetaVerifyResult;
+using android::fs_mgr::VerifyPublicKeyBlob;
+using android::fs_mgr::VerifyVBMetaData;
+using android::fs_mgr::VerifyVBMetaSignature;
+
+namespace fs_avb_host_test {
+
+class AvbUtilTest : public BaseFsAvbTest {
+ public:
+ AvbUtilTest(){};
+
+ protected:
+ ~AvbUtilTest(){};
+ // Helper function for VerifyVBMetaSignature test. Modifies vbmeta.data()
+ // in a number of places at |offset| of size |length| and checks that
+ // VerifyVBMetaSignature() returns |expected_result|.
+ bool TestVBMetaModification(VBMetaVerifyResult expected_result, const VBMetaData& vbmeta,
+ size_t offset, size_t length);
+ // Modifies a random bit for a file, in the range of [offset, offset + length - 1].
+ void ModifyFile(const base::FilePath& file_path, size_t offset, ssize_t length);
+
+ // Loads the content of avb_image_path and comparies it with the content of vbmeta.
+ bool CompareVBMeta(const base::FilePath& avb_image_path, const VBMetaData& expected_vbmeta);
+};
+
+TEST_F(AvbUtilTest, AvbPartitionToDevicePatition) {
+ EXPECT_EQ("system", AvbPartitionToDevicePatition("system", "", ""));
+ EXPECT_EQ("system", AvbPartitionToDevicePatition("system", "", "_b"));
+
+ EXPECT_EQ("system_a", AvbPartitionToDevicePatition("system", "_a", ""));
+ EXPECT_EQ("system_a", AvbPartitionToDevicePatition("system", "_a", "_b"));
+
+ EXPECT_EQ("system_b", AvbPartitionToDevicePatition("system_other", "", "_b"));
+ EXPECT_EQ("system_b", AvbPartitionToDevicePatition("system_other", "_a", "_b"));
+}
+
+TEST_F(AvbUtilTest, GetFdTotalSize) {
+ // Generates a raw test.img via BaseFsAvbTest.
+ const size_t image_size = 5 * 1024 * 1024;
+ base::FilePath image_path = GenerateImage("test.img", image_size);
+
+ // Checks file size is as expected via base::GetFileSize().
+ int64_t file_size;
+ ASSERT_TRUE(base::GetFileSize(image_path, &file_size));
+ EXPECT_EQ(image_size, file_size);
+
+ // Checks file size is expected via libfs_avb internal utils.
+ auto fd = OpenUniqueReadFd(image_path);
+ EXPECT_EQ(image_size, GetTotalSize(fd));
+}
+
+TEST_F(AvbUtilTest, GetFdTotalSizeWithOffset) {
+ // Generates a raw test.img via BaseFsAvbTest.
+ const size_t image_size = 10 * 1024 * 1024;
+ base::FilePath image_path = GenerateImage("test.img", image_size);
+
+ // Checks file size is expected even with a non-zero offset at the beginning.
+ auto fd = OpenUniqueReadFd(image_path);
+ off_t initial_offset = 2019;
+ EXPECT_EQ(initial_offset, lseek(fd, initial_offset, SEEK_SET));
+ EXPECT_EQ(image_size, GetTotalSize(fd)); // checks that total size is still returned.
+ EXPECT_EQ(initial_offset, lseek(fd, 0, SEEK_CUR)); // checks original offset is restored.
+}
+
+TEST_F(AvbUtilTest, GetAvbFooter) {
+ // Generates a raw system.img
+ const size_t image_size = 10 * 1024 * 1024;
+ const size_t partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", image_size);
+ EXPECT_NE(0U, system_path.value().size());
+
+ // Checks image size is as expected.
+ int64_t file_size;
+ ASSERT_TRUE(base::GetFileSize(system_path, &file_size));
+ EXPECT_EQ(image_size, file_size);
+
+ // Appends AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", partition_size, "SHA512_RSA8192", 20,
+ data_dir_.Append("testkey_rsa8192.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Checks partition size is as expected, after adding footer.
+ ASSERT_TRUE(base::GetFileSize(system_path, &file_size));
+ EXPECT_EQ(partition_size, file_size);
+
+ // Checks avb footer and avb vbmeta.
+ EXPECT_EQ(
+ "Footer version: 1.0\n"
+ "Image size: 15728640 bytes\n"
+ "Original image size: 10485760 bytes\n"
+ "VBMeta offset: 10661888\n"
+ "VBMeta size: 3648 bytes\n"
+ "--\n"
+ "Minimum libavb version: 1.0\n"
+ "Header Block: 256 bytes\n"
+ "Authentication Block: 1088 bytes\n"
+ "Auxiliary Block: 2304 bytes\n"
+ "Algorithm: SHA512_RSA8192\n"
+ "Rollback Index: 20\n"
+ "Flags: 0\n"
+ "Release String: 'unit test'\n"
+ "Descriptors:\n"
+ " Hashtree descriptor:\n"
+ " Version of dm-verity: 1\n"
+ " Image Size: 10485760 bytes\n"
+ " Tree Offset: 10485760\n"
+ " Tree Size: 86016 bytes\n"
+ " Data Block Size: 4096 bytes\n"
+ " Hash Block Size: 4096 bytes\n"
+ " FEC num roots: 2\n"
+ " FEC offset: 10571776\n"
+ " FEC size: 90112 bytes\n"
+ " Hash Algorithm: sha1\n"
+ " Partition Name: system\n"
+ " Salt: d00df00d\n"
+ " Root Digest: a3d5dd307341393d85de356c384ff543ec1ed81b\n"
+ " Flags: 0\n",
+ InfoImage(system_path));
+
+ // Checks each field from GetAvbFooter(fd).
+ auto fd = OpenUniqueReadFd(system_path);
+ auto footer = GetAvbFooter(fd);
+ EXPECT_NE(nullptr, footer);
+ EXPECT_EQ(10485760, footer->original_image_size);
+ EXPECT_EQ(10661888, footer->vbmeta_offset);
+ EXPECT_EQ(3648, footer->vbmeta_size);
+}
+
+TEST_F(AvbUtilTest, GetAvbFooterErrorVerification) {
+ // Generates a raw system.img
+ const size_t image_size = 5 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", image_size);
+
+ // Checks each field from GetAvbFooter(fd).
+ auto fd = OpenUniqueReadFd(system_path);
+ auto footer = GetAvbFooter(fd);
+ EXPECT_EQ(nullptr, footer);
+}
+
+TEST_F(AvbUtilTest, GetAvbFooterInsufficientSize) {
+ // Generates a raw system.img
+ const size_t image_size = AVB_FOOTER_SIZE - 10;
+ base::FilePath system_path = GenerateImage("system.img", image_size);
+
+ // Checks each field from GetAvbFooter(fd).
+ auto fd = OpenUniqueReadFd(system_path);
+ auto footer = GetAvbFooter(fd);
+ EXPECT_EQ(nullptr, footer);
+}
+
+TEST_F(AvbUtilTest, GetVBMetaHeader) {
+ // Generates a raw boot.img
+ const size_t image_size = 5 * 1024 * 1024;
+ const size_t partition_size = 10 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot.img", image_size);
+ // Appends AVB Hash Footer.
+ AddAvbFooter(boot_path, "hash", "boot", partition_size, "SHA256_RSA4096", 10,
+ data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+ // Extracts boot vbmeta from boot.img into boot-vbmeta.img.
+ base::FilePath boot_vbmeta = ExtractVBMetaImage(boot_path, "boot-vbmeta.img");
+ EXPECT_EQ(
+ "Minimum libavb version: 1.0\n"
+ "Header Block: 256 bytes\n"
+ "Authentication Block: 576 bytes\n"
+ "Auxiliary Block: 1216 bytes\n"
+ "Algorithm: SHA256_RSA4096\n"
+ "Rollback Index: 10\n"
+ "Flags: 0\n"
+ "Release String: 'unit test'\n"
+ "Descriptors:\n"
+ " Hash descriptor:\n"
+ " Image Size: 5242880 bytes\n"
+ " Hash Algorithm: sha256\n"
+ " Partition Name: boot\n"
+ " Salt: d00df00d\n"
+ " Digest: "
+ "222dd01e98284a1fcd7781f85d1392e43a530511a64eff96db197db90ebc4df1\n"
+ " Flags: 0\n",
+ InfoImage("boot-vbmeta.img"));
+
+ // Creates a VBMetaData with the content from boot-vbmeta.img.
+ std::string content;
+ EXPECT_TRUE(base::ReadFileToString(boot_vbmeta, &content));
+ VBMetaData vbmeta((uint8_t*)content.data(), content.size(), "boot-vbmeta");
+ EXPECT_EQ(content.size(), vbmeta.size());
+
+ // Checks each field returned from GetVBMetaHeader().
+ auto vbmeta_header = vbmeta.GetVBMetaHeader(false /* update_vbmeta_size */);
+ EXPECT_NE(nullptr, vbmeta_header);
+ EXPECT_EQ(576, vbmeta_header->authentication_data_block_size);
+ EXPECT_EQ(1216, vbmeta_header->auxiliary_data_block_size);
+ EXPECT_EQ(AVB_ALGORITHM_TYPE_SHA256_RSA4096, vbmeta_header->algorithm_type);
+ EXPECT_EQ(0, vbmeta_header->hash_offset);
+ EXPECT_EQ(32, vbmeta_header->hash_size);
+ EXPECT_EQ(32, vbmeta_header->signature_offset);
+ EXPECT_EQ(512, vbmeta_header->signature_size);
+ EXPECT_EQ(176, vbmeta_header->public_key_offset);
+ EXPECT_EQ(1032, vbmeta_header->public_key_size);
+ EXPECT_EQ(0, vbmeta_header->descriptors_offset);
+ EXPECT_EQ(176, vbmeta_header->descriptors_size);
+ EXPECT_EQ(10, vbmeta_header->rollback_index);
+ EXPECT_EQ(0, vbmeta_header->flags);
+ EXPECT_EQ("unit test", std::string((const char*)vbmeta_header->release_string));
+
+ // Appends some garbage to the end of the vbmeta buffer, checks it still can work.
+ std::string padding(2020, 'A'); // Generate a padding with length 2020.
+ std::string content_padding = content + padding;
+ VBMetaData vbmeta_padding((const uint8_t*)content_padding.data(), content_padding.size(),
+ "boot");
+ EXPECT_EQ(content_padding.size(), vbmeta_padding.size());
+
+ // Checks each field still can be parsed properly, even with garbage padding.
+ vbmeta_header = vbmeta_padding.GetVBMetaHeader(false /* update_vbmeta_size */);
+ EXPECT_NE(nullptr, vbmeta_header);
+ EXPECT_EQ(576, vbmeta_header->authentication_data_block_size);
+ EXPECT_EQ(1216, vbmeta_header->auxiliary_data_block_size);
+ EXPECT_EQ(AVB_ALGORITHM_TYPE_SHA256_RSA4096, vbmeta_header->algorithm_type);
+ EXPECT_EQ(0, vbmeta_header->hash_offset);
+ EXPECT_EQ(32, vbmeta_header->hash_size);
+ EXPECT_EQ(32, vbmeta_header->signature_offset);
+ EXPECT_EQ(512, vbmeta_header->signature_size);
+ EXPECT_EQ(176, vbmeta_header->public_key_offset);
+ EXPECT_EQ(1032, vbmeta_header->public_key_size);
+ EXPECT_EQ(0, vbmeta_header->descriptors_offset);
+ EXPECT_EQ(176, vbmeta_header->descriptors_size);
+ EXPECT_EQ(10, vbmeta_header->rollback_index);
+ EXPECT_EQ(0, vbmeta_header->flags);
+ EXPECT_EQ("unit test", std::string((const char*)vbmeta_header->release_string));
+
+ // Checks vbmeta size is updated to the actual size without padding.
+ vbmeta_header = vbmeta_padding.GetVBMetaHeader(true /* update_vbmeta_size */);
+ EXPECT_EQ(content_padding.size() - padding.size(), vbmeta_padding.size());
+}
+
+TEST_F(AvbUtilTest, VerifyPublicKeyBlob) {
+ // Generates a raw key.bin
+ const size_t key_size = 2048;
+ base::FilePath key_path = GenerateImage("key.bin", key_size);
+
+ uint8_t key_data[key_size];
+ EXPECT_EQ(key_size, base::ReadFile(key_path, (char*)key_data, key_size));
+
+ std::string expected_key_blob;
+ EXPECT_TRUE(base::ReadFileToString(key_path, &expected_key_blob));
+ EXPECT_TRUE(VerifyPublicKeyBlob(key_data, key_size, expected_key_blob));
+
+ key_data[10] ^= 0x80; // toggles a bit and expects a failure
+ EXPECT_FALSE(VerifyPublicKeyBlob(key_data, key_size, expected_key_blob));
+ key_data[10] ^= 0x80; // toggles the bit again, should pass
+ EXPECT_TRUE(VerifyPublicKeyBlob(key_data, key_size, expected_key_blob));
+}
+
+TEST_F(AvbUtilTest, VerifyEmptyPublicKeyBlob) {
+ // Generates a raw key.bin
+ const size_t key_size = 2048;
+ base::FilePath key_path = GenerateImage("key.bin", key_size);
+
+ uint8_t key_data[key_size];
+ EXPECT_EQ(key_size, base::ReadFile(key_path, (char*)key_data, key_size));
+
+ std::string expected_key_blob = ""; // empty means no expectation, thus return true.
+ EXPECT_TRUE(VerifyPublicKeyBlob(key_data, key_size, expected_key_blob));
+}
+
+TEST_F(AvbUtilTest, VerifyVBMetaSignature) {
+ const size_t image_size = 10 * 1024 * 1024;
+ const size_t partition_size = 15 * 1024 * 1024;
+ auto signing_key = data_dir_.Append("testkey_rsa4096.pem");
+ auto vbmeta = GenerateImageAndExtractVBMetaData("system", image_size, partition_size,
+ "hashtree", signing_key, "SHA256_RSA4096",
+ 10 /* rollback_index */);
+
+ auto expected_public_key = ExtractPublicKeyAvbBlob(signing_key);
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess, VerifyVBMetaSignature(vbmeta, expected_public_key));
+
+ // Converts the expected key into an 'unexpected' key.
+ expected_public_key[10] ^= 0x80;
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
+ VerifyVBMetaSignature(vbmeta, expected_public_key));
+}
+
+bool AvbUtilTest::TestVBMetaModification(VBMetaVerifyResult expected_result,
+ const VBMetaData& vbmeta, size_t offset, size_t length) {
+ uint8_t* d = reinterpret_cast<uint8_t*>(vbmeta.data());
+ const int kNumCheckIntervals = 8;
+
+ // Tests |kNumCheckIntervals| modifications in the start, middle, and
+ // end of the given sub-array at offset with size.
+ for (int n = 0; n <= kNumCheckIntervals; n++) {
+ size_t o = std::min(length * n / kNumCheckIntervals, length - 1) + offset;
+ d[o] ^= 0x80;
+ VBMetaVerifyResult result = VerifyVBMetaSignature(vbmeta, "" /* expected_public_key */);
+ d[o] ^= 0x80;
+ if (result != expected_result) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+TEST_F(AvbUtilTest, VerifyVBMetaSignatureWithModification) {
+ const size_t image_size = 10 * 1024 * 1024;
+ const size_t partition_size = 15 * 1024 * 1024;
+ auto signing_key = data_dir_.Append("testkey_rsa4096.pem");
+ auto vbmeta = GenerateImageAndExtractVBMetaData("system", image_size, partition_size,
+ "hashtree", signing_key, "SHA256_RSA4096",
+ 10 /* rollback_index */);
+
+ auto header = vbmeta.GetVBMetaHeader(true /* update_vbmeta_size */);
+ size_t header_block_offset = 0;
+ size_t authentication_block_offset = header_block_offset + sizeof(AvbVBMetaImageHeader);
+ size_t auxiliary_block_offset =
+ authentication_block_offset + header->authentication_data_block_size;
+
+ // Should detect modifications in the auxiliary data block.
+ EXPECT_TRUE(TestVBMetaModification(VBMetaVerifyResult::kErrorVerification, vbmeta,
+ auxiliary_block_offset, header->auxiliary_data_block_size));
+
+ // Sholud detect modifications in the hash part of authentication data block.
+ EXPECT_TRUE(TestVBMetaModification(VBMetaVerifyResult::kErrorVerification, vbmeta,
+ authentication_block_offset + header->hash_offset,
+ header->hash_size));
+
+ // Sholud detect modifications in the signature part of authentication data block.
+ EXPECT_TRUE(TestVBMetaModification(VBMetaVerifyResult::kErrorVerification, vbmeta,
+ authentication_block_offset + header->signature_offset,
+ header->signature_size));
+}
+
+TEST_F(AvbUtilTest, VerifyVBMetaSignatureNotSigned) {
+ const size_t image_size = 10 * 1024 * 1024;
+ const size_t partition_size = 15 * 1024 * 1024;
+ auto vbmeta = GenerateImageAndExtractVBMetaData(
+ "system", image_size, partition_size, "hashtree", {} /* avb_signing_key */,
+ "" /* avb_algorithm */, 10 /* rollback_index */);
+
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, VerifyVBMetaSignature(vbmeta, ""));
+}
+
+TEST_F(AvbUtilTest, VerifyVBMetaSignatureInvalidVBMeta) {
+ const size_t buffer_size = 5 * 1024 * 1024;
+ std::vector<uint8_t> vbmeta_buffer(buffer_size);
+ for (size_t n = 0; n < buffer_size; n++) {
+ vbmeta_buffer[n] = uint8_t(n);
+ }
+
+ VBMetaData invalid_vbmeta((const uint8_t*)vbmeta_buffer.data(), vbmeta_buffer.size(),
+ "invalid_vbmeta");
+ EXPECT_EQ(VBMetaVerifyResult::kError, VerifyVBMetaSignature(invalid_vbmeta, ""));
+}
+
+bool AvbUtilTest::CompareVBMeta(const base::FilePath& avb_image_path,
+ const VBMetaData& expected_vbmeta) {
+ if (!base::PathExists(avb_image_path)) return false;
+
+ std::string image_file_name = avb_image_path.RemoveExtension().BaseName().value();
+
+ base::FilePath extracted_vbmeta_path;
+ if (base::StartsWith(image_file_name, "vbmeta", base::CompareCase::INSENSITIVE_ASCII)) {
+ extracted_vbmeta_path = avb_image_path; // no need to extract if it's a vbmeta image.
+ } else {
+ extracted_vbmeta_path = ExtractVBMetaImage(avb_image_path, image_file_name + "-vbmeta.img");
+ }
+
+ // Gets file size of the vbmeta image.
+ int64_t extracted_vbmeta_size;
+ EXPECT_TRUE(base::GetFileSize(extracted_vbmeta_path, &extracted_vbmeta_size));
+
+ // Reads the vbmeta into a vector.
+ std::vector<uint8_t> extracted_vbmeta_content(extracted_vbmeta_size);
+ EXPECT_TRUE(base::ReadFile(extracted_vbmeta_path,
+ reinterpret_cast<char*>(extracted_vbmeta_content.data()),
+ extracted_vbmeta_size));
+
+ // Compares extracted_vbmeta_content with the expected_vbmeta.
+ EXPECT_EQ(expected_vbmeta.size(), extracted_vbmeta_size);
+ return memcmp(reinterpret_cast<void*>(extracted_vbmeta_content.data()),
+ reinterpret_cast<void*>(expected_vbmeta.data()), extracted_vbmeta_size) == 0;
+}
+
+TEST_F(AvbUtilTest, VerifyVBMetaDataWithoutFooter) {
+ // Generates chain partition descriptors.
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+
+ // Makes a vbmeta image includeing 'boot' and 'system' chained descriptors.
+ auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
+ data_dir_.Append("testkey_rsa8192.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"boot", 1, rsa2048_public_key}, /* chain_partitions */
+ {"system", 2, rsa4096_public_key}},
+ "--internal_release_string \"unit test\"");
+ EXPECT_EQ(
+ "Minimum libavb version: 1.0\n"
+ "Header Block: 256 bytes\n"
+ "Authentication Block: 1088 bytes\n"
+ "Auxiliary Block: 3840 bytes\n"
+ "Algorithm: SHA256_RSA8192\n"
+ "Rollback Index: 0\n"
+ "Flags: 0\n"
+ "Release String: 'unit test'\n"
+ "Descriptors:\n"
+ " Chain Partition descriptor:\n"
+ " Partition Name: boot\n"
+ " Rollback Index Location: 1\n"
+ " Public key (sha1): cdbb77177f731920bbe0a0f94f84d9038ae0617d\n"
+ " Chain Partition descriptor:\n"
+ " Partition Name: system\n"
+ " Rollback Index Location: 2\n"
+ " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n",
+ InfoImage("vbmeta.img"));
+
+ android::base::unique_fd fd(open(vbmeta_path.value().c_str(), O_RDONLY | O_CLOEXEC));
+ ASSERT_TRUE(fd > 0);
+
+ VBMetaVerifyResult verify_result;
+ std::unique_ptr<VBMetaData> vbmeta =
+ VerifyVBMetaData(fd, "vbmeta", "" /*expected_public_key_blob */, &verify_result);
+ EXPECT_TRUE(vbmeta != nullptr);
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
+
+ // Checkes the returned vbmeta content is the same as that extracted via avbtool.
+ vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */);
+ EXPECT_TRUE(CompareVBMeta(vbmeta_path, *vbmeta));
+}
+
+TEST_F(AvbUtilTest, VerifyVBMetaDataWithFooter) {
+ const size_t image_size = 10 * 1024 * 1024;
+ const size_t partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", image_size);
+
+ // Appends AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", partition_size, "SHA512_RSA8192", 20,
+ data_dir_.Append("testkey_rsa8192.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ android::base::unique_fd fd(open(system_path.value().c_str(), O_RDONLY | O_CLOEXEC));
+ ASSERT_TRUE(fd > 0);
+
+ VBMetaVerifyResult verify_result;
+ std::unique_ptr<VBMetaData> vbmeta =
+ VerifyVBMetaData(fd, "system", "" /*expected_public_key_blob */, &verify_result);
+ EXPECT_TRUE(vbmeta != nullptr);
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
+
+ // Checkes the returned vbmeta content is the same as that extracted via avbtool.
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
+}
+
+// Modifies a random bit for a file, in the range of [offset, offset + length - 1].
+// Length < 0 means only resets previous modification without introducing new modification.
+void AvbUtilTest::ModifyFile(const base::FilePath& file_path, size_t offset, ssize_t length) {
+ static int last_modified_location = -1;
+ static std::string last_file_path;
+
+ int64_t file_size;
+ ASSERT_TRUE(base::GetFileSize(file_path, &file_size));
+
+ std::vector<uint8_t> file_content(file_size);
+ ASSERT_TRUE(base::ReadFile(file_path, reinterpret_cast<char*>(file_content.data()), file_size));
+
+ // Resets previous modification for consecutive calls on the same file.
+ if (last_file_path == file_path.value()) {
+ file_content[last_modified_location] ^= 0x80;
+ }
+
+ // Introduces a new modification.
+ if (length > 0) {
+ int modify_location = base::RandInt(offset, offset + length - 1);
+ file_content[modify_location] ^= 0x80;
+ last_file_path = file_path.value();
+ last_modified_location = modify_location;
+ }
+
+ ASSERT_EQ(file_size, static_cast<const size_t>(base::WriteFile(
+ file_path, reinterpret_cast<const char*>(file_content.data()),
+ file_content.size())));
+}
+
+TEST_F(AvbUtilTest, VerifyVBMetaDataError) {
+ const size_t image_size = 10 * 1024 * 1024;
+ const size_t partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", image_size);
+
+ // Appends AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", partition_size, "SHA512_RSA8192", 20,
+ data_dir_.Append("testkey_rsa8192.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ android::base::unique_fd fd(open(system_path.value().c_str(), O_RDONLY | O_CLOEXEC));
+ ASSERT_TRUE(fd > 0);
+
+ std::unique_ptr<AvbFooter> footer = GetAvbFooter(fd);
+ EXPECT_TRUE(footer != nullptr);
+
+ VBMetaVerifyResult verify_result;
+ std::unique_ptr<VBMetaData> vbmeta =
+ VerifyVBMetaData(fd, "system", "" /*expected_public_key_blob */, &verify_result);
+ EXPECT_NE(nullptr, vbmeta);
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
+
+ // Modifies hash and signature, checks there is verification error.
+ auto header = vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */);
+ size_t header_block_offset = 0;
+ size_t authentication_block_offset = header_block_offset + sizeof(AvbVBMetaImageHeader);
+
+ // Modifies the hash.
+ ModifyFile(system_path,
+ footer->vbmeta_offset + authentication_block_offset + header->hash_offset,
+ header->hash_size);
+ android::base::unique_fd hash_modified_fd(
+ open(system_path.value().c_str(), O_RDONLY | O_CLOEXEC));
+ ASSERT_TRUE(hash_modified_fd > 0);
+ // Should return ErrorVerification.
+ vbmeta = VerifyVBMetaData(hash_modified_fd, "system", "" /*expected_public_key_blob */,
+ &verify_result);
+ EXPECT_NE(nullptr, vbmeta);
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
+
+ // Modifies the auxiliary data block.
+ size_t auxiliary_block_offset =
+ authentication_block_offset + header->authentication_data_block_size;
+ ModifyFile(system_path, footer->vbmeta_offset + auxiliary_block_offset,
+ header->auxiliary_data_block_size);
+ android::base::unique_fd aux_modified_fd(
+ open(system_path.value().c_str(), O_RDONLY | O_CLOEXEC));
+ ASSERT_TRUE(aux_modified_fd > 0);
+ // Should return ErrorVerification.
+ vbmeta = VerifyVBMetaData(aux_modified_fd, "system", "" /*expected_public_key_blob */,
+ &verify_result);
+ EXPECT_NE(nullptr, vbmeta);
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
+
+ // Resets previous modification by setting offset to -1, and checks the verification can pass.
+ ModifyFile(system_path, 0 /* offset */, -1 /* length */);
+ android::base::unique_fd ok_fd(open(system_path.value().c_str(), O_RDONLY | O_CLOEXEC));
+ ASSERT_TRUE(ok_fd > 0);
+ // Should return ResultOK..
+ vbmeta = VerifyVBMetaData(ok_fd, "system", "" /*expected_public_key_blob */, &verify_result);
+ EXPECT_NE(nullptr, vbmeta);
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
+}
+
+TEST_F(AvbUtilTest, GetChainPartitionInfo) {
+ // Generates a raw boot.img
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ const size_t boot_partition_size = 10 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
+ // Adds AVB Hash Footer.
+ AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
+ data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates a raw system.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", system_image_size);
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
+ data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates chain partition descriptors.
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+ // Makes a vbmeta_system.img including the 'system' chained descriptor.
+ GenerateVBMetaImage("vbmeta_system.img", "SHA256_RSA4096", 0,
+ data_dir_.Append("testkey_rsa4096.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"system", 3, rsa4096_public_key}}, /* chain_partitions */
+ "--internal_release_string \"unit test\"");
+
+ // Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
+ GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0, data_dir_.Append("testkey_rsa8192.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"boot", 1, rsa2048_public_key}, /* chain_partitions */
+ {"vbmeta_system", 2, rsa4096_public_key}},
+ "--internal_release_string \"unit test\"");
+
+ // Calculates the digest of all chained partitions, to ensure the chained is formed properly.
+ EXPECT_EQ("6f4bf815a651aa35ec7102a88b7906b91aef284bc5e20d0bf527c7d460da3266",
+ CalcVBMetaDigest("vbmeta.img", "sha256"));
+ // Loads the key blobs for comparison.
+ std::string expected_key_blob_2048;
+ EXPECT_TRUE(base::ReadFileToString(rsa2048_public_key, &expected_key_blob_2048));
+ std::string expected_key_blob_4096;
+ EXPECT_TRUE(base::ReadFileToString(rsa4096_public_key, &expected_key_blob_4096));
+
+ // Checks chain descriptors in vbmeta.img
+ EXPECT_EQ(
+ "Minimum libavb version: 1.0\n"
+ "Header Block: 256 bytes\n"
+ "Authentication Block: 1088 bytes\n"
+ "Auxiliary Block: 3840 bytes\n"
+ "Algorithm: SHA256_RSA8192\n"
+ "Rollback Index: 0\n"
+ "Flags: 0\n"
+ "Release String: 'unit test'\n"
+ "Descriptors:\n"
+ " Chain Partition descriptor:\n"
+ " Partition Name: boot\n"
+ " Rollback Index Location: 1\n"
+ " Public key (sha1): cdbb77177f731920bbe0a0f94f84d9038ae0617d\n"
+ " Chain Partition descriptor:\n"
+ " Partition Name: vbmeta_system\n"
+ " Rollback Index Location: 2\n"
+ " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n",
+ InfoImage("vbmeta.img"));
+
+ bool fatal_error = false;
+ auto chained_descriptors = GetChainPartitionInfo(LoadVBMetaData("vbmeta.img"), &fatal_error);
+ EXPECT_EQ(2, chained_descriptors.size()); // contains 'boot' and 'vbmeta_system'.
+ EXPECT_EQ(false, fatal_error);
+
+ EXPECT_EQ("boot", chained_descriptors[0].partition_name);
+ EXPECT_EQ(expected_key_blob_2048, chained_descriptors[0].public_key_blob);
+
+ EXPECT_EQ("vbmeta_system", chained_descriptors[1].partition_name);
+ EXPECT_EQ(expected_key_blob_4096, chained_descriptors[1].public_key_blob);
+
+ // Checks chain descriptors in vbmeta_system.img
+ EXPECT_EQ(
+ "Minimum libavb version: 1.0\n"
+ "Header Block: 256 bytes\n"
+ "Authentication Block: 576 bytes\n"
+ "Auxiliary Block: 2176 bytes\n"
+ "Algorithm: SHA256_RSA4096\n"
+ "Rollback Index: 0\n"
+ "Flags: 0\n"
+ "Release String: 'unit test'\n"
+ "Descriptors:\n"
+ " Chain Partition descriptor:\n"
+ " Partition Name: system\n"
+ " Rollback Index Location: 3\n"
+ " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n",
+ InfoImage("vbmeta_system.img"));
+
+ chained_descriptors = GetChainPartitionInfo(LoadVBMetaData("vbmeta_system.img"), &fatal_error);
+ EXPECT_EQ(1, chained_descriptors.size()); // contains 'system' only.
+ EXPECT_EQ(false, fatal_error);
+ EXPECT_EQ("system", chained_descriptors[0].partition_name);
+ EXPECT_EQ(expected_key_blob_4096, chained_descriptors[0].public_key_blob);
+}
+
+TEST_F(AvbUtilTest, GetChainPartitionInfoNone) {
+ // Generates a raw boot.img
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ const size_t boot_partition_size = 10 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
+ // Adds AVB Hash Footer.
+ AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA4096", 10,
+ data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates a raw system.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", system_image_size);
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA8192", 20,
+ data_dir_.Append("testkey_rsa8192.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Makes a vbmeta.img including both 'boot' and 'system' descriptors.
+ GenerateVBMetaImage("vbmeta.img", "SHA256_RSA2048", 0, data_dir_.Append("testkey_rsa2048.pem"),
+ {boot_path, system_path}, /* include_descriptor_image_paths */
+ {}, /* chain_partitions */
+ "--internal_release_string \"unit test\"");
+ EXPECT_EQ("a069cbfc30c816cddf3b53f1ad53b7ca5d61a3d93845eb596bbb1b40caa1c62f",
+ CalcVBMetaDigest("vbmeta.img", "sha256"));
+
+ EXPECT_EQ(
+ "Minimum libavb version: 1.0\n"
+ "Header Block: 256 bytes\n"
+ "Authentication Block: 320 bytes\n"
+ "Auxiliary Block: 960 bytes\n"
+ "Algorithm: SHA256_RSA2048\n"
+ "Rollback Index: 0\n"
+ "Flags: 0\n"
+ "Release String: 'unit test'\n"
+ "Descriptors:\n"
+ " Hash descriptor:\n"
+ " Image Size: 5242880 bytes\n"
+ " Hash Algorithm: sha256\n"
+ " Partition Name: boot\n"
+ " Salt: d00df00d\n"
+ " Digest: "
+ "222dd01e98284a1fcd7781f85d1392e43a530511a64eff96db197db90ebc4df1\n"
+ " Flags: 0\n"
+ " Hashtree descriptor:\n"
+ " Version of dm-verity: 1\n"
+ " Image Size: 10485760 bytes\n"
+ " Tree Offset: 10485760\n"
+ " Tree Size: 86016 bytes\n"
+ " Data Block Size: 4096 bytes\n"
+ " Hash Block Size: 4096 bytes\n"
+ " FEC num roots: 2\n"
+ " FEC offset: 10571776\n"
+ " FEC size: 90112 bytes\n"
+ " Hash Algorithm: sha1\n"
+ " Partition Name: system\n"
+ " Salt: d00df00d\n"
+ " Root Digest: a3d5dd307341393d85de356c384ff543ec1ed81b\n"
+ " Flags: 0\n",
+ InfoImage("vbmeta.img"));
+
+ // Checks none of chain descriptors is found.
+ bool fatal_error = false;
+ auto chained_descriptors = GetChainPartitionInfo(LoadVBMetaData("vbmeta.img"), &fatal_error);
+ EXPECT_EQ(0, chained_descriptors.size()); // There is no chain descriptors.
+ EXPECT_EQ(false, fatal_error);
+}
+
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaImpl) {
+ // Generates a raw boot.img
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ const size_t boot_partition_size = 10 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
+
+ // Adds AVB Hash Footer.
+ AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
+ data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates a raw system.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", system_image_size);
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
+ data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates chain partition descriptors.
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+ // Makes a vbmeta_system.img including the 'system' chained descriptor.
+ auto vbmeta_system_path = GenerateVBMetaImage(
+ "vbmeta_system.img", "SHA256_RSA4096", 0, data_dir_.Append("testkey_rsa4096.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"system", 3, rsa4096_public_key}}, /* chain_partitions */
+ "--internal_release_string \"unit test\"");
+
+ // Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
+ auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
+ data_dir_.Append("testkey_rsa8192.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"boot", 1, rsa2048_public_key}, /* chain_partitions */
+ {"vbmeta_system", 2, rsa4096_public_key}},
+ "--internal_release_string \"unit test\"");
+
+ // Calculates the digest of all chained partitions, to ensure the chained is formed properly.
+ EXPECT_EQ("6f4bf815a651aa35ec7102a88b7906b91aef284bc5e20d0bf527c7d460da3266",
+ CalcVBMetaDigest("vbmeta.img", "sha256"));
+
+ // Starts to test LoadAndVerifyVbmetaImpl.
+ std::vector<VBMetaData> vbmeta_images;
+ auto vbmeta_image_path = [this](const std::string& partition_name) {
+ return test_dir_.Append(partition_name + ".img").value();
+ };
+
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+
+ EXPECT_EQ(4UL, vbmeta_images.size()); // vbmeta, boot, vbmeta_system and system
+ // Binary comparison for each vbmeta image.
+ EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
+ EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
+ EXPECT_TRUE(CompareVBMeta(vbmeta_system_path, vbmeta_images[2]));
+ EXPECT_TRUE(CompareVBMeta(system_path, vbmeta_images[3]));
+
+ // Skip loading chained vbmeta images.
+ vbmeta_images.clear();
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ false /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ // Only vbmeta is loaded.
+ EXPECT_EQ(1UL, vbmeta_images.size());
+ EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
+}
+
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaImplWithSuffixes) {
+ // Tests the following chained partitions.
+ // vbmeta_a.img
+ // |--> boot_b.img (boot_other)
+ // |--> vbmeta_system_b.img (vbmeta_system_other)
+ // |--> system_a.img
+
+ // Generates a raw boot_b.img
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ const size_t boot_partition_size = 10 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot_b.img", boot_image_size);
+
+ // Adds AVB Hash Footer.
+ AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
+ data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates a raw system_a.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system_a.img", system_image_size);
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
+ data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates chain partition descriptors.
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+ // Makes a vbmeta_system_b.img including the 'system' chained descriptor.
+ auto vbmeta_system_path = GenerateVBMetaImage(
+ "vbmeta_system_b.img", "SHA256_RSA4096", 0, data_dir_.Append("testkey_rsa4096.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"system", 3, rsa4096_public_key}}, /* chain_partitions */
+ "--internal_release_string \"unit test\"");
+
+ // Makes a vbmeta_a.img includeing 'boot_other' and 'vbmeta_system_other' chained descriptors.
+ auto vbmeta_path = GenerateVBMetaImage(
+ "vbmeta_a.img", "SHA256_RSA8192", 0, data_dir_.Append("testkey_rsa8192.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"boot_other", 1, rsa2048_public_key}, /* chain_partitions */
+ {"vbmeta_system_other", 2, rsa4096_public_key}},
+ "--internal_release_string \"unit test\"");
+
+ // Starts to test LoadAndVerifyVbmetaImpl with ab_suffix and ab_other_suffix.
+ auto vbmeta_image_path = [this](const std::string& partition_name) {
+ return test_dir_.Append(partition_name + ".img").value();
+ };
+
+ std::vector<VBMetaData> vbmeta_images;
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "_a" /* ab_suffix */, "_b" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+
+ EXPECT_EQ(4UL, vbmeta_images.size()); // vbmeta, boot_other, vbmeta_system_other and system
+ // Binary comparison for each vbmeta image.
+ EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
+ EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
+ EXPECT_TRUE(CompareVBMeta(vbmeta_system_path, vbmeta_images[2]));
+ EXPECT_TRUE(CompareVBMeta(system_path, vbmeta_images[3]));
+
+ // Skips loading chained vbmeta images.
+ vbmeta_images.clear();
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "_a" /* ab_suffix */, "_b" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ false /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ // Only vbmeta is loaded.
+ EXPECT_EQ(1UL, vbmeta_images.size());
+ EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
+
+ // Using an invalid suffix for 'other' slot, checks it returns error.
+ EXPECT_EQ(VBMetaVerifyResult::kError,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "_a" /* ab_suffix */,
+ "_invalid_suffix" /* other_suffix */, "" /* expected_public_key_blob*/,
+ false /* allow_verification_error */, true /* load_chained_vbmeta */,
+ true /* rollback_protection */, vbmeta_image_path,
+ false /* is_chained_vbmeta*/, &vbmeta_images));
+}
+
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaImplErrorVerification) {
+ // Generates a raw boot.img
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ const size_t boot_partition_size = 10 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
+
+ // Adds AVB Hash Footer.
+ AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
+ data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates a raw system.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", system_image_size);
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
+ data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates chain partition descriptors.
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+
+ // Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
+ auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
+ data_dir_.Append("testkey_rsa8192.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"boot", 1, rsa2048_public_key}, /* chain_partitions */
+ {"system", 2, rsa4096_public_key}},
+ "--internal_release_string \"unit test\"");
+
+ // Calculates the digest of all chained partitions, to ensure the chained is formed properly.
+ EXPECT_EQ("abbe11b316901f3336e26630f64c4732dadbe14532186ac8640e4141a403721f",
+ CalcVBMetaDigest("vbmeta.img", "sha256"));
+
+ auto vbmeta = LoadVBMetaData("vbmeta.img");
+
+ // Modifies hash, checks there is error if allow_verification_error is false.
+ auto header = vbmeta.GetVBMetaHeader(true /* update_vbmeta_size */);
+ size_t header_block_offset = 0;
+ size_t authentication_block_offset = header_block_offset + sizeof(AvbVBMetaImageHeader);
+
+ // Modifies the hash.
+ ModifyFile(vbmeta_path, authentication_block_offset + header->hash_offset, header->hash_size);
+
+ // Starts to test LoadAndVerifyVbmetaImpl.
+ std::vector<VBMetaData> vbmeta_images;
+ auto vbmeta_image_path = [this](const std::string& partition_name) {
+ return test_dir_.Append(partition_name + ".img").value();
+ };
+ EXPECT_EQ(VBMetaVerifyResult::kError,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ // Stops to load vbmeta because the top-level vbmeta has verification error.
+ EXPECT_EQ(0UL, vbmeta_images.size());
+
+ // Tries again with verification error allowed.
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "", /* other_suffix */
+ "" /* expected_public_key_blob*/, true /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+
+ EXPECT_EQ(3UL, vbmeta_images.size()); // vbmeta, boot, and system
+ // Binary comparison for each vbmeta image.
+ EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
+ EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
+ EXPECT_TRUE(CompareVBMeta(system_path, vbmeta_images[2]));
+
+ // Resets the modification of the hash.
+ ModifyFile(vbmeta_path, 0 /* offset */, -1 /* length */);
+
+ // Modifies the auxiliary data of system.img
+ auto fd = OpenUniqueReadFd(system_path);
+ auto system_footer = GetAvbFooter(fd);
+ auto system_vbmeta = ExtractAndLoadVBMetaData(system_path, "system-vbmeta.img");
+ auto system_header = system_vbmeta.GetVBMetaHeader(true /* update_vbmeta_size */);
+ size_t auxiliary_block_offset =
+ authentication_block_offset + system_header->authentication_data_block_size;
+
+ // Modifies the auxiliary data block.
+ ModifyFile(system_path, system_footer->vbmeta_offset + auxiliary_block_offset,
+ system_header->auxiliary_data_block_size);
+ vbmeta_images.clear();
+ EXPECT_EQ(VBMetaVerifyResult::kError,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ // 'vbmeta', 'boot' but no 'system', because of verification error.
+ EXPECT_EQ(2UL, vbmeta_images.size());
+ // Binary comparison for the loaded 'vbmeta' and 'boot'.
+ EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
+ EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
+
+ // Resets the modification of the auxiliary data.
+ ModifyFile(vbmeta_path, 0 /* offset */, -1 /* length */);
+
+ // Sets the vbmeta header flags on a chained partition, which introduces an error.
+ ModifyFile(system_path, system_footer->vbmeta_offset + offsetof(AvbVBMetaImageHeader, flags),
+ sizeof(uint32_t));
+ EXPECT_EQ(VBMetaVerifyResult::kError,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, true /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+}
+
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaImplUnexpectedPublicKey) {
+ // Generates chain partition descriptors.
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+ base::FilePath rsa8192_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa8192.pem"));
+
+ // Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
+ auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
+ data_dir_.Append("testkey_rsa8192.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"boot", 1, rsa2048_public_key}, /* chain_partitions */
+ {"system", 2, rsa4096_public_key}},
+ "--internal_release_string \"unit test\"");
+ std::string expected_key_blob_4096;
+ EXPECT_TRUE(base::ReadFileToString(rsa4096_public_key, &expected_key_blob_4096));
+ std::string expected_key_blob_8192;
+ EXPECT_TRUE(base::ReadFileToString(rsa8192_public_key, &expected_key_blob_8192));
+
+ auto vbmeta_image_path = [this](const std::string& partition_name) {
+ return test_dir_.Append(partition_name + ".img").value();
+ };
+ std::vector<VBMetaData> vbmeta_images;
+ // Uses the correct expected public key.
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ expected_key_blob_8192, true /* allow_verification_error */,
+ false /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+
+ // Uses the wrong expected public key with allow_verification_error set to true.
+ vbmeta_images.clear();
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ expected_key_blob_4096, true /* allow_verification_error */,
+ false /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+
+ // Uses the wrong expected public key with allow_verification_error set to false.
+ vbmeta_images.clear();
+ EXPECT_EQ(VBMetaVerifyResult::kError,
+ LoadAndVerifyVbmetaImpl(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ expected_key_blob_4096, false /* allow_verification_error */,
+ false /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+}
+
+} // namespace fs_avb_host_test
diff --git a/fs_mgr/libfs_avb/tests/fs_avb_test.cpp b/fs_mgr/libfs_avb/tests/fs_avb_test.cpp
new file mode 100644
index 0000000..2c819a9
--- /dev/null
+++ b/fs_mgr/libfs_avb/tests/fs_avb_test.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2019 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 <endian.h>
+#include <stdlib.h>
+
+#include <android-base/file.h>
+#include <base/files/file_util.h>
+#include <base/strings/string_util.h>
+#include <fs_avb/fs_avb.h>
+#include <libavb/libavb.h>
+
+#include "fs_avb_test_util.h"
+
+// Target classes or functions to test:
+using android::fs_mgr::AvbHandle;
+using android::fs_mgr::AvbHandleStatus;
+using android::fs_mgr::HashAlgorithm;
+
+namespace fs_avb_host_test {
+
+class PublicFsAvbTest : public BaseFsAvbTest {
+ public:
+ PublicFsAvbTest(){};
+
+ protected:
+ ~PublicFsAvbTest(){};
+ // Modifies |flags| field in the vbmeta header in an Avb image.
+ // e.g., AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED.
+ void ModifyVBMetaHeaderFlags(const base::FilePath& vbmeta_image_path, uint32_t flags);
+};
+
+void PublicFsAvbTest::ModifyVBMetaHeaderFlags(const base::FilePath& vbmeta_image_path,
+ uint32_t flags) {
+ if (!base::PathExists(vbmeta_image_path)) return;
+
+ // Only support modifying the flags in vbmeta*.img.
+ std::string image_file_name = vbmeta_image_path.RemoveExtension().BaseName().value();
+ ASSERT_TRUE(base::StartsWith(image_file_name, "vbmeta", base::CompareCase::INSENSITIVE_ASCII));
+
+ android::base::unique_fd fd(open(vbmeta_image_path.value().c_str(), O_RDWR | O_CLOEXEC));
+ EXPECT_TRUE(fd > 0);
+
+ auto flags_offset = offsetof(AvbVBMetaImageHeader, flags);
+ uint32_t flags_data = htobe32(flags);
+ EXPECT_EQ(flags_offset, lseek64(fd, flags_offset, SEEK_SET));
+ EXPECT_EQ(sizeof flags_data, write(fd, &flags_data, sizeof flags_data));
+}
+
+TEST_F(PublicFsAvbTest, LoadAndVerifyVbmeta) {
+ // Generates a raw boot.img
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ const size_t boot_partition_size = 10 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
+
+ // Adds AVB Hash Footer.
+ AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
+ data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates a raw system.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", system_image_size);
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
+ data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates chain partition descriptors.
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+
+ // Makes a vbmeta image includeing 'boot' and 'system' chained descriptors.
+ auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
+ data_dir_.Append("testkey_rsa8192.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"boot", 1, rsa2048_public_key}, /* chain_partitions */
+ {"system", 2, rsa4096_public_key}},
+ "--internal_release_string \"unit test\"");
+
+ // Calculates the digest of all chained partitions, to ensure the chained is formed properly.
+ EXPECT_EQ("abbe11b316901f3336e26630f64c4732dadbe14532186ac8640e4141a403721f",
+ CalcVBMetaDigest("vbmeta.img", "sha256"));
+
+ // Invokes the public API from fs_avb.h.
+ auto vbmeta_image_path = [this](const std::string& partition_name) {
+ return test_dir_.Append(partition_name + ".img").value();
+ };
+ auto avb_handle = AvbHandle::LoadAndVerifyVbmeta(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
+ false /* allow_verification_error */, true /* load_chained_vbmeta */,
+ true /* rollback_protection */, vbmeta_image_path);
+ EXPECT_NE(nullptr, avb_handle);
+ EXPECT_EQ(AvbHandleStatus::kSuccess, avb_handle->status());
+
+ // Checks the summary info for all vbmeta images.
+ // Checks the digest matches the value calculated by CalcVBMetaDigest().
+ EXPECT_EQ("abbe11b316901f3336e26630f64c4732dadbe14532186ac8640e4141a403721f",
+ avb_handle->vbmeta_info().digest);
+ EXPECT_EQ(8576UL, avb_handle->vbmeta_info().total_size);
+ EXPECT_EQ(HashAlgorithm::kSHA256, avb_handle->vbmeta_info().hash_algorithm);
+
+ // Skip loading chained vbmeta.
+ avb_handle = AvbHandle::LoadAndVerifyVbmeta(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
+ false /* allow_verification_error */, false /* load_chained_vbmeta */,
+ true /* rollback_protection */, vbmeta_image_path);
+ EXPECT_NE(nullptr, avb_handle);
+ EXPECT_EQ(AvbHandleStatus::kSuccess, avb_handle->status());
+ EXPECT_EQ("5c31197992b3c72a854ec7dc0eb9609ffebcffab7917ffd381a99ecee328f09c",
+ avb_handle->vbmeta_info().digest);
+ EXPECT_EQ(5184UL, avb_handle->vbmeta_info().total_size);
+ EXPECT_EQ(HashAlgorithm::kSHA256, avb_handle->vbmeta_info().hash_algorithm);
+}
+
+TEST_F(PublicFsAvbTest, LoadAndVerifyVbmetaWithModifications) {
+ // Generates a raw boot.img
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ const size_t boot_partition_size = 10 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
+
+ // Adds AVB Hash Footer.
+ AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
+ data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates a raw system.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", system_image_size);
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
+ data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates chain partition descriptors.
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+
+ // Makes a vbmeta image includeing 'boot' and 'system' chained descriptors.
+ auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
+ data_dir_.Append("testkey_rsa8192.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"boot", 1, rsa2048_public_key}, /* chain_partitions */
+ {"system", 2, rsa4096_public_key}},
+ "--internal_release_string \"unit test\"");
+
+ // Calculates the digest of all chained partitions, to ensure the chained is formed properly.
+ EXPECT_EQ("abbe11b316901f3336e26630f64c4732dadbe14532186ac8640e4141a403721f",
+ CalcVBMetaDigest("vbmeta.img", "sha256"));
+
+ // Sets AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED in the vbmeta.img.
+ ModifyVBMetaHeaderFlags(vbmeta_path, AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
+
+ auto vbmeta_image_path = [this](const std::string& partition_name) {
+ return test_dir_.Append(partition_name + ".img").value();
+ };
+ auto avb_handle = AvbHandle::LoadAndVerifyVbmeta(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
+ false /* allow_verification_error */, true /* load_chained_vbmeta */,
+ true /* rollback_protection */, vbmeta_image_path);
+ // Returns a null handler because allow_verification is not True.
+ EXPECT_EQ(nullptr, avb_handle);
+
+ // Try again with allow_verification_error set to true.
+ avb_handle = AvbHandle::LoadAndVerifyVbmeta(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
+ true /* allow_verification_error */, true /* load_chained_vbmeta */,
+ true /* rollback_protection */, vbmeta_image_path);
+ EXPECT_NE(nullptr, avb_handle);
+ EXPECT_EQ(AvbHandleStatus::kHashtreeDisabled, avb_handle->status());
+
+ // Checks the summary info for all vbmeta images.
+ // Checks the digest matches the value calculated by CalcVBMetaDigest().
+ EXPECT_EQ("ae8f7ad95cbb7ce4f0feeeedc2a0a39824af5cd29dad4d028597cab4b8c2e83c",
+ CalcVBMetaDigest("vbmeta.img", "sha256"));
+ EXPECT_EQ("ae8f7ad95cbb7ce4f0feeeedc2a0a39824af5cd29dad4d028597cab4b8c2e83c",
+ avb_handle->vbmeta_info().digest);
+ EXPECT_EQ(8576UL, avb_handle->vbmeta_info().total_size);
+ EXPECT_EQ(HashAlgorithm::kSHA256, avb_handle->vbmeta_info().hash_algorithm);
+
+ // Sets AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED in the vbmeta.img.
+ ModifyVBMetaHeaderFlags(vbmeta_path, AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
+ // Loads the vbmeta with allow_verification_error set to true.
+ avb_handle = AvbHandle::LoadAndVerifyVbmeta(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
+ true /* allow_verification_error */, true /* load_chained_vbmeta */,
+ true /* rollback_protection */, vbmeta_image_path);
+ EXPECT_NE(nullptr, avb_handle);
+ EXPECT_EQ(AvbHandleStatus::kVerificationDisabled, avb_handle->status());
+ // Only the top-level vbmeta.img is loaded, when VERIFICATION_DISABLED is set.
+ // However, CalcVBMetaDigest() reads all vbmeta structs to calculate the digest,
+ // including vbmeta.img, boot.img and syste.img. So we don't compare the digest here.
+ EXPECT_EQ(5184UL, avb_handle->vbmeta_info().total_size);
+
+ // Sets a unknown flag in the vbmeta.imgm and expects to get
+ // AvbHandleStatus::kVerificationError.
+ ModifyVBMetaHeaderFlags(vbmeta_path, 0x10000000);
+ // Loads the vbmeta with allow_verification_error set to true.
+ avb_handle = AvbHandle::LoadAndVerifyVbmeta(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, HashAlgorithm::kSHA256,
+ true /* allow_verification_error */, true /* load_chained_vbmeta */,
+ true /* rollback_protection */, vbmeta_image_path);
+ EXPECT_NE(nullptr, avb_handle);
+ EXPECT_EQ(AvbHandleStatus::kVerificationError, avb_handle->status());
+ // Checks the digest matches the value calculated by CalcVBMetaDigest().
+ EXPECT_EQ("8fb99c4f54500053c3582df5eaf04e9a533137398879188aad9968ec19a664f1",
+ CalcVBMetaDigest("vbmeta.img", "sha256"));
+ EXPECT_EQ("8fb99c4f54500053c3582df5eaf04e9a533137398879188aad9968ec19a664f1",
+ avb_handle->vbmeta_info().digest);
+ EXPECT_EQ(8576UL, avb_handle->vbmeta_info().total_size);
+ EXPECT_EQ(HashAlgorithm::kSHA256, avb_handle->vbmeta_info().hash_algorithm);
+}
+
+TEST_F(PublicFsAvbTest, LoadAndVerifyVbmetaWithPublicKeys) {
+ // Generates a raw boot.img
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ const size_t boot_partition_size = 10 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
+
+ // Adds AVB Hash Footer.
+ AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
+ data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates a raw system.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", system_image_size);
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
+ data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates chain partition descriptors.
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+ base::FilePath rsa8192_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa8192.pem"));
+
+ // Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
+ auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
+ data_dir_.Append("testkey_rsa8192.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"boot", 1, rsa2048_public_key}, /* chain_partitions */
+ {"system", 2, rsa4096_public_key}},
+ "--internal_release_string \"unit test\"");
+
+ auto vbmeta_image_path = [this](const std::string& partition_name) {
+ return test_dir_.Append(partition_name + ".img").value();
+ };
+ std::vector<VBMetaData> vbmeta_images;
+ // Uses the correct expected public key.
+ auto avb_handle = AvbHandle::LoadAndVerifyVbmeta(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ rsa8192_public_key.value(), HashAlgorithm::kSHA256, true /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path);
+ EXPECT_NE(nullptr, avb_handle);
+ EXPECT_EQ(AvbHandleStatus::kSuccess, avb_handle->status());
+
+ // Uses a non-existed public key.
+ avb_handle = AvbHandle::LoadAndVerifyVbmeta(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "/path/to/non-existed/key", HashAlgorithm::kSHA256, true /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path);
+ EXPECT_EQ(nullptr, avb_handle);
+
+ // Uses an incorrect public key, with allow_verification_error false.
+ avb_handle = AvbHandle::LoadAndVerifyVbmeta(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ rsa4096_public_key.value(), HashAlgorithm::kSHA256,
+ false /* allow_verification_error */, true /* load_chained_vbmeta */,
+ true /* rollback_protection */, vbmeta_image_path);
+ EXPECT_EQ(nullptr, avb_handle);
+
+ // Uses an incorrect public key, with allow_verification_error true.
+ avb_handle = AvbHandle::LoadAndVerifyVbmeta(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ rsa4096_public_key.value(), HashAlgorithm::kSHA256, true /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path);
+ EXPECT_NE(nullptr, avb_handle);
+ EXPECT_EQ(AvbHandleStatus::kVerificationError, avb_handle->status());
+}
+
+} // namespace fs_avb_host_test
diff --git a/fs_mgr/libfs_avb/tests/fs_avb_test_util.cpp b/fs_mgr/libfs_avb/tests/fs_avb_test_util.cpp
index 95b17d8..17f4c4e 100644
--- a/fs_mgr/libfs_avb/tests/fs_avb_test_util.cpp
+++ b/fs_mgr/libfs_avb/tests/fs_avb_test_util.cpp
@@ -69,7 +69,7 @@
return trimmed_digest_data;
}
-void BaseFsAvbTest::GenerateVBMetaImage(
+base::FilePath BaseFsAvbTest::GenerateVBMetaImage(
const std::string& file_name, const std::string& avb_algorithm, uint64_t rollback_index,
const base::FilePath& key_path,
const std::vector<base::FilePath>& include_descriptor_image_paths,
@@ -107,17 +107,19 @@
chain_partition_options.c_str(), additional_options.c_str(),
vbmeta_image.path.value().c_str());
int64_t file_size;
- ASSERT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size));
+ EXPECT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size));
vbmeta_image.content.resize(file_size);
- ASSERT_TRUE(base::ReadFile(vbmeta_image.path,
+ EXPECT_TRUE(base::ReadFile(vbmeta_image.path,
reinterpret_cast<char*>(vbmeta_image.content.data()), file_size));
// Stores the generated vbmeta image into vbmeta_images_ member object.
vbmeta_images_.emplace(file_name, std::move(vbmeta_image));
+
+ return vbmeta_images_[file_name].path; // returns the path.
}
-void BaseFsAvbTest::ExtractVBMetaImage(const base::FilePath& image_path,
- const std::string& output_file_name,
- const size_t padding_size) {
+base::FilePath BaseFsAvbTest::ExtractVBMetaImage(const base::FilePath& image_path,
+ const std::string& output_file_name,
+ const size_t padding_size) {
VBMetaImage vbmeta_image;
vbmeta_image.path = test_dir_.Append(output_file_name);
EXPECT_COMMAND(0,
@@ -127,12 +129,15 @@
" --padding_size %zu",
image_path.value().c_str(), vbmeta_image.path.value().c_str(), padding_size);
int64_t file_size;
- ASSERT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size));
+ EXPECT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size));
vbmeta_image.content.resize(file_size);
- ASSERT_TRUE(base::ReadFile(vbmeta_image.path,
+ EXPECT_TRUE(base::ReadFile(vbmeta_image.path,
reinterpret_cast<char*>(vbmeta_image.content.data()), file_size));
// Stores the extracted vbmeta image into vbmeta_images_ member object.
vbmeta_images_.emplace(output_file_name, std::move(vbmeta_image));
+
+ // Returns the output file path.
+ return vbmeta_images_[output_file_name].path;
}
// Generates a file with name |file_name| of size |image_size| with
@@ -179,6 +184,49 @@
additional_options.c_str());
}
+VBMetaData BaseFsAvbTest::GenerateImageAndExtractVBMetaData(
+ const std::string& partition_name, const size_t image_size, const size_t partition_size,
+ const std::string& footer_type, const base::FilePath& avb_signing_key,
+ const std::string& avb_algorithm, const uint64_t rollback_index) {
+ // Generates a raw image first
+ base::FilePath image_path = GenerateImage(partition_name + ".img", image_size);
+
+ // Appends AVB Hashtree Footer.
+ AddAvbFooter(image_path, footer_type, partition_name, partition_size, avb_algorithm,
+ rollback_index, avb_signing_key, "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Extracts vbmeta from the ram image into another *-vbmeta.img.
+ auto vbmeta_image = ExtractVBMetaImage(image_path, partition_name + "-vbmeta.img");
+
+ // Loads *-vbmeta.img into a VBMetaData.
+ std::string vbmeta_buffer;
+ EXPECT_TRUE(base::ReadFileToString(vbmeta_image, &vbmeta_buffer));
+
+ return {(const uint8_t*)vbmeta_buffer.data(), vbmeta_buffer.size(), partition_name};
+}
+
+VBMetaData BaseFsAvbTest::LoadVBMetaData(const std::string& file_name) {
+ auto iter = vbmeta_images_.find(file_name);
+ EXPECT_NE(iter, vbmeta_images_.end()); // ensures file_name is generated before.
+
+ // Gets the image path from iterator->second.path: VBMetaImage.path.
+ base::FilePath image_path = iter->second.path;
+
+ // Loads the vbmeta_image into a VBMetaData.
+ std::string vbmeta_buffer;
+ EXPECT_TRUE(base::ReadFileToString(image_path, &vbmeta_buffer));
+
+ std::string partition_name = image_path.RemoveExtension().BaseName().value();
+ return {(const uint8_t*)vbmeta_buffer.data(), vbmeta_buffer.size(), partition_name};
+}
+
+VBMetaData BaseFsAvbTest::ExtractAndLoadVBMetaData(const base::FilePath& image_path,
+ const std::string& output_file_name) {
+ ExtractVBMetaImage(image_path, output_file_name);
+ return LoadVBMetaData(output_file_name);
+}
+
std::string BaseFsAvbTest::InfoImage(const base::FilePath& image_path) {
base::FilePath tmp_path = test_dir_.Append("info_output.txt");
EXPECT_COMMAND(0, "avbtool info_image --image %s --output %s", image_path.value().c_str(),
diff --git a/fs_mgr/libfs_avb/tests/fs_avb_test_util.h b/fs_mgr/libfs_avb/tests/fs_avb_test_util.h
index f80dc5f..2e46644 100644
--- a/fs_mgr/libfs_avb/tests/fs_avb_test_util.h
+++ b/fs_mgr/libfs_avb/tests/fs_avb_test_util.h
@@ -16,14 +16,20 @@
#pragma once
+#include <fcntl.h>
#include <inttypes.h>
#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/wait.h>
+
#include <string>
#include <vector>
+#include <android-base/unique_fd.h>
#include <base/files/file_path.h>
#include <base/strings/stringprintf.h>
+#include <fs_avb/fs_avb.h>
#include <gtest/gtest.h>
// Utility macro to run the command expressed by the printf()-style string
@@ -36,6 +42,8 @@
EXPECT_EQ(WEXITSTATUS(rc), expected_exit_status); \
} while (0);
+using android::fs_mgr::VBMetaData;
+
namespace fs_avb_host_test {
struct VBMetaImage {
@@ -51,6 +59,10 @@
base::FilePath key_blob_path;
};
+inline android::base::unique_fd OpenUniqueReadFd(const base::FilePath& file_path) {
+ return android::base::unique_fd(open(file_path.value().c_str(), O_RDONLY | O_CLOEXEC));
+}
+
/* Base-class used for unit test. */
class BaseFsAvbTest : public ::testing::Test {
public:
@@ -66,16 +78,18 @@
// Generates a vbmeta image with |file_name| by avbtool.
// The generated vbmeta image will be written to disk, see the
// |vbmeta_images_| variable for its path and the content.
- void GenerateVBMetaImage(const std::string& file_name, const std::string& avb_algorithm,
- uint64_t rollback_index, const base::FilePath& key_path,
- const std::vector<base::FilePath>& include_descriptor_image_paths,
- const std::vector<ChainPartitionConfig>& chain_partitions,
- const std::string& additional_options = "");
+ base::FilePath GenerateVBMetaImage(
+ const std::string& file_name, const std::string& avb_algorithm, uint64_t rollback_index,
+ const base::FilePath& key_path,
+ const std::vector<base::FilePath>& include_descriptor_image_paths,
+ const std::vector<ChainPartitionConfig>& chain_partitions,
+ const std::string& additional_options = "");
// Similar to above, but extracts a vbmeta image from the given image_path.
// The extracted vbmeta image will be written to disk, with |output_file_name|.
// See the |vbmeta_images_| variable for its path and the content.
- void ExtractVBMetaImage(const base::FilePath& image_path, const std::string& output_file_name,
- const size_t padding_size = 0);
+ base::FilePath ExtractVBMetaImage(const base::FilePath& image_path,
+ const std::string& output_file_name,
+ const size_t padding_size = 0);
// Generate a file with name |file_name| of size |image_size| with
// known content (0x00 0x01 0x02 .. 0xff 0x00 0x01 ..).
@@ -86,9 +100,19 @@
void AddAvbFooter(const base::FilePath& image_path, const std::string& footer_type,
const std::string& partition_name, const uint64_t partition_size,
const std::string& avb_algorithm, uint64_t rollback_index,
- const base::FilePath& key_path, const std::string& salt = "d00df00d",
+ const base::FilePath& avb_signing_key, const std::string& salt = "d00df00d",
const std::string& additional_options = "");
+ VBMetaData GenerateImageAndExtractVBMetaData(
+ const std::string& partition_name, const size_t image_size, const size_t partition_size,
+ const std::string& footer_type, const base::FilePath& avb_signing_key,
+ const std::string& avb_algorithm, const uint64_t rollback_index);
+
+ VBMetaData ExtractAndLoadVBMetaData(const base::FilePath& image_path,
+ const std::string& output_file_name);
+
+ VBMetaData LoadVBMetaData(const std::string& file_name);
+
// Returns the output of 'avbtool info_image' for the |image_path|.
std::string InfoImage(const base::FilePath& image_path);
// Same as above, but for an internal vbmeta image with |file_name| in |vbmeta_images_|.
diff --git a/fs_mgr/libfs_avb/tests/util_test.cpp b/fs_mgr/libfs_avb/tests/util_test.cpp
index 835e8fd..9e37d22 100644
--- a/fs_mgr/libfs_avb/tests/util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/util_test.cpp
@@ -15,6 +15,7 @@
*/
#include <unistd.h>
+
#include <future>
#include <string>
#include <thread>
diff --git a/fs_mgr/libfs_avb/util.cpp b/fs_mgr/libfs_avb/util.cpp
index 17d47d9..9d4f05f 100644
--- a/fs_mgr/libfs_avb/util.cpp
+++ b/fs_mgr/libfs_avb/util.cpp
@@ -17,6 +17,7 @@
#include "util.h"
#include <sys/ioctl.h>
+
#include <thread>
#include <android-base/unique_fd.h>
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 110d56e..c39fbe7 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -838,9 +838,10 @@
<< block_device.size << ")";
return false;
}
- if (device_info.logical_block_size != geometry_.logical_block_size) {
- LERROR << "Device logical block size does not match (got " << device_info.logical_block_size
- << ", expected " << geometry_.logical_block_size << ")";
+ if (geometry_.logical_block_size % device_info.logical_block_size) {
+ LERROR << "Device logical block size is misaligned (block size="
+ << device_info.logical_block_size << ", alignment=" << geometry_.logical_block_size
+ << ")";
return false;
}
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 7d615a3..8f08169 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -495,6 +495,11 @@
EXPECT_EQ(new_info.size, 1024 * 1024);
new_info.logical_block_size = 512;
+ ASSERT_TRUE(builder->UpdateBlockDeviceInfo("super", new_info));
+ ASSERT_TRUE(builder->GetBlockDeviceInfo("super", &new_info));
+ EXPECT_EQ(new_info.logical_block_size, 4096);
+
+ new_info.logical_block_size = 7;
ASSERT_FALSE(builder->UpdateBlockDeviceInfo("super", new_info));
ASSERT_TRUE(builder->GetBlockDeviceInfo("super", &new_info));
EXPECT_EQ(new_info.logical_block_size, 4096);
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 0765f04..ede0122 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -62,16 +62,17 @@
Returns: true if the command succeeded" ]
adb_sh() {
args=
- for i in ${@}; do
+ for i in "${@}"; do
+ [ -z "${args}" ] || args="${args} "
if [ X"${i}" != X"${i#\'}" ]; then
- args="${args} ${i}"
+ args="${args}${i}"
elif [ X"${i}" != X"${i#* }" ]; then
- args="${args} '${i}'"
+ args="${args}'${i}'"
else
- args="${args} ${i}"
+ args="${args}${i}"
fi
done
- adb shell ${args}
+ adb shell "${args}"
}
[ "USAGE: adb_date >/dev/stdout
@@ -309,7 +310,7 @@
-e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \
-e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
-e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
- -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|metadata\) "
+ -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
}
if [ X"-s" = X"${1}" -a -n "${2}" ]; then
@@ -332,6 +333,12 @@
# Do something
+D=`get_property ro.serialno`
+[ -n "${D}" ] || D=`get_property ro.boot.serialno`
+[ -z "${D}" ] || ANDROID_SERIAL=${D}
+BUILD_DESCRIPTION=`get_property ro.build.description`
+echo "${BLUE}[ INFO ]${NORMAL} ${ANDROID_SERIAL} ${BUILD_DESCRIPTION}" >&2
+
echo "${GREEN}[ RUN ]${NORMAL} Testing kernel support for overlayfs" >&2
overlayfs_supported=true;
@@ -403,9 +410,15 @@
echo "${D}" | grep -v /dev/root`
fi
D=`echo "${D}" | cut -s -d' ' -f1 | sort -u`
+no_dedupe=true
+for d in ${D}; do
+ adb_sh tune2fs -l $d 2>&1 |
+ grep "Filesystem features:.*shared_blocks" >/dev/null &&
+ no_dedupe=false
+done
D=`adb_sh df -k ${D} </dev/null`
echo "${D}"
-if [ X"${D}" = X"${D##* 100[%] }" ]; then
+if [ X"${D}" = X"${D##* 100[%] }" ] && ${no_dedupe} ; then
overlayfs_needed=false
elif ! ${overlayfs_supported}; then
die "need overlayfs, but do not have it"
@@ -547,8 +560,8 @@
echo "${GREEN}[ RUN ]${NORMAL} push content to /system and /vendor" >&2
A="Hello World! $(date)"
-echo "${A}" | adb_sh "cat - > /system/hello"
-echo "${A}" | adb_sh "cat - > /vendor/hello"
+echo "${A}" | adb_sh cat - ">/system/hello"
+echo "${A}" | adb_sh cat - ">/vendor/hello"
B="`adb_cat /system/hello`" ||
die "sytem hello"
check_eq "${A}" "${B}" /system before reboot
@@ -569,7 +582,7 @@
( echo "${L}" && false ) ||
die -d "overlay takeover failed after reboot"
- adb_su "sed -n '1,/overlay \\/system/p' /proc/mounts" </dev/null |
+ adb_su sed -n '1,/overlay \/system/p' /proc/mounts </dev/null |
skip_administrative_mounts |
grep -v ' \(squashfs\|ext4\|f2fs\) ' &&
echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
@@ -597,6 +610,7 @@
echo "${GREEN}[ RUN ]${NORMAL} flash vendor, confirm its content disappears" >&2
H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
+is_userspace_fastboot=false
if [ -z "${ANDROID_PRODUCT_OUT}" ]; then
echo "${ORANGE}[ WARNING ]${NORMAL} build tree not setup, skipping"
elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then
@@ -609,6 +623,8 @@
fastboot flash vendor ||
( fastboot reboot && false) ||
die "fastboot flash vendor"
+ fastboot_getvar is-userspace yes &&
+ is_userspace_fastboot=true
if [ -n "${scratch_paritition}" ]; then
fastboot_getvar partition-type:${scratch_partition} raw ||
( fastboot reboot && false) ||
@@ -654,7 +670,12 @@
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
die "overlay /system takeover after flash vendor"
echo "${D}" | grep "^overlay .* /vendor\$" >/dev/null &&
- die "overlay supposed to be minus /vendor takeover after flash vendor"
+ if ${is_userspace_fastboot}; then
+ die "overlay supposed to be minus /vendor takeover after flash vendor"
+ else
+ echo "${ORANGE}[ WARNING ]${NORMAL} user fastboot missing, ignoring a failure"
+ ( die "overlay supposed to be minus /vendor takeover after flash vendor" )
+ fi
fi
B="`adb_cat /system/hello`" ||
die "re-read /system/hello after flash vendor"
@@ -662,8 +683,17 @@
adb_root ||
die "adb root"
B="`adb_cat /vendor/hello`" &&
- die "re-read /vendor/hello after flash vendor"
- check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
+ if ${is_userspace_fastboot} || ! ${overlayfs_needed}; then
+ die "re-read /vendor/hello after flash vendor"
+ else
+ echo "${ORANGE}[ WARNING ]${NORMAL} user fastboot missing, ignoring a failure"
+ ( die "re-read /vendor/hello after flash vendor" )
+ fi
+ if ${is_userspace_fastboot} || ! ${overlayfs_needed}; then
+ check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
+ else
+ ( check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor )
+ fi
fi
echo "${GREEN}[ RUN ]${NORMAL} remove test content (cleanup)" >&2
@@ -682,17 +712,22 @@
if [ -n "${scratch_partition}" ]; then
- echo "${GREEN}[ RUN ]${NORMAL} test fastboot flash to ${scratch_partition}" >&2
+ echo "${GREEN}[ RUN ]${NORMAL} test fastboot flash to ${scratch_partition} recovery" >&2
adb reboot-fastboot ||
die "Reboot into fastbootd"
+ cleanup() {
+ rm /tmp/adb-remount-test.img
+ }
dd if=/dev/zero of=/tmp/adb-remount-test.img bs=4096 count=16 2>/dev/null &&
fastboot_wait 2m ||
- ( rm /tmp/adb-remount-test.img && false) ||
die "reboot into fastboot"
fastboot flash --force ${scratch_partition} /tmp/adb-remount-test.img
err=${?}
- rm /tmp/adb-remount-test.img
+ cleanup
+ cleanup() {
+ :
+ }
fastboot reboot ||
die "can not reboot out of fastboot"
[ 0 -eq ${err} ] ||
@@ -703,6 +738,8 @@
T=`adb_date`
D=`adb disable-verity 2>&1`
err=${?}
+ adb remount ||
+ die "remount failed"
echo "${D}"
[ ${err} = 0 ] &&
[ X"${D}" = X"${D##*setup failed}" ] &&
@@ -711,4 +748,18 @@
die -t ${T} "setup for overlayfs"
fi
+echo "${GREEN}[ RUN ]${NORMAL} test raw remount command" >&2
+
+# prerequisite is a prepped device from above
+adb_reboot &&
+ adb_wait 2m ||
+ die "lost device after reboot to ro state"
+adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null &&
+ die "/vendor is not read-only"
+adb_su mount -o rw,remount /vendor ||
+ die "remount command"
+adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null ||
+ die "/vendor is not read-write"
+echo "${GREEN}[ OK ]${NORMAL} mount -o rw,remount command works" >&2
+
echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 1922a69..4582401 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -138,38 +138,32 @@
}
TEST(fs_mgr, fs_mgr_read_fstab_file_proc_mounts) {
- auto fstab = fs_mgr_read_fstab("/proc/mounts");
- ASSERT_NE(fstab, nullptr);
+ Fstab fstab;
+ ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &fstab));
std::unique_ptr<std::FILE, int (*)(std::FILE*)> mounts(setmntent("/proc/mounts", "re"),
endmntent);
ASSERT_NE(mounts, nullptr);
mntent* mentry;
- int i = 0;
+ size_t i = 0;
while ((mentry = getmntent(mounts.get())) != nullptr) {
- ASSERT_LT(i, fstab->num_entries);
- auto fsrec = &fstab->recs[i];
+ ASSERT_LT(i, fstab.size());
+ auto& entry = fstab[i];
- std::string mnt_fsname(mentry->mnt_fsname ?: "nullptr");
- std::string blk_device(fsrec->blk_device ?: "nullptr");
- EXPECT_EQ(mnt_fsname, blk_device);
-
- std::string mnt_dir(mentry->mnt_dir ?: "nullptr");
- std::string mount_point(fsrec->mount_point ?: "nullptr");
- EXPECT_EQ(mnt_dir, mount_point);
-
- std::string mnt_type(mentry->mnt_type ?: "nullptr");
- std::string fs_type(fsrec->fs_type ?: "nullptr");
- EXPECT_EQ(mnt_type, fs_type);
+ EXPECT_EQ(mentry->mnt_fsname, entry.blk_device);
+ EXPECT_EQ(mentry->mnt_dir, entry.mount_point);
+ EXPECT_EQ(mentry->mnt_type, entry.fs_type);
std::set<std::string> mnt_opts;
- for (auto& s : android::base::Split(mentry->mnt_opts ?: "nullptr", ",")) {
+ for (auto& s : android::base::Split(mentry->mnt_opts, ",")) {
mnt_opts.emplace(s);
}
std::set<std::string> fs_options;
- for (auto& s : android::base::Split(fsrec->fs_options ?: "nullptr", ",")) {
- fs_options.emplace(s);
+ if (!entry.fs_options.empty()) {
+ for (auto& s : android::base::Split(entry.fs_options, ",")) {
+ fs_options.emplace(s);
+ }
}
// matches private content in fs_mgr_fstab.c
static struct flag_list {
@@ -194,14 +188,17 @@
{0, 0},
};
for (auto f = 0; mount_flags[f].name; ++f) {
- if (mount_flags[f].flag & fsrec->flags) {
+ if (mount_flags[f].flag & entry.flags) {
fs_options.emplace(mount_flags[f].name);
}
}
- if (!(fsrec->flags & MS_RDONLY)) fs_options.emplace("rw");
+ if (!(entry.flags & MS_RDONLY)) {
+ fs_options.emplace("rw");
+ }
EXPECT_EQ(mnt_opts, fs_options);
++i;
}
+ EXPECT_EQ(i, fstab.size());
}
TEST(fs_mgr, ReadFstabFromFile_FsOptions) {
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 80bf84a..2127b96 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -109,6 +109,7 @@
libbase \
libutils \
libcutils \
+ libprocessgroup \
liblog \
libm \
libc \
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index affa39e..153b857 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -73,7 +73,9 @@
bool InitRequiredDevices();
bool InitMappedDevice(const std::string& verity_device);
bool CreateLogicalPartitions();
- bool MountPartition(FstabEntry* fstab_entry);
+ bool MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
+ Fstab::iterator* end = nullptr);
+
bool MountPartitions();
bool TrySwitchSystemAsRoot();
bool TrySkipMountingPartitions();
@@ -385,29 +387,40 @@
return true;
}
-bool FirstStageMount::MountPartition(FstabEntry* fstab_entry) {
- if (fstab_entry->fs_mgr_flags.logical) {
- if (!fs_mgr_update_logical_partition(fstab_entry)) {
+bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
+ Fstab::iterator* end) {
+ if (begin->fs_mgr_flags.logical) {
+ if (!fs_mgr_update_logical_partition(&(*begin))) {
return false;
}
- if (!InitMappedDevice(fstab_entry->blk_device)) {
+ if (!InitMappedDevice(begin->blk_device)) {
return false;
}
}
- if (!SetUpDmVerity(fstab_entry)) {
- PLOG(ERROR) << "Failed to setup verity for '" << fstab_entry->mount_point << "'";
+ if (!SetUpDmVerity(&(*begin))) {
+ PLOG(ERROR) << "Failed to setup verity for '" << begin->mount_point << "'";
return false;
}
- if (fs_mgr_do_mount_one(*fstab_entry)) {
- if (fstab_entry->fs_mgr_flags.formattable) {
- PLOG(INFO) << "Failed to mount '" << fstab_entry->mount_point << "', "
- << "ignoring mount for formattable partition";
- return true;
+
+ bool mounted = (fs_mgr_do_mount_one(*begin) == 0);
+
+ // Try other mounts with the same mount point.
+ Fstab::iterator current = begin + 1;
+ for (; current != fstab_.end() && current->mount_point == begin->mount_point; current++) {
+ if (!mounted) {
+ // blk_device is already updated to /dev/dm-<N> by SetUpDmVerity() above.
+ // Copy it from the begin iterator.
+ current->blk_device = begin->blk_device;
+ mounted = (fs_mgr_do_mount_one(*current) == 0);
}
- PLOG(ERROR) << "Failed to mount '" << fstab_entry->mount_point << "'";
- return false;
}
- return true;
+ if (erase_used_fstab_entry) {
+ current = fstab_.erase(begin, current);
+ }
+ if (end) {
+ *end = current;
+ }
+ return mounted;
}
// If system is in the fstab then we're not a system-as-root device, and in
@@ -418,8 +431,7 @@
return entry.mount_point == "/metadata";
});
if (metadata_partition != fstab_.end()) {
- if (MountPartition(&(*metadata_partition))) {
- fstab_.erase(metadata_partition);
+ if (MountPartition(metadata_partition, true /* erase_used_fstab_entry */)) {
UseGsiIfPresent();
}
}
@@ -430,30 +442,13 @@
if (system_partition == fstab_.end()) return true;
- bool mounted = false;
- bool no_fail = false;
- for (auto it = system_partition; it != fstab_.end();) {
- if (it->mount_point != "/system") {
- break;
- }
- no_fail |= (it->fs_mgr_flags).no_fail;
- if (MountPartition(&(*it))) {
- mounted = true;
- SwitchRoot("/system");
- break;
- }
- it++;
- }
-
- if (!mounted && !no_fail) {
- LOG(ERROR) << "Failed to mount /system";
+ if (MountPartition(system_partition, true /* erase_used_fstab_entry */)) {
+ SwitchRoot("/system");
+ } else {
+ PLOG(ERROR) << "Failed to mount /system";
return false;
}
- auto it = std::remove_if(fstab_.begin(), fstab_.end(),
- [](const auto& entry) { return entry.mount_point == "/system"; });
- fstab_.erase(it, fstab_.end());
-
return true;
}
@@ -490,23 +485,21 @@
if (!TrySkipMountingPartitions()) return false;
- for (auto it = fstab_.begin(); it != fstab_.end();) {
- bool mounted = false;
- bool no_fail = false;
- auto start_mount_point = it->mount_point;
- do {
- no_fail |= (it->fs_mgr_flags).no_fail;
- if (!mounted)
- mounted = MountPartition(&(*it));
- else
- LOG(INFO) << "Skip already-mounted partition: " << start_mount_point;
- it++;
- } while (it != fstab_.end() && it->mount_point == start_mount_point);
-
- if (!mounted && !no_fail) {
- LOG(ERROR) << start_mount_point << " mounted unsuccessfully but it is required!";
- return false;
+ for (auto current = fstab_.begin(); current != fstab_.end();) {
+ Fstab::iterator end;
+ if (!MountPartition(current, false, &end)) {
+ if (current->fs_mgr_flags.no_fail) {
+ LOG(INFO) << "Failed to mount " << current->mount_point
+ << ", ignoring mount for no_fail partition";
+ } else if (current->fs_mgr_flags.formattable) {
+ LOG(INFO) << "Failed to mount " << current->mount_point
+ << ", ignoring mount for formattable partition";
+ } else {
+ PLOG(ERROR) << "Failed to mount " << current->mount_point;
+ return false;
+ }
}
+ current = end;
}
// heads up for instantiating required device(s) for overlayfs logic
diff --git a/init/selinux.cpp b/init/selinux.cpp
index d93e9ec..ee302c1 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -34,16 +34,18 @@
// identical to the system image shipped on a vendor's device.
// The split SEPolicy is loaded as described below:
-// 1) There is a precompiled SEPolicy located at /vendor/etc/selinux/precompiled_sepolicy.
-// Stored along with this file is the sha256 hash of the parts of the SEPolicy on /system that
-// were used to compile this precompiled policy. The system partition contains a similar sha256
-// of the parts of the SEPolicy that it currently contains. If these two hashes match, then the
-// system loads this precompiled_sepolicy directly.
-// 2) If these hashes do not match, then /system has been updated out of sync with /vendor and the
-// init needs to compile the SEPolicy. /system contains the SEPolicy compiler, secilc, and it
-// is used by the LoadSplitPolicy() function below to compile the SEPolicy to a temp directory
-// and load it. That function contains even more documentation with the specific implementation
-// details of how the SEPolicy is compiled if needed.
+// 1) There is a precompiled SEPolicy located at either /vendor/etc/selinux/precompiled_sepolicy or
+// /odm/etc/selinux/precompiled_sepolicy if odm parition is present. Stored along with this file
+// are the sha256 hashes of the parts of the SEPolicy on /system and /product that were used to
+// compile this precompiled policy. The system partition contains a similar sha256 of the parts
+// of the SEPolicy that it currently contains. Symmetrically, product paritition contains a
+// sha256 of its SEPolicy. System loads this precompiled_sepolicy directly if and only if hashes
+// for system policy match and hashes for product policy match.
+// 2) If these hashes do not match, then either /system or /product (or both) have been updated out
+// of sync with /vendor and the init needs to compile the SEPolicy. /system contains the
+// SEPolicy compiler, secilc, and it is used by the LoadSplitPolicy() function below to compile
+// the SEPolicy to a temp directory and load it. That function contains even more documentation
+// with the specific implementation details of how the SEPolicy is compiled if needed.
#include "selinux.h"
@@ -217,20 +219,35 @@
return false;
}
std::string actual_plat_id;
- if (!ReadFirstLine("/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256", &actual_plat_id)) {
+ if (!ReadFirstLine("/system/etc/selinux/plat_sepolicy_and_mapping.sha256", &actual_plat_id)) {
PLOG(INFO) << "Failed to read "
- "/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256";
+ "/system/etc/selinux/plat_sepolicy_and_mapping.sha256";
+ return false;
+ }
+ std::string actual_product_id;
+ if (!ReadFirstLine("/product/etc/selinux/product_sepolicy_and_mapping.sha256",
+ &actual_product_id)) {
+ PLOG(INFO) << "Failed to read "
+ "/product/etc/selinux/product_sepolicy_and_mapping.sha256";
return false;
}
std::string precompiled_plat_id;
- std::string precompiled_sha256 = *file + ".plat_and_mapping.sha256";
- if (!ReadFirstLine(precompiled_sha256.c_str(), &precompiled_plat_id)) {
- PLOG(INFO) << "Failed to read " << precompiled_sha256;
+ std::string precompiled_plat_sha256 = *file + ".plat_sepolicy_and_mapping.sha256";
+ if (!ReadFirstLine(precompiled_plat_sha256.c_str(), &precompiled_plat_id)) {
+ PLOG(INFO) << "Failed to read " << precompiled_plat_sha256;
file->clear();
return false;
}
- if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) {
+ std::string precompiled_product_id;
+ std::string precompiled_product_sha256 = *file + ".product_sepolicy_and_mapping.sha256";
+ if (!ReadFirstLine(precompiled_product_sha256.c_str(), &precompiled_product_id)) {
+ PLOG(INFO) << "Failed to read " << precompiled_product_sha256;
+ file->clear();
+ return false;
+ }
+ if (actual_plat_id.empty() || actual_plat_id != precompiled_plat_id ||
+ actual_product_id.empty() || actual_product_id != precompiled_product_id) {
file->clear();
return false;
}
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 4291212..0dbbc3f 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -66,7 +66,6 @@
"load_file.cpp",
"native_handle.cpp",
"record_stream.cpp",
- "sched_policy.cpp",
"sockets.cpp",
"strdup16to8.cpp",
"strdup8to16.cpp",
@@ -178,8 +177,12 @@
"libbase_headers",
"libcutils_headers",
"libutils_headers",
+ "libprocessgroup_headers",
],
- export_header_lib_headers: ["libcutils_headers"],
+ export_header_lib_headers: [
+ "libcutils_headers",
+ "libprocessgroup_headers",
+ ],
local_include_dirs: ["include"],
cflags: [
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 1490fbc..59cbbc5 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -197,6 +197,9 @@
{ 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) |
CAP_MASK_LONG(CAP_SETGID),
"system/bin/run-as" },
+ { 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) |
+ CAP_MASK_LONG(CAP_SETGID),
+ "system/bin/simpleperf_app_runner" },
// Support FIFO scheduling mode in SurfaceFlinger.
{ 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE),
diff --git a/libcutils/include/cutils/sched_policy.h b/libcutils/include/cutils/sched_policy.h
index cf91b76..538ff6b 100644
--- a/libcutils/include/cutils/sched_policy.h
+++ b/libcutils/include/cutils/sched_policy.h
@@ -17,67 +17,10 @@
#ifndef __CUTILS_SCHED_POLICY_H
#define __CUTILS_SCHED_POLICY_H
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/*
- * Check if Linux kernel enables CPUSETS feature.
- *
- * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise.
+ * For backwards compatibility only
+ * New users should include processgroup/sched_policy.h directly
*/
-extern bool cpusets_enabled();
-
-/*
- * Check if Linux kernel enables SCHEDTUNE feature (only available in Android
- * common kernel or Linaro LSK, not in mainline Linux as of v4.9)
- *
- * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise.
- */
-extern bool schedboost_enabled();
-
-/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */
-typedef enum {
- SP_DEFAULT = -1,
- SP_BACKGROUND = 0,
- SP_FOREGROUND = 1,
- SP_SYSTEM = 2, // can't be used with set_sched_policy()
- SP_AUDIO_APP = 3,
- SP_AUDIO_SYS = 4,
- SP_TOP_APP = 5,
- SP_RT_APP = 6,
- SP_RESTRICTED = 7,
- SP_CNT,
- SP_MAX = SP_CNT - 1,
- SP_SYSTEM_DEFAULT = SP_FOREGROUND,
-} SchedPolicy;
-
-extern int set_cpuset_policy(int tid, SchedPolicy policy);
-
-/* Assign thread tid to the cgroup associated with the specified policy.
- * If the thread is a thread group leader, that is it's gettid() == getpid(),
- * then the other threads in the same thread group are _not_ affected.
- * On platforms which support gettid(), zero tid means current thread.
- * Return value: 0 for success, or -errno for error.
- */
-extern int set_sched_policy(int tid, SchedPolicy policy);
-
-/* Return the policy associated with the cgroup of thread tid via policy pointer.
- * On platforms which support gettid(), zero tid means current thread.
- * Return value: 0 for success, or -1 for error and set errno.
- */
-extern int get_sched_policy(int tid, SchedPolicy *policy);
-
-/* Return a displayable string corresponding to policy.
- * Return value: non-NULL NUL-terminated name of unspecified length;
- * the caller is responsible for displaying the useful part of the string.
- */
-extern const char *get_sched_policy_name(SchedPolicy policy);
-
-#ifdef __cplusplus
-}
-#endif
+#include <processgroup/sched_policy.h>
#endif /* __CUTILS_SCHED_POLICY_H */
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 7884190..72ae559 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -59,6 +59,7 @@
"libcutils",
"liblog",
"libbase",
+ "libprocessgroup",
]
cc_test {
diff --git a/libmeminfo/include/meminfo/pageacct.h b/libmeminfo/include/meminfo/pageacct.h
index 8ddaef2..8483d84 100644
--- a/libmeminfo/include/meminfo/pageacct.h
+++ b/libmeminfo/include/meminfo/pageacct.h
@@ -65,5 +65,17 @@
::android::base::unique_fd pageidle_fd_;
};
+// Returns if the page present bit is set in the value
+// passed in.
+bool page_present(uint64_t pagemap_val);
+
+// Returns if the page swapped bit is set in the value
+// passed in.
+bool page_swapped(uint64_t pagemap_val);
+
+// Returns the page frame number (physical page) from
+// pagemap value
+uint64_t page_pfn(uint64_t pagemap_val);
+
} // namespace meminfo
} // namespace android
diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h
index 0b66074..1fb4151 100644
--- a/libmeminfo/include/meminfo/procmeminfo.h
+++ b/libmeminfo/include/meminfo/procmeminfo.h
@@ -40,6 +40,11 @@
const MemUsage& Usage();
const MemUsage& Wss();
+ // Same as Maps() except, only valid for reading working set using CONFIG_IDLE_PAGE_TRACKING
+ // support in kernel. If the kernel support doesn't exist, the function will return an empty
+ // vector.
+ const std::vector<Vma>& MapsWithPageIdle();
+
// Collect all 'vma' or 'maps' from /proc/<pid>/smaps and store them in 'maps_'. Returns a
// constant reference to the vma vector after the collection is done.
//
@@ -73,11 +78,18 @@
const std::vector<uint16_t>& SwapOffsets();
+ // Reads /proc/<pid>/pagemap for this process for each page within
+ // the 'vma' and stores that in 'pagemap'. It is assumed that the 'vma'
+ // is obtained by calling Maps() or 'ForEachVma' for the same object. No special checks
+ // are made to see if 'vma' is *valid*.
+ // Returns false if anything goes wrong, 'true' otherwise.
+ bool PageMap(const Vma& vma, std::vector<uint64_t>* pagemap);
+
~ProcMemInfo() = default;
private:
- bool ReadMaps(bool get_wss);
- bool ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss);
+ bool ReadMaps(bool get_wss, bool use_pageidle = false);
+ bool ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle);
pid_t pid_;
bool get_wss_;
diff --git a/libmeminfo/include/meminfo/sysmeminfo.h b/libmeminfo/include/meminfo/sysmeminfo.h
index 450a469..8388920 100644
--- a/libmeminfo/include/meminfo/sysmeminfo.h
+++ b/libmeminfo/include/meminfo/sysmeminfo.h
@@ -58,7 +58,7 @@
// in vmalloc area by the kernel.
// Note that this deliberately ignores binder buffers. They are _always_
// mapped in a process and are counted for in each process.
- uint64_t ReadVmallocInfo(const std::string& path = "/proc/vmallocinfo");
+ uint64_t ReadVmallocInfo();
// getters
uint64_t mem_total_kb() { return mem_in_kb_[kMemTotal]; }
@@ -84,5 +84,10 @@
std::function<void(const std::string&, uint64_t)> store_val);
};
+// Parse /proc/vmallocinfo and return total physical memory mapped
+// in vmalloc area by the kernel. Note that this deliberately ignores binder buffers. They are
+// _always_ mapped in a process and are counted for in each process.
+uint64_t ReadVmallocInfo(const std::string& path = "/proc/vmallocinfo");
+
} // namespace meminfo
} // namespace android
diff --git a/libmeminfo/libmeminfo_benchmark.cpp b/libmeminfo/libmeminfo_benchmark.cpp
index 81fc3b3..d88919b 100644
--- a/libmeminfo/libmeminfo_benchmark.cpp
+++ b/libmeminfo/libmeminfo_benchmark.cpp
@@ -455,8 +455,7 @@
std::string vmallocinfo =
::android::base::StringPrintf("%s/testdata1/vmallocinfo", exec_dir.c_str());
for (auto _ : state) {
- SysMemInfo smi;
- CHECK_EQ(smi.ReadVmallocInfo(vmallocinfo), 29884416);
+ CHECK_EQ(::android::meminfo::ReadVmallocInfo(vmallocinfo), 29884416);
}
}
BENCHMARK(BM_VmallocInfo_new);
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 7d85dd2..ccc40d1 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -121,6 +121,23 @@
EXPECT_EQ(proc_usage.swap / getpagesize(), swap_offsets.size());
}
+TEST_F(ValidateProcMemInfo, TestPageMap) {
+ std::vector<uint64_t> pagemap;
+
+ auto vma_callback = [&](const Vma& vma) {
+ uint64_t* pmap_out;
+ size_t len;
+ ASSERT_EQ(0, pm_process_pagemap_range(proc, vma.start, vma.end, &pmap_out, &len));
+ ASSERT_TRUE(proc_mem->PageMap(vma, &pagemap));
+
+ EXPECT_EQ(len, ((vma.end - vma.start) / getpagesize()));
+ for (size_t i = 0; i < len; i++) {
+ EXPECT_EQ(pmap_out[i], pagemap[i]);
+ }
+ };
+ ASSERT_TRUE(proc_mem->ForEachVma(vma_callback));
+}
+
class ValidateProcMemInfoWss : public ::testing::Test {
protected:
void SetUp() override {
@@ -844,8 +861,7 @@
ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
std::string file = std::string(tf.path);
- SysMemInfo smi;
- EXPECT_EQ(smi.ReadVmallocInfo(file), 0);
+ EXPECT_EQ(ReadVmallocInfo(file), 0);
}
TEST(SysMemInfoParser, TestVmallocInfoKernel) {
@@ -857,8 +873,7 @@
ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
std::string file = std::string(tf.path);
- SysMemInfo smi;
- EXPECT_EQ(smi.ReadVmallocInfo(file), getpagesize());
+ EXPECT_EQ(ReadVmallocInfo(file), getpagesize());
}
TEST(SysMemInfoParser, TestVmallocInfoModule) {
@@ -870,8 +885,7 @@
ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
std::string file = std::string(tf.path);
- SysMemInfo smi;
- EXPECT_EQ(smi.ReadVmallocInfo(file), 6 * getpagesize());
+ EXPECT_EQ(ReadVmallocInfo(file), 6 * getpagesize());
}
TEST(SysMemInfoParser, TestVmallocInfoAll) {
@@ -888,8 +902,7 @@
ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
std::string file = std::string(tf.path);
- SysMemInfo smi;
- EXPECT_EQ(smi.ReadVmallocInfo(file), 7 * getpagesize());
+ EXPECT_EQ(ReadVmallocInfo(file), 7 * getpagesize());
}
int main(int argc, char** argv) {
diff --git a/libmeminfo/pageacct.cpp b/libmeminfo/pageacct.cpp
index 887a74d..0a26c08 100644
--- a/libmeminfo/pageacct.cpp
+++ b/libmeminfo/pageacct.cpp
@@ -138,5 +138,18 @@
return !!(idle_bits & (1ULL << (pfn % 64)));
}
+// Public methods
+bool page_present(uint64_t pagemap_val) {
+ return PAGE_PRESENT(pagemap_val);
+}
+
+bool page_swapped(uint64_t pagemap_val) {
+ return PAGE_SWAPPED(pagemap_val);
+}
+
+uint64_t page_pfn(uint64_t pagemap_val) {
+ return PAGE_PFN(pagemap_val);
+}
+
} // namespace meminfo
} // namespace android
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index d6332a3..069b6b3 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -121,6 +121,14 @@
return maps_;
}
+const std::vector<Vma>& ProcMemInfo::MapsWithPageIdle() {
+ if (maps_.empty() && !ReadMaps(get_wss_, true)) {
+ LOG(ERROR) << "Failed to read maps with page idle for Process " << pid_;
+ }
+
+ return maps_;
+}
+
const std::vector<Vma>& ProcMemInfo::Smaps(const std::string& path) {
if (!maps_.empty()) {
return maps_;
@@ -199,7 +207,34 @@
return swap_offsets_;
}
-bool ProcMemInfo::ReadMaps(bool get_wss) {
+bool ProcMemInfo::PageMap(const Vma& vma, std::vector<uint64_t>* pagemap) {
+ pagemap->clear();
+ std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid_);
+ ::android::base::unique_fd pagemap_fd(
+ TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (pagemap_fd < 0) {
+ PLOG(ERROR) << "Failed to open " << pagemap_file;
+ return false;
+ }
+
+ uint64_t nr_pages = (vma.end - vma.start) / getpagesize();
+ pagemap->reserve(nr_pages);
+
+ uint64_t idx = vma.start / getpagesize();
+ uint64_t last = idx + nr_pages;
+ uint64_t val;
+ for (; idx < last; idx++) {
+ if (pread64(pagemap_fd, &val, sizeof(uint64_t), idx * sizeof(uint64_t)) < 0) {
+ PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
+ return false;
+ }
+ pagemap->emplace_back(val);
+ }
+
+ return true;
+}
+
+bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle) {
// Each object reads /proc/<pid>/maps only once. This is done to make sure programs that are
// running for the lifetime of the system can recycle the objects and don't have to
// unnecessarily retain and update this object in memory (which can get significantly large).
@@ -229,7 +264,7 @@
}
for (auto& vma : maps_) {
- if (!ReadVmaStats(pagemap_fd.get(), vma, get_wss)) {
+ if (!ReadVmaStats(pagemap_fd.get(), vma, get_wss, use_pageidle)) {
LOG(ERROR) << "Failed to read page map for vma " << vma.name << "[" << vma.start << "-"
<< vma.end << "]";
maps_.clear();
@@ -241,7 +276,7 @@
return true;
}
-bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss) {
+bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle) {
PageAcct& pinfo = PageAcct::Instance();
uint64_t pagesz = getpagesize();
uint64_t num_pages = (vma.end - vma.start) / pagesz;
@@ -254,6 +289,13 @@
return false;
}
+ if (get_wss && use_pageidle) {
+ if (!pinfo.InitPageAcct(true)) {
+ LOG(ERROR) << "Failed to init idle page accounting";
+ return false;
+ }
+ }
+
std::unique_ptr<uint64_t[]> pg_flags(new uint64_t[num_pages]);
std::unique_ptr<uint64_t[]> pg_counts(new uint64_t[num_pages]);
for (uint64_t i = 0; i < num_pages; ++i) {
@@ -296,7 +338,8 @@
bool is_private = (pg_counts[i] == 1);
// Working set
if (get_wss) {
- bool is_referenced = !!(pg_flags[i] & (1 << KPF_REFERENCED));
+ bool is_referenced = use_pageidle ? (pinfo.IsPageIdle(page_frame) == 1)
+ : !!(pg_flags[i] & (1 << KPF_REFERENCED));
if (!is_referenced) {
continue;
}
diff --git a/libmeminfo/sysmeminfo.cpp b/libmeminfo/sysmeminfo.cpp
index 8fd18d0..5cfa6c3 100644
--- a/libmeminfo/sysmeminfo.cpp
+++ b/libmeminfo/sysmeminfo.cpp
@@ -79,36 +79,8 @@
});
}
-uint64_t SysMemInfo::ReadVmallocInfo(const std::string& path) {
- uint64_t vmalloc_total = 0;
- auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
- if (fp == nullptr) {
- return vmalloc_total;
- }
-
- char line[1024];
- while (fgets(line, 1024, fp.get()) != nullptr) {
- // We are looking for lines like
- // 0x0000000000000000-0x0000000000000000 12288 drm_property_create_blob+0x44/0xec pages=2
- // vmalloc 0x0000000000000000-0x0000000000000000 8192
- // wlan_logging_sock_init_svc+0xf8/0x4f0 [wlan] pages=1 vmalloc Notice that if the caller is
- // coming from a module, the kernel prints and extra "[module_name]" after the address and
- // the symbol of the call site. This means we can't use the old sscanf() method of getting
- // the # of pages.
- char* p_start = strstr(line, "pages=");
- if (p_start == nullptr) {
- // we didn't find anything
- continue;
- }
-
- p_start = strtok(p_start, " ");
- long nr_pages;
- if (sscanf(p_start, "pages=%ld", &nr_pages) == 1) {
- vmalloc_total += (nr_pages * getpagesize());
- }
- }
-
- return vmalloc_total;
+uint64_t SysMemInfo::ReadVmallocInfo() {
+ return ::android::meminfo::ReadVmallocInfo();
}
// TODO: Delete this function if it can't match up with the c-like implementation below.
@@ -263,5 +235,41 @@
return false;
}
+// Public methods
+uint64_t ReadVmallocInfo(const std::string& path) {
+ uint64_t vmalloc_total = 0;
+ auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+ if (fp == nullptr) {
+ return vmalloc_total;
+ }
+
+ char* line = nullptr;
+ size_t line_alloc = 0;
+ while (getline(&line, &line_alloc, fp.get()) > 0) {
+ // We are looking for lines like
+ //
+ // 0x0000000000000000-0x0000000000000000 12288 drm_property_create_blob+0x44/0xec pages=2 vmalloc
+ // 0x0000000000000000-0x0000000000000000 8192 wlan_logging_sock_init_svc+0xf8/0x4f0 [wlan] pages=1 vmalloc
+ //
+ // Notice that if the caller is coming from a module, the kernel prints and extra
+ // "[module_name]" after the address and the symbol of the call site. This means we can't
+ // use the old sscanf() method of getting the # of pages.
+ char* p_start = strstr(line, "pages=");
+ if (p_start == nullptr) {
+ // we didn't find anything
+ continue;
+ }
+
+ uint64_t nr_pages;
+ if (sscanf(p_start, "pages=%" SCNu64 "", &nr_pages) == 1) {
+ vmalloc_total += (nr_pages * getpagesize());
+ }
+ }
+
+ free(line);
+
+ return vmalloc_total;
+}
+
} // namespace meminfo
} // namespace android
diff --git a/libmeminfo/tools/Android.bp b/libmeminfo/tools/Android.bp
index 24054c6..2e89c41 100644
--- a/libmeminfo/tools/Android.bp
+++ b/libmeminfo/tools/Android.bp
@@ -67,3 +67,17 @@
"libmeminfo",
],
}
+
+cc_binary {
+ name: "wsstop",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ srcs: ["wsstop.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libmeminfo",
+ ],
+}
diff --git a/libmeminfo/tools/wsstop.cpp b/libmeminfo/tools/wsstop.cpp
new file mode 100644
index 0000000..368d04e
--- /dev/null
+++ b/libmeminfo/tools/wsstop.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2019 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 <getopt.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <meminfo/pageacct.h>
+#include <meminfo/procmeminfo.h>
+
+using ::android::meminfo::ProcMemInfo;
+using ::android::meminfo::Vma;
+
+// Global options
+static int32_t g_delay = 0;
+static int32_t g_total = 2;
+static pid_t g_pid = -1;
+
+[[noreturn]] static void usage(int exit_status) {
+ fprintf(stderr,
+ "%s [-d DELAY_BETWEEN_EACH_SAMPLE] [-n REFRESH_TOTAL] PID\n"
+ "-d\tdelay between each working set sample (default 0)\n"
+ "-n\ttotal number of refreshes before we exit (default 2)\n",
+ getprogname());
+
+ exit(exit_status);
+}
+
+static void print_header() {
+ const char* addr1 = " start end ";
+ const char* addr2 = " addr addr ";
+
+ printf("%s virtual shared shared private private\n", addr1);
+ printf("%s size RSS PSS clean dirty clean dirty swap "
+ "swapPSS",
+ addr2);
+ printf(" object\n");
+}
+
+static void print_divider() {
+ printf("---------------- ---------------- ");
+ printf("--------- --------- --------- --------- --------- --------- --------- --------- "
+ "--------- ");
+ printf("------------------------------\n");
+}
+
+static void print_vma(const Vma& v) {
+ printf("%16" PRIx64 " %16" PRIx64 " ", v.start, v.end);
+ printf("%8" PRIu64 "K %8" PRIu64 "K %8" PRIu64 "K %8" PRIu64 "K %8" PRIu64 "K %8" PRIu64
+ "K %8" PRIu64 "K %8" PRIu64 "K %8" PRIu64 "K ",
+ v.usage.vss / 1024, v.usage.rss / 1024, v.usage.pss / 1024, v.usage.shared_clean / 1024,
+ v.usage.shared_dirty / 1024, v.usage.private_clean / 1024, v.usage.private_dirty / 1024,
+ v.usage.swap / 1024, v.usage.swap_pss / 1024);
+ printf("%s\n", v.name.c_str());
+}
+
+static bool same_vma(const Vma& cur, const Vma& last) {
+ return (cur.start == last.start && cur.end == last.end && cur.name == last.name &&
+ cur.flags == last.flags && cur.offset == last.offset);
+}
+
+static Vma diff_vma_params(const Vma& cur, const Vma& last) {
+ Vma res;
+ res.usage.shared_clean = cur.usage.shared_clean > last.usage.shared_clean
+ ? cur.usage.shared_clean - last.usage.shared_clean
+ : 0;
+ res.usage.shared_dirty = cur.usage.shared_dirty > last.usage.shared_dirty
+ ? cur.usage.shared_dirty - last.usage.shared_dirty
+ : 0;
+ res.usage.private_clean = cur.usage.private_clean > last.usage.private_clean
+ ? cur.usage.private_clean - last.usage.private_clean
+ : 0;
+ res.usage.private_dirty = cur.usage.private_dirty > last.usage.private_dirty
+ ? cur.usage.private_dirty - last.usage.private_dirty
+ : 0;
+
+ res.usage.rss = cur.usage.rss > last.usage.rss ? cur.usage.rss - last.usage.rss : 0;
+ res.usage.pss = cur.usage.pss > last.usage.pss ? cur.usage.pss - last.usage.pss : 0;
+ res.usage.uss = cur.usage.uss > last.usage.uss ? cur.usage.uss - last.usage.uss : 0;
+ res.usage.swap = cur.usage.swap > last.usage.swap ? cur.usage.swap - last.usage.swap : 0;
+ res.usage.swap_pss =
+ cur.usage.swap_pss > last.usage.swap_pss ? cur.usage.swap_pss - last.usage.swap_pss : 0;
+
+ // set vma properties to the same as the current one.
+ res.start = cur.start;
+ res.end = cur.end;
+ res.offset = cur.offset;
+ res.flags = cur.flags;
+ res.name = cur.name;
+ return res;
+}
+
+static void diff_workingset(std::vector<Vma>& wss, std::vector<Vma>& old, std::vector<Vma>* res) {
+ res->clear();
+ auto vma_sorter = [](const Vma& a, const Vma& b) { return a.start < b.start; };
+ std::sort(wss.begin(), wss.end(), vma_sorter);
+ std::sort(old.begin(), old.end(), vma_sorter);
+ if (old.empty()) {
+ *res = wss;
+ return;
+ }
+
+ for (auto& i : wss) {
+ bool found_same_vma = false;
+ // TODO: This is highly inefficient, fix it if it takes
+ // too long. Worst case will be system_server
+ for (auto& j : old) {
+ if (same_vma(i, j)) {
+ res->emplace_back(diff_vma_params(i, j));
+ found_same_vma = true;
+ break;
+ }
+ }
+
+ if (!found_same_vma) {
+ res->emplace_back(i);
+ }
+ }
+
+ std::sort(res->begin(), res->end(), vma_sorter);
+ return;
+}
+
+static int workingset() {
+ std::vector<Vma> last_wss = {};
+ std::vector<Vma> diff_wss = {};
+ uint32_t nr_refresh = 0;
+
+ while (true) {
+ std::unique_ptr<ProcMemInfo> proc_mem = std::make_unique<ProcMemInfo>(g_pid, true);
+ std::vector<Vma> wss = proc_mem->MapsWithPageIdle();
+
+ diff_workingset(wss, last_wss, &diff_wss);
+ diff_wss.erase(std::remove_if(diff_wss.begin(), diff_wss.end(),
+ [](const auto& v) { return v.usage.rss == 0; }),
+ diff_wss.end());
+ if ((nr_refresh % 5) == 0) {
+ print_header();
+ print_divider();
+ }
+
+ for (const auto& v : diff_wss) {
+ print_vma(v);
+ }
+
+ nr_refresh++;
+ if (nr_refresh == g_total) {
+ break;
+ }
+
+ last_wss = wss;
+ sleep(g_delay);
+ print_divider();
+ }
+
+ return 0;
+}
+
+int main(int argc, char* argv[]) {
+ struct option longopts[] = {
+ {"help", no_argument, nullptr, 'h'},
+ {0, 0, nullptr, 0},
+ };
+
+ int opt;
+ while ((opt = getopt_long(argc, argv, "d:n:h", longopts, nullptr)) != -1) {
+ switch (opt) {
+ case 'd':
+ g_delay = atoi(optarg);
+ break;
+ case 'n':
+ g_total = atoi(optarg);
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ default:
+ usage(EXIT_FAILURE);
+ }
+ }
+
+ if ((argc - 1) < optind) {
+ fprintf(stderr, "Invalid arguments: Must provide <pid> at the end\n");
+ usage(EXIT_FAILURE);
+ }
+
+ g_pid = atoi(argv[optind]);
+ if (g_pid <= 0) {
+ fprintf(stderr, "Invalid process id %s\n", argv[optind]);
+ usage(EXIT_FAILURE);
+ }
+
+ if (!::android::meminfo::PageAcct::KernelHasPageIdle()) {
+ fprintf(stderr, "Missing support for Idle page tracking in the kernel\n");
+ return 0;
+ }
+
+ return workingset();
+}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index ab17b29..ad967db 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -43,10 +43,6 @@
#include <android-base/properties.h>
#endif
-extern "C" {
-struct android_namespace_t* android_get_exported_namespace(const char*);
-}
-
#define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
"%s:%d: %s CHECK '" #predicate "' failed.",\
__FILE__, __LINE__, __FUNCTION__)
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index c38279d..d04a79a 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -1,10 +1,45 @@
+cc_library_headers {
+ name: "libprocessgroup_headers",
+ vendor_available: true,
+ recovery_available: true,
+ host_supported: true,
+ export_include_dirs: ["include"],
+ target: {
+ linux_bionic: {
+ enabled: true,
+ },
+ windows: {
+ enabled: true,
+ },
+ },
+}
+
cc_library {
- srcs: ["processgroup.cpp"],
+ srcs: [
+ "processgroup.cpp",
+ "sched_policy.cpp",
+ ],
name: "libprocessgroup",
host_supported: true,
recovery_available: true,
- shared_libs: ["libbase"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+ // for cutils/android_filesystem_config.h
+ header_libs: [
+ "libcutils_headers",
+ "libprocessgroup_headers",
+ ],
export_include_dirs: ["include"],
+ export_header_lib_headers: [
+ "libprocessgroup_headers",
+ ],
cflags: [
"-Wall",
"-Werror",
diff --git a/libprocessgroup/include/processgroup/sched_policy.h b/libprocessgroup/include/processgroup/sched_policy.h
new file mode 100644
index 0000000..79a32fd
--- /dev/null
+++ b/libprocessgroup/include/processgroup/sched_policy.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Check if Linux kernel enables CPUSETS feature.
+ *
+ * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise.
+ */
+extern bool cpusets_enabled();
+
+/*
+ * Check if Linux kernel enables SCHEDTUNE feature (only available in Android
+ * common kernel or Linaro LSK, not in mainline Linux as of v4.9)
+ *
+ * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise.
+ */
+extern bool schedboost_enabled();
+
+/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */
+typedef enum {
+ SP_DEFAULT = -1,
+ SP_BACKGROUND = 0,
+ SP_FOREGROUND = 1,
+ SP_SYSTEM = 2, // can't be used with set_sched_policy()
+ SP_AUDIO_APP = 3,
+ SP_AUDIO_SYS = 4,
+ SP_TOP_APP = 5,
+ SP_RT_APP = 6,
+ SP_RESTRICTED = 7,
+ SP_CNT,
+ SP_MAX = SP_CNT - 1,
+ SP_SYSTEM_DEFAULT = SP_FOREGROUND,
+} SchedPolicy;
+
+extern int set_cpuset_policy(int tid, SchedPolicy policy);
+
+/* Assign thread tid to the cgroup associated with the specified policy.
+ * If the thread is a thread group leader, that is it's gettid() == getpid(),
+ * then the other threads in the same thread group are _not_ affected.
+ * On platforms which support gettid(), zero tid means current thread.
+ * Return value: 0 for success, or -errno for error.
+ */
+extern int set_sched_policy(int tid, SchedPolicy policy);
+
+/* Return the policy associated with the cgroup of thread tid via policy pointer.
+ * On platforms which support gettid(), zero tid means current thread.
+ * Return value: 0 for success, or -1 for error and set errno.
+ */
+extern int get_sched_policy(int tid, SchedPolicy *policy);
+
+/* Return a displayable string corresponding to policy.
+ * Return value: non-NULL NUL-terminated name of unspecified length;
+ * the caller is responsible for displaying the useful part of the string.
+ */
+extern const char *get_sched_policy_name(SchedPolicy policy);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 9df8dd9..8d2ac3d 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -42,7 +42,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <private/android_filesystem_config.h>
+#include <cutils/android_filesystem_config.h>
#include <processgroup/processgroup.h>
diff --git a/libcutils/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
similarity index 99%
rename from libcutils/sched_policy.cpp
rename to libprocessgroup/sched_policy.cpp
index 3fa548f..f95d7e4 100644
--- a/libcutils/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -14,7 +14,7 @@
** limitations under the License.
*/
-#include <cutils/sched_policy.h>
+#include <processgroup/sched_policy.h>
#define LOG_TAG "SchedPolicy"
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index 8ad339f..2ec4754 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -67,3 +67,18 @@
cflags: ["-Werror"],
}
+
+python_binary_host {
+ name: "simg_dump.py",
+ main: "simg_dump.py",
+ srcs: ["simg_dump.py"],
+ version: {
+ py2: {
+ embedded_launcher: true,
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+}
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
deleted file mode 100644
index 05e68bc..0000000
--- a/libsparse/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2010 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := simg_dump.py
-LOCAL_SRC_FILES := simg_dump.py
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_IS_HOST_MODULE := true
-LOCAL_CFLAGS := -Werror
-include $(BUILD_PREBUILT)
diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp
index 5bc60b9..393eb3e 100644
--- a/libunwindstack/DwarfOp.cpp
+++ b/libunwindstack/DwarfOp.cpp
@@ -32,8 +32,1451 @@
namespace unwindstack {
+enum DwarfOpHandleFunc : uint8_t {
+ OP_ILLEGAL = 0,
+ OP_DEREF,
+ OP_DEREF_SIZE,
+ OP_PUSH,
+ OP_DUP,
+ OP_DROP,
+ OP_OVER,
+ OP_PICK,
+ OP_SWAP,
+ OP_ROT,
+ OP_ABS,
+ OP_AND,
+ OP_DIV,
+ OP_MINUS,
+ OP_MOD,
+ OP_MUL,
+ OP_NEG,
+ OP_NOT,
+ OP_OR,
+ OP_PLUS,
+ OP_PLUS_UCONST,
+ OP_SHL,
+ OP_SHR,
+ OP_SHRA,
+ OP_XOR,
+ OP_BRA,
+ OP_EQ,
+ OP_GE,
+ OP_GT,
+ OP_LE,
+ OP_LT,
+ OP_NE,
+ OP_SKIP,
+ OP_LIT,
+ OP_REG,
+ OP_REGX,
+ OP_BREG,
+ OP_BREGX,
+ OP_NOP,
+ OP_NOT_IMPLEMENTED,
+};
+
+struct OpCallback {
+ // It may seem tempting to "clean this up" by replacing "const char[26]" with
+ // "const char*", but doing so would place the entire callback table in
+ // .data.rel.ro section, instead of .rodata section, and thus increase
+ // dirty memory usage. Libunwindstack is used by the linker and therefore
+ // loaded for every running process, so every bit of memory counts.
+ // Unlike C standard, C++ standard guarantees this array is big enough to
+ // store the names, or else we would get a compilation error.
+ const char name[26];
+
+ // Similarily for this field, we do NOT want to directly store function
+ // pointers here. Not only would that cause the callback table to be placed
+ // in .data.rel.ro section, but it would be duplicated for each AddressType.
+ // Instead, we use DwarfOpHandleFunc enum to decouple the callback table from
+ // the function pointers.
+ DwarfOpHandleFunc handle_func;
+
+ uint8_t num_required_stack_values;
+ uint8_t num_operands;
+ uint8_t operands[2];
+};
+
+constexpr static OpCallback kCallbackTable[256] = {
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0x00 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0x01 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0x02 illegal op
+ {
+ // 0x03 DW_OP_addr
+ "DW_OP_addr",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_absptr},
+ },
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0x04 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0x05 illegal op
+ {
+ // 0x06 DW_OP_deref
+ "DW_OP_deref",
+ OP_DEREF,
+ 1,
+ 0,
+ {},
+ },
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0x07 illegal op
+ {
+ // 0x08 DW_OP_const1u
+ "DW_OP_const1u",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_udata1},
+ },
+ {
+ // 0x09 DW_OP_const1s
+ "DW_OP_const1s",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_sdata1},
+ },
+ {
+ // 0x0a DW_OP_const2u
+ "DW_OP_const2u",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_udata2},
+ },
+ {
+ // 0x0b DW_OP_const2s
+ "DW_OP_const2s",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_sdata2},
+ },
+ {
+ // 0x0c DW_OP_const4u
+ "DW_OP_const4u",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_udata4},
+ },
+ {
+ // 0x0d DW_OP_const4s
+ "DW_OP_const4s",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_sdata4},
+ },
+ {
+ // 0x0e DW_OP_const8u
+ "DW_OP_const8u",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_udata8},
+ },
+ {
+ // 0x0f DW_OP_const8s
+ "DW_OP_const8s",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_sdata8},
+ },
+ {
+ // 0x10 DW_OP_constu
+ "DW_OP_constu",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_uleb128},
+ },
+ {
+ // 0x11 DW_OP_consts
+ "DW_OP_consts",
+ OP_PUSH,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x12 DW_OP_dup
+ "DW_OP_dup",
+ OP_DUP,
+ 1,
+ 0,
+ {},
+ },
+ {
+ // 0x13 DW_OP_drop
+ "DW_OP_drop",
+ OP_DROP,
+ 1,
+ 0,
+ {},
+ },
+ {
+ // 0x14 DW_OP_over
+ "DW_OP_over",
+ OP_OVER,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x15 DW_OP_pick
+ "DW_OP_pick",
+ OP_PICK,
+ 0,
+ 1,
+ {DW_EH_PE_udata1},
+ },
+ {
+ // 0x16 DW_OP_swap
+ "DW_OP_swap",
+ OP_SWAP,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x17 DW_OP_rot
+ "DW_OP_rot",
+ OP_ROT,
+ 3,
+ 0,
+ {},
+ },
+ {
+ // 0x18 DW_OP_xderef
+ "DW_OP_xderef",
+ OP_NOT_IMPLEMENTED,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x19 DW_OP_abs
+ "DW_OP_abs",
+ OP_ABS,
+ 1,
+ 0,
+ {},
+ },
+ {
+ // 0x1a DW_OP_and
+ "DW_OP_and",
+ OP_AND,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x1b DW_OP_div
+ "DW_OP_div",
+ OP_DIV,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x1c DW_OP_minus
+ "DW_OP_minus",
+ OP_MINUS,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x1d DW_OP_mod
+ "DW_OP_mod",
+ OP_MOD,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x1e DW_OP_mul
+ "DW_OP_mul",
+ OP_MUL,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x1f DW_OP_neg
+ "DW_OP_neg",
+ OP_NEG,
+ 1,
+ 0,
+ {},
+ },
+ {
+ // 0x20 DW_OP_not
+ "DW_OP_not",
+ OP_NOT,
+ 1,
+ 0,
+ {},
+ },
+ {
+ // 0x21 DW_OP_or
+ "DW_OP_or",
+ OP_OR,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x22 DW_OP_plus
+ "DW_OP_plus",
+ OP_PLUS,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x23 DW_OP_plus_uconst
+ "DW_OP_plus_uconst",
+ OP_PLUS_UCONST,
+ 1,
+ 1,
+ {DW_EH_PE_uleb128},
+ },
+ {
+ // 0x24 DW_OP_shl
+ "DW_OP_shl",
+ OP_SHL,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x25 DW_OP_shr
+ "DW_OP_shr",
+ OP_SHR,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x26 DW_OP_shra
+ "DW_OP_shra",
+ OP_SHRA,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x27 DW_OP_xor
+ "DW_OP_xor",
+ OP_XOR,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x28 DW_OP_bra
+ "DW_OP_bra",
+ OP_BRA,
+ 1,
+ 1,
+ {DW_EH_PE_sdata2},
+ },
+ {
+ // 0x29 DW_OP_eq
+ "DW_OP_eq",
+ OP_EQ,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x2a DW_OP_ge
+ "DW_OP_ge",
+ OP_GE,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x2b DW_OP_gt
+ "DW_OP_gt",
+ OP_GT,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x2c DW_OP_le
+ "DW_OP_le",
+ OP_LE,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x2d DW_OP_lt
+ "DW_OP_lt",
+ OP_LT,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x2e DW_OP_ne
+ "DW_OP_ne",
+ OP_NE,
+ 2,
+ 0,
+ {},
+ },
+ {
+ // 0x2f DW_OP_skip
+ "DW_OP_skip",
+ OP_SKIP,
+ 0,
+ 1,
+ {DW_EH_PE_sdata2},
+ },
+ {
+ // 0x30 DW_OP_lit0
+ "DW_OP_lit0",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x31 DW_OP_lit1
+ "DW_OP_lit1",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x32 DW_OP_lit2
+ "DW_OP_lit2",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x33 DW_OP_lit3
+ "DW_OP_lit3",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x34 DW_OP_lit4
+ "DW_OP_lit4",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x35 DW_OP_lit5
+ "DW_OP_lit5",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x36 DW_OP_lit6
+ "DW_OP_lit6",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x37 DW_OP_lit7
+ "DW_OP_lit7",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x38 DW_OP_lit8
+ "DW_OP_lit8",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x39 DW_OP_lit9
+ "DW_OP_lit9",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x3a DW_OP_lit10
+ "DW_OP_lit10",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x3b DW_OP_lit11
+ "DW_OP_lit11",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x3c DW_OP_lit12
+ "DW_OP_lit12",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x3d DW_OP_lit13
+ "DW_OP_lit13",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x3e DW_OP_lit14
+ "DW_OP_lit14",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x3f DW_OP_lit15
+ "DW_OP_lit15",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x40 DW_OP_lit16
+ "DW_OP_lit16",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x41 DW_OP_lit17
+ "DW_OP_lit17",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x42 DW_OP_lit18
+ "DW_OP_lit18",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x43 DW_OP_lit19
+ "DW_OP_lit19",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x44 DW_OP_lit20
+ "DW_OP_lit20",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x45 DW_OP_lit21
+ "DW_OP_lit21",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x46 DW_OP_lit22
+ "DW_OP_lit22",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x47 DW_OP_lit23
+ "DW_OP_lit23",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x48 DW_OP_lit24
+ "DW_OP_lit24",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x49 DW_OP_lit25
+ "DW_OP_lit25",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x4a DW_OP_lit26
+ "DW_OP_lit26",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x4b DW_OP_lit27
+ "DW_OP_lit27",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x4c DW_OP_lit28
+ "DW_OP_lit28",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x4d DW_OP_lit29
+ "DW_OP_lit29",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x4e DW_OP_lit30
+ "DW_OP_lit30",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x4f DW_OP_lit31
+ "DW_OP_lit31",
+ OP_LIT,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x50 DW_OP_reg0
+ "DW_OP_reg0",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x51 DW_OP_reg1
+ "DW_OP_reg1",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x52 DW_OP_reg2
+ "DW_OP_reg2",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x53 DW_OP_reg3
+ "DW_OP_reg3",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x54 DW_OP_reg4
+ "DW_OP_reg4",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x55 DW_OP_reg5
+ "DW_OP_reg5",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x56 DW_OP_reg6
+ "DW_OP_reg6",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x57 DW_OP_reg7
+ "DW_OP_reg7",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x58 DW_OP_reg8
+ "DW_OP_reg8",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x59 DW_OP_reg9
+ "DW_OP_reg9",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x5a DW_OP_reg10
+ "DW_OP_reg10",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x5b DW_OP_reg11
+ "DW_OP_reg11",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x5c DW_OP_reg12
+ "DW_OP_reg12",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x5d DW_OP_reg13
+ "DW_OP_reg13",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x5e DW_OP_reg14
+ "DW_OP_reg14",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x5f DW_OP_reg15
+ "DW_OP_reg15",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x60 DW_OP_reg16
+ "DW_OP_reg16",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x61 DW_OP_reg17
+ "DW_OP_reg17",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x62 DW_OP_reg18
+ "DW_OP_reg18",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x63 DW_OP_reg19
+ "DW_OP_reg19",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x64 DW_OP_reg20
+ "DW_OP_reg20",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x65 DW_OP_reg21
+ "DW_OP_reg21",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x66 DW_OP_reg22
+ "DW_OP_reg22",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x67 DW_OP_reg23
+ "DW_OP_reg23",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x68 DW_OP_reg24
+ "DW_OP_reg24",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x69 DW_OP_reg25
+ "DW_OP_reg25",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x6a DW_OP_reg26
+ "DW_OP_reg26",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x6b DW_OP_reg27
+ "DW_OP_reg27",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x6c DW_OP_reg28
+ "DW_OP_reg28",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x6d DW_OP_reg29
+ "DW_OP_reg29",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x6e DW_OP_reg30
+ "DW_OP_reg30",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x6f DW_OP_reg31
+ "DW_OP_reg31",
+ OP_REG,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x70 DW_OP_breg0
+ "DW_OP_breg0",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x71 DW_OP_breg1
+ "DW_OP_breg1",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x72 DW_OP_breg2
+ "DW_OP_breg2",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x73 DW_OP_breg3
+ "DW_OP_breg3",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x74 DW_OP_breg4
+ "DW_OP_breg4",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x75 DW_OP_breg5
+ "DW_OP_breg5",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x76 DW_OP_breg6
+ "DW_OP_breg6",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x77 DW_OP_breg7
+ "DW_OP_breg7",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x78 DW_OP_breg8
+ "DW_OP_breg8",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x79 DW_OP_breg9
+ "DW_OP_breg9",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x7a DW_OP_breg10
+ "DW_OP_breg10",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x7b DW_OP_breg11
+ "DW_OP_breg11",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x7c DW_OP_breg12
+ "DW_OP_breg12",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x7d DW_OP_breg13
+ "DW_OP_breg13",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x7e DW_OP_breg14
+ "DW_OP_breg14",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x7f DW_OP_breg15
+ "DW_OP_breg15",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x80 DW_OP_breg16
+ "DW_OP_breg16",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x81 DW_OP_breg17
+ "DW_OP_breg17",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x82 DW_OP_breg18
+ "DW_OP_breg18",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x83 DW_OP_breg19
+ "DW_OP_breg19",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x84 DW_OP_breg20
+ "DW_OP_breg20",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x85 DW_OP_breg21
+ "DW_OP_breg21",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x86 DW_OP_breg22
+ "DW_OP_breg22",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x87 DW_OP_breg23
+ "DW_OP_breg23",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x88 DW_OP_breg24
+ "DW_OP_breg24",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x89 DW_OP_breg25
+ "DW_OP_breg25",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x8a DW_OP_breg26
+ "DW_OP_breg26",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x8b DW_OP_breg27
+ "DW_OP_breg27",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x8c DW_OP_breg28
+ "DW_OP_breg28",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x8d DW_OP_breg29
+ "DW_OP_breg29",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x8e DW_OP_breg30
+ "DW_OP_breg30",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x8f DW_OP_breg31
+ "DW_OP_breg31",
+ OP_BREG,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x90 DW_OP_regx
+ "DW_OP_regx",
+ OP_REGX,
+ 0,
+ 1,
+ {DW_EH_PE_uleb128},
+ },
+ {
+ // 0x91 DW_OP_fbreg
+ "DW_OP_fbreg",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 1,
+ {DW_EH_PE_sleb128},
+ },
+ {
+ // 0x92 DW_OP_bregx
+ "DW_OP_bregx",
+ OP_BREGX,
+ 0,
+ 2,
+ {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
+ },
+ {
+ // 0x93 DW_OP_piece
+ "DW_OP_piece",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 1,
+ {DW_EH_PE_uleb128},
+ },
+ {
+ // 0x94 DW_OP_deref_size
+ "DW_OP_deref_size",
+ OP_DEREF_SIZE,
+ 1,
+ 1,
+ {DW_EH_PE_udata1},
+ },
+ {
+ // 0x95 DW_OP_xderef_size
+ "DW_OP_xderef_size",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 1,
+ {DW_EH_PE_udata1},
+ },
+ {
+ // 0x96 DW_OP_nop
+ "DW_OP_nop",
+ OP_NOP,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x97 DW_OP_push_object_address
+ "DW_OP_push_object_address",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x98 DW_OP_call2
+ "DW_OP_call2",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 1,
+ {DW_EH_PE_udata2},
+ },
+ {
+ // 0x99 DW_OP_call4
+ "DW_OP_call4",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 1,
+ {DW_EH_PE_udata4},
+ },
+ {
+ // 0x9a DW_OP_call_ref
+ "DW_OP_call_ref",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 0, // Has a different sized operand (4 bytes or 8 bytes).
+ {},
+ },
+ {
+ // 0x9b DW_OP_form_tls_address
+ "DW_OP_form_tls_address",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x9c DW_OP_call_frame_cfa
+ "DW_OP_call_frame_cfa",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 0,
+ {},
+ },
+ {
+ // 0x9d DW_OP_bit_piece
+ "DW_OP_bit_piece",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 2,
+ {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
+ },
+ {
+ // 0x9e DW_OP_implicit_value
+ "DW_OP_implicit_value",
+ OP_NOT_IMPLEMENTED,
+ 0,
+ 1,
+ {DW_EH_PE_uleb128},
+ },
+ {
+ // 0x9f DW_OP_stack_value
+ "DW_OP_stack_value",
+ OP_NOT_IMPLEMENTED,
+ 1,
+ 0,
+ {},
+ },
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xa0 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xa1 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xa2 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xa3 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xa4 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xa5 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xa6 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xa7 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xa8 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xa9 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xaa illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xab illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xac illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xad illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xae illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xaf illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xb0 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xb1 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xb2 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xb3 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xb4 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xb5 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xb6 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xb7 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xb8 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xb9 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xba illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xbb illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xbc illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xbd illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xbe illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xbf illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xc0 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xc1 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xc2 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xc3 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xc4 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xc5 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xc6 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xc7 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xc8 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xc9 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xca illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xcb illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xcc illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xcd illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xce illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xcf illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xd0 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xd1 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xd2 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xd3 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xd4 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xd5 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xd6 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xd7 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xd8 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xd9 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xda illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xdb illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xdc illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xdd illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xde illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xdf illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xe0 DW_OP_lo_user
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xe1 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xe2 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xe3 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xe4 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xe5 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xe6 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xe7 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xe8 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xe9 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xea illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xeb illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xec illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xed illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xee illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xef illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xf0 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xf1 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xf2 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xf3 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xf4 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xf5 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xf6 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xf7 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xf8 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xf9 illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xfa illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xfb illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xfc illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xfd illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xfe illegal op
+ {"", OP_ILLEGAL, 0, 0, {}}, // 0xff DW_OP_hi_user
+};
+
template <typename AddressType>
-constexpr typename DwarfOp<AddressType>::OpCallback DwarfOp<AddressType>::kCallbackTable[256];
+const typename DwarfOp<AddressType>::OpHandleFuncPtr DwarfOp<AddressType>::kOpHandleFuncList[] = {
+ [OP_ILLEGAL] = nullptr,
+ [OP_DEREF] = &DwarfOp<AddressType>::op_deref,
+ [OP_DEREF_SIZE] = &DwarfOp<AddressType>::op_deref_size,
+ [OP_PUSH] = &DwarfOp<AddressType>::op_push,
+ [OP_DUP] = &DwarfOp<AddressType>::op_dup,
+ [OP_DROP] = &DwarfOp<AddressType>::op_drop,
+ [OP_OVER] = &DwarfOp<AddressType>::op_over,
+ [OP_PICK] = &DwarfOp<AddressType>::op_pick,
+ [OP_SWAP] = &DwarfOp<AddressType>::op_swap,
+ [OP_ROT] = &DwarfOp<AddressType>::op_rot,
+ [OP_ABS] = &DwarfOp<AddressType>::op_abs,
+ [OP_AND] = &DwarfOp<AddressType>::op_and,
+ [OP_DIV] = &DwarfOp<AddressType>::op_div,
+ [OP_MINUS] = &DwarfOp<AddressType>::op_minus,
+ [OP_MOD] = &DwarfOp<AddressType>::op_mod,
+ [OP_MUL] = &DwarfOp<AddressType>::op_mul,
+ [OP_NEG] = &DwarfOp<AddressType>::op_neg,
+ [OP_NOT] = &DwarfOp<AddressType>::op_not,
+ [OP_OR] = &DwarfOp<AddressType>::op_or,
+ [OP_PLUS] = &DwarfOp<AddressType>::op_plus,
+ [OP_PLUS_UCONST] = &DwarfOp<AddressType>::op_plus_uconst,
+ [OP_SHL] = &DwarfOp<AddressType>::op_shl,
+ [OP_SHR] = &DwarfOp<AddressType>::op_shr,
+ [OP_SHRA] = &DwarfOp<AddressType>::op_shra,
+ [OP_XOR] = &DwarfOp<AddressType>::op_xor,
+ [OP_BRA] = &DwarfOp<AddressType>::op_bra,
+ [OP_EQ] = &DwarfOp<AddressType>::op_eq,
+ [OP_GE] = &DwarfOp<AddressType>::op_ge,
+ [OP_GT] = &DwarfOp<AddressType>::op_gt,
+ [OP_LE] = &DwarfOp<AddressType>::op_le,
+ [OP_LT] = &DwarfOp<AddressType>::op_lt,
+ [OP_NE] = &DwarfOp<AddressType>::op_ne,
+ [OP_SKIP] = &DwarfOp<AddressType>::op_skip,
+ [OP_LIT] = &DwarfOp<AddressType>::op_lit,
+ [OP_REG] = &DwarfOp<AddressType>::op_reg,
+ [OP_REGX] = &DwarfOp<AddressType>::op_regx,
+ [OP_BREG] = &DwarfOp<AddressType>::op_breg,
+ [OP_BREGX] = &DwarfOp<AddressType>::op_bregx,
+ [OP_NOP] = &DwarfOp<AddressType>::op_nop,
+ [OP_NOT_IMPLEMENTED] = &DwarfOp<AddressType>::op_not_implemented,
+};
template <typename AddressType>
bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end) {
@@ -97,12 +1540,13 @@
}
const auto* op = &kCallbackTable[cur_op_];
- const auto handle_func = op->handle_func;
- if (handle_func == nullptr) {
+ if (op->handle_func == OP_ILLEGAL) {
last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
+ const auto handle_func = kOpHandleFuncList[op->handle_func];
+
// Make sure that the required number of stack elements is available.
if (stack_.size() < op->num_required_stack_values) {
last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID;
@@ -135,7 +1579,7 @@
std::string raw_string(android::base::StringPrintf("Raw Data: 0x%02x", cur_op));
std::string log_string;
const auto* op = &kCallbackTable[cur_op];
- if (op->handle_func == nullptr) {
+ if (op->handle_func == OP_ILLEGAL) {
log_string = "Illegal";
} else {
log_string = op->name;
diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h
index 4c69b3d..ac9fd2d 100644
--- a/libunwindstack/DwarfOp.h
+++ b/libunwindstack/DwarfOp.h
@@ -42,14 +42,6 @@
// Signed version of AddressType
typedef typename std::make_signed<AddressType>::type SignedType;
- struct OpCallback {
- const char* name;
- bool (DwarfOp::*handle_func)();
- uint8_t num_required_stack_values;
- uint8_t num_operands;
- uint8_t operands[2];
- };
-
public:
DwarfOp(DwarfMemory* memory, Memory* regular_memory)
: memory_(memory), regular_memory_(regular_memory) {}
@@ -143,1342 +135,8 @@
bool op_nop();
bool op_not_implemented();
- constexpr static OpCallback kCallbackTable[256] = {
- {nullptr, nullptr, 0, 0, {}}, // 0x00 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0x01 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0x02 illegal op
- {
- // 0x03 DW_OP_addr
- "DW_OP_addr",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_absptr},
- },
- {nullptr, nullptr, 0, 0, {}}, // 0x04 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0x05 illegal op
- {
- // 0x06 DW_OP_deref
- "DW_OP_deref",
- &DwarfOp::op_deref,
- 1,
- 0,
- {},
- },
- {nullptr, nullptr, 0, 0, {}}, // 0x07 illegal op
- {
- // 0x08 DW_OP_const1u
- "DW_OP_const1u",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_udata1},
- },
- {
- // 0x09 DW_OP_const1s
- "DW_OP_const1s",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_sdata1},
- },
- {
- // 0x0a DW_OP_const2u
- "DW_OP_const2u",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_udata2},
- },
- {
- // 0x0b DW_OP_const2s
- "DW_OP_const2s",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_sdata2},
- },
- {
- // 0x0c DW_OP_const4u
- "DW_OP_const4u",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_udata4},
- },
- {
- // 0x0d DW_OP_const4s
- "DW_OP_const4s",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_sdata4},
- },
- {
- // 0x0e DW_OP_const8u
- "DW_OP_const8u",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_udata8},
- },
- {
- // 0x0f DW_OP_const8s
- "DW_OP_const8s",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_sdata8},
- },
- {
- // 0x10 DW_OP_constu
- "DW_OP_constu",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_uleb128},
- },
- {
- // 0x11 DW_OP_consts
- "DW_OP_consts",
- &DwarfOp::op_push,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x12 DW_OP_dup
- "DW_OP_dup",
- &DwarfOp::op_dup,
- 1,
- 0,
- {},
- },
- {
- // 0x13 DW_OP_drop
- "DW_OP_drop",
- &DwarfOp::op_drop,
- 1,
- 0,
- {},
- },
- {
- // 0x14 DW_OP_over
- "DW_OP_over",
- &DwarfOp::op_over,
- 2,
- 0,
- {},
- },
- {
- // 0x15 DW_OP_pick
- "DW_OP_pick",
- &DwarfOp::op_pick,
- 0,
- 1,
- {DW_EH_PE_udata1},
- },
- {
- // 0x16 DW_OP_swap
- "DW_OP_swap",
- &DwarfOp::op_swap,
- 2,
- 0,
- {},
- },
- {
- // 0x17 DW_OP_rot
- "DW_OP_rot",
- &DwarfOp::op_rot,
- 3,
- 0,
- {},
- },
- {
- // 0x18 DW_OP_xderef
- "DW_OP_xderef",
- &DwarfOp::op_not_implemented,
- 2,
- 0,
- {},
- },
- {
- // 0x19 DW_OP_abs
- "DW_OP_abs",
- &DwarfOp::op_abs,
- 1,
- 0,
- {},
- },
- {
- // 0x1a DW_OP_and
- "DW_OP_and",
- &DwarfOp::op_and,
- 2,
- 0,
- {},
- },
- {
- // 0x1b DW_OP_div
- "DW_OP_div",
- &DwarfOp::op_div,
- 2,
- 0,
- {},
- },
- {
- // 0x1c DW_OP_minus
- "DW_OP_minus",
- &DwarfOp::op_minus,
- 2,
- 0,
- {},
- },
- {
- // 0x1d DW_OP_mod
- "DW_OP_mod",
- &DwarfOp::op_mod,
- 2,
- 0,
- {},
- },
- {
- // 0x1e DW_OP_mul
- "DW_OP_mul",
- &DwarfOp::op_mul,
- 2,
- 0,
- {},
- },
- {
- // 0x1f DW_OP_neg
- "DW_OP_neg",
- &DwarfOp::op_neg,
- 1,
- 0,
- {},
- },
- {
- // 0x20 DW_OP_not
- "DW_OP_not",
- &DwarfOp::op_not,
- 1,
- 0,
- {},
- },
- {
- // 0x21 DW_OP_or
- "DW_OP_or",
- &DwarfOp::op_or,
- 2,
- 0,
- {},
- },
- {
- // 0x22 DW_OP_plus
- "DW_OP_plus",
- &DwarfOp::op_plus,
- 2,
- 0,
- {},
- },
- {
- // 0x23 DW_OP_plus_uconst
- "DW_OP_plus_uconst",
- &DwarfOp::op_plus_uconst,
- 1,
- 1,
- {DW_EH_PE_uleb128},
- },
- {
- // 0x24 DW_OP_shl
- "DW_OP_shl",
- &DwarfOp::op_shl,
- 2,
- 0,
- {},
- },
- {
- // 0x25 DW_OP_shr
- "DW_OP_shr",
- &DwarfOp::op_shr,
- 2,
- 0,
- {},
- },
- {
- // 0x26 DW_OP_shra
- "DW_OP_shra",
- &DwarfOp::op_shra,
- 2,
- 0,
- {},
- },
- {
- // 0x27 DW_OP_xor
- "DW_OP_xor",
- &DwarfOp::op_xor,
- 2,
- 0,
- {},
- },
- {
- // 0x28 DW_OP_bra
- "DW_OP_bra",
- &DwarfOp::op_bra,
- 1,
- 1,
- {DW_EH_PE_sdata2},
- },
- {
- // 0x29 DW_OP_eq
- "DW_OP_eq",
- &DwarfOp::op_eq,
- 2,
- 0,
- {},
- },
- {
- // 0x2a DW_OP_ge
- "DW_OP_ge",
- &DwarfOp::op_ge,
- 2,
- 0,
- {},
- },
- {
- // 0x2b DW_OP_gt
- "DW_OP_gt",
- &DwarfOp::op_gt,
- 2,
- 0,
- {},
- },
- {
- // 0x2c DW_OP_le
- "DW_OP_le",
- &DwarfOp::op_le,
- 2,
- 0,
- {},
- },
- {
- // 0x2d DW_OP_lt
- "DW_OP_lt",
- &DwarfOp::op_lt,
- 2,
- 0,
- {},
- },
- {
- // 0x2e DW_OP_ne
- "DW_OP_ne",
- &DwarfOp::op_ne,
- 2,
- 0,
- {},
- },
- {
- // 0x2f DW_OP_skip
- "DW_OP_skip",
- &DwarfOp::op_skip,
- 0,
- 1,
- {DW_EH_PE_sdata2},
- },
- {
- // 0x30 DW_OP_lit0
- "DW_OP_lit0",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x31 DW_OP_lit1
- "DW_OP_lit1",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x32 DW_OP_lit2
- "DW_OP_lit2",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x33 DW_OP_lit3
- "DW_OP_lit3",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x34 DW_OP_lit4
- "DW_OP_lit4",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x35 DW_OP_lit5
- "DW_OP_lit5",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x36 DW_OP_lit6
- "DW_OP_lit6",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x37 DW_OP_lit7
- "DW_OP_lit7",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x38 DW_OP_lit8
- "DW_OP_lit8",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x39 DW_OP_lit9
- "DW_OP_lit9",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x3a DW_OP_lit10
- "DW_OP_lit10",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x3b DW_OP_lit11
- "DW_OP_lit11",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x3c DW_OP_lit12
- "DW_OP_lit12",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x3d DW_OP_lit13
- "DW_OP_lit13",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x3e DW_OP_lit14
- "DW_OP_lit14",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x3f DW_OP_lit15
- "DW_OP_lit15",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x40 DW_OP_lit16
- "DW_OP_lit16",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x41 DW_OP_lit17
- "DW_OP_lit17",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x42 DW_OP_lit18
- "DW_OP_lit18",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x43 DW_OP_lit19
- "DW_OP_lit19",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x44 DW_OP_lit20
- "DW_OP_lit20",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x45 DW_OP_lit21
- "DW_OP_lit21",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x46 DW_OP_lit22
- "DW_OP_lit22",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x47 DW_OP_lit23
- "DW_OP_lit23",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x48 DW_OP_lit24
- "DW_OP_lit24",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x49 DW_OP_lit25
- "DW_OP_lit25",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x4a DW_OP_lit26
- "DW_OP_lit26",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x4b DW_OP_lit27
- "DW_OP_lit27",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x4c DW_OP_lit28
- "DW_OP_lit28",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x4d DW_OP_lit29
- "DW_OP_lit29",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x4e DW_OP_lit30
- "DW_OP_lit30",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x4f DW_OP_lit31
- "DW_OP_lit31",
- &DwarfOp::op_lit,
- 0,
- 0,
- {},
- },
- {
- // 0x50 DW_OP_reg0
- "DW_OP_reg0",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x51 DW_OP_reg1
- "DW_OP_reg1",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x52 DW_OP_reg2
- "DW_OP_reg2",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x53 DW_OP_reg3
- "DW_OP_reg3",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x54 DW_OP_reg4
- "DW_OP_reg4",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x55 DW_OP_reg5
- "DW_OP_reg5",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x56 DW_OP_reg6
- "DW_OP_reg6",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x57 DW_OP_reg7
- "DW_OP_reg7",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x58 DW_OP_reg8
- "DW_OP_reg8",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x59 DW_OP_reg9
- "DW_OP_reg9",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x5a DW_OP_reg10
- "DW_OP_reg10",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x5b DW_OP_reg11
- "DW_OP_reg11",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x5c DW_OP_reg12
- "DW_OP_reg12",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x5d DW_OP_reg13
- "DW_OP_reg13",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x5e DW_OP_reg14
- "DW_OP_reg14",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x5f DW_OP_reg15
- "DW_OP_reg15",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x60 DW_OP_reg16
- "DW_OP_reg16",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x61 DW_OP_reg17
- "DW_OP_reg17",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x62 DW_OP_reg18
- "DW_OP_reg18",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x63 DW_OP_reg19
- "DW_OP_reg19",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x64 DW_OP_reg20
- "DW_OP_reg20",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x65 DW_OP_reg21
- "DW_OP_reg21",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x66 DW_OP_reg22
- "DW_OP_reg22",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x67 DW_OP_reg23
- "DW_OP_reg23",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x68 DW_OP_reg24
- "DW_OP_reg24",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x69 DW_OP_reg25
- "DW_OP_reg25",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x6a DW_OP_reg26
- "DW_OP_reg26",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x6b DW_OP_reg27
- "DW_OP_reg27",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x6c DW_OP_reg28
- "DW_OP_reg28",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x6d DW_OP_reg29
- "DW_OP_reg29",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x6e DW_OP_reg30
- "DW_OP_reg30",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x6f DW_OP_reg31
- "DW_OP_reg31",
- &DwarfOp::op_reg,
- 0,
- 0,
- {},
- },
- {
- // 0x70 DW_OP_breg0
- "DW_OP_breg0",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x71 DW_OP_breg1
- "DW_OP_breg1",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x72 DW_OP_breg2
- "DW_OP_breg2",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x73 DW_OP_breg3
- "DW_OP_breg3",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x74 DW_OP_breg4
- "DW_OP_breg4",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x75 DW_OP_breg5
- "DW_OP_breg5",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x76 DW_OP_breg6
- "DW_OP_breg6",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x77 DW_OP_breg7
- "DW_OP_breg7",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x78 DW_OP_breg8
- "DW_OP_breg8",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x79 DW_OP_breg9
- "DW_OP_breg9",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7a DW_OP_breg10
- "DW_OP_breg10",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7b DW_OP_breg11
- "DW_OP_breg11",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7c DW_OP_breg12
- "DW_OP_breg12",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7d DW_OP_breg13
- "DW_OP_breg13",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7e DW_OP_breg14
- "DW_OP_breg14",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7f DW_OP_breg15
- "DW_OP_breg15",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x80 DW_OP_breg16
- "DW_OP_breg16",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x81 DW_OP_breg17
- "DW_OP_breg17",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x82 DW_OP_breg18
- "DW_OP_breg18",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x83 DW_OP_breg19
- "DW_OP_breg19",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x84 DW_OP_breg20
- "DW_OP_breg20",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x85 DW_OP_breg21
- "DW_OP_breg21",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x86 DW_OP_breg22
- "DW_OP_breg22",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x87 DW_OP_breg23
- "DW_OP_breg23",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x88 DW_OP_breg24
- "DW_OP_breg24",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x89 DW_OP_breg25
- "DW_OP_breg25",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8a DW_OP_breg26
- "DW_OP_breg26",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8b DW_OP_breg27
- "DW_OP_breg27",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8c DW_OP_breg28
- "DW_OP_breg28",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8d DW_OP_breg29
- "DW_OP_breg29",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8e DW_OP_breg30
- "DW_OP_breg30",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8f DW_OP_breg31
- "DW_OP_breg31",
- &DwarfOp::op_breg,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x90 DW_OP_regx
- "DW_OP_regx",
- &DwarfOp::op_regx,
- 0,
- 1,
- {DW_EH_PE_uleb128},
- },
- {
- // 0x91 DW_OP_fbreg
- "DW_OP_fbreg",
- &DwarfOp::op_not_implemented,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x92 DW_OP_bregx
- "DW_OP_bregx",
- &DwarfOp::op_bregx,
- 0,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
- },
- {
- // 0x93 DW_OP_piece
- "DW_OP_piece",
- &DwarfOp::op_not_implemented,
- 0,
- 1,
- {DW_EH_PE_uleb128},
- },
- {
- // 0x94 DW_OP_deref_size
- "DW_OP_deref_size",
- &DwarfOp::op_deref_size,
- 1,
- 1,
- {DW_EH_PE_udata1},
- },
- {
- // 0x95 DW_OP_xderef_size
- "DW_OP_xderef_size",
- &DwarfOp::op_not_implemented,
- 0,
- 1,
- {DW_EH_PE_udata1},
- },
- {
- // 0x96 DW_OP_nop
- "DW_OP_nop",
- &DwarfOp::op_nop,
- 0,
- 0,
- {},
- },
- {
- // 0x97 DW_OP_push_object_address
- "DW_OP_push_object_address",
- &DwarfOp::op_not_implemented,
- 0,
- 0,
- {},
- },
- {
- // 0x98 DW_OP_call2
- "DW_OP_call2",
- &DwarfOp::op_not_implemented,
- 0,
- 1,
- {DW_EH_PE_udata2},
- },
- {
- // 0x99 DW_OP_call4
- "DW_OP_call4",
- &DwarfOp::op_not_implemented,
- 0,
- 1,
- {DW_EH_PE_udata4},
- },
- {
- // 0x9a DW_OP_call_ref
- "DW_OP_call_ref",
- &DwarfOp::op_not_implemented,
- 0,
- 0, // Has a different sized operand (4 bytes or 8 bytes).
- {},
- },
- {
- // 0x9b DW_OP_form_tls_address
- "DW_OP_form_tls_address",
- &DwarfOp::op_not_implemented,
- 0,
- 0,
- {},
- },
- {
- // 0x9c DW_OP_call_frame_cfa
- "DW_OP_call_frame_cfa",
- &DwarfOp::op_not_implemented,
- 0,
- 0,
- {},
- },
- {
- // 0x9d DW_OP_bit_piece
- "DW_OP_bit_piece",
- &DwarfOp::op_not_implemented,
- 0,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
- },
- {
- // 0x9e DW_OP_implicit_value
- "DW_OP_implicit_value",
- &DwarfOp::op_not_implemented,
- 0,
- 1,
- {DW_EH_PE_uleb128},
- },
- {
- // 0x9f DW_OP_stack_value
- "DW_OP_stack_value",
- &DwarfOp::op_not_implemented,
- 1,
- 0,
- {},
- },
- {nullptr, nullptr, 0, 0, {}}, // 0xa0 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xa1 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xa2 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xa3 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xa4 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xa5 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xa6 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xa7 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xa8 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xa9 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xaa illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xab illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xac illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xad illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xae illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xaf illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xb0 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xb1 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xb2 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xb3 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xb4 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xb5 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xb6 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xb7 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xb8 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xb9 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xba illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xbb illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xbc illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xbd illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xbe illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xbf illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xc0 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xc1 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xc2 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xc3 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xc4 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xc5 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xc6 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xc7 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xc8 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xc9 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xca illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xcb illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xcc illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xcd illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xce illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xcf illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xd0 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xd1 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xd2 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xd3 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xd4 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xd5 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xd6 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xd7 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xd8 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xd9 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xda illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xdb illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xdc illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xdd illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xde illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xdf illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xe0 DW_OP_lo_user
- {nullptr, nullptr, 0, 0, {}}, // 0xe1 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xe2 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xe3 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xe4 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xe5 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xe6 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xe7 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xe8 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xe9 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xea illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xeb illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xec illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xed illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xee illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xef illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xf0 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xf1 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xf2 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xf3 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xf4 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xf5 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xf6 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xf7 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xf8 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xf9 illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xfa illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xfb illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xfc illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xfd illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xfe illegal op
- {nullptr, nullptr, 0, 0, {}}, // 0xff DW_OP_hi_user
- };
+ using OpHandleFuncPtr = bool (DwarfOp::*)();
+ static const OpHandleFuncPtr kOpHandleFuncList[];
};
} // namespace unwindstack
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 0dd95cf..2734cf8 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -247,7 +247,7 @@
// or the pc in the first frame is in a valid map.
// This allows for a case where the code jumps into the middle of
// nowhere, but there is no other unwind information after that.
- if (frames_.size() != 2 || maps_->Find(frames_[0].pc) != nullptr) {
+ if (frames_.size() > 2 || (frames_.size() > 0 && maps_->Find(frames_[0].pc) != nullptr)) {
// Remove the speculative frame.
frames_.pop_back();
}
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
index 0336173..67a9640 100644
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -40,7 +40,7 @@
public:
explicit DexFiles(std::shared_ptr<Memory>& memory);
DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
- ~DexFiles();
+ virtual ~DexFiles();
DexFile* GetDexFile(uint64_t dex_file_offset, MapInfo* info);
diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
index f64b04f..8b7b4b5 100644
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ b/libunwindstack/include/unwindstack/JitDebug.h
@@ -38,7 +38,7 @@
public:
explicit JitDebug(std::shared_ptr<Memory>& memory);
JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
- ~JitDebug();
+ virtual ~JitDebug();
Elf* GetElf(Maps* maps, uint64_t pc);
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index ab239c1..f4788d7 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -72,7 +72,7 @@
frames_.reserve(max_frames);
}
- ~Unwinder() = default;
+ virtual ~Unwinder() = default;
void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
@@ -124,7 +124,7 @@
class UnwinderFromPid : public Unwinder {
public:
UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {}
- ~UnwinderFromPid() = default;
+ virtual ~UnwinderFromPid() = default;
bool Init(ArchEnum arch);
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index a91bd95..c747eab 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -47,6 +47,7 @@
enum TestTypeEnum : uint8_t {
TEST_TYPE_LOCAL_UNWINDER = 0,
TEST_TYPE_LOCAL_UNWINDER_FROM_PID,
+ TEST_TYPE_LOCAL_WAIT_FOR_FINISH,
TEST_TYPE_REMOTE,
TEST_TYPE_REMOTE_WITH_INVALID_CALL,
};
@@ -79,7 +80,10 @@
extern "C" void SignalInnerFunction() {
g_signal_ready_for_remote = true;
- while (!g_finish.load()) {
+ // Avoid any function calls because not every instruction will be
+ // unwindable.
+ // This method of looping is only used when testing a remote unwind.
+ while (true) {
}
}
@@ -134,6 +138,11 @@
// off. If this doesn't happen, then all of the calls will be optimized
// away.
extern "C" void InnerFunction(TestTypeEnum test_type) {
+ if (test_type == TEST_TYPE_LOCAL_WAIT_FOR_FINISH) {
+ while (!g_finish.load()) {
+ }
+ return;
+ }
if (test_type == TEST_TYPE_REMOTE || test_type == TEST_TYPE_REMOTE_WITH_INVALID_CALL) {
g_ready_for_remote = true;
g_ready = true;
@@ -141,7 +150,10 @@
void (*crash_func)() = nullptr;
crash_func();
}
- while (!g_finish.load()) {
+ // Avoid any function calls because not every instruction will be
+ // unwindable.
+ // This method of looping is only used when testing a remote unwind.
+ while (true) {
}
return;
}
@@ -271,7 +283,7 @@
std::atomic_int tid(0);
std::thread thread([&]() {
tid = syscall(__NR_gettid);
- OuterFunction(TEST_TYPE_REMOTE);
+ OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
});
struct sigaction act, oldact;
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 49aeeb3..d88531f 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -749,6 +749,23 @@
EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
+// Verify that a speculative frame does not cause a crash when it wasn't
+// really added due to a filter.
+TEST_F(UnwinderTest, speculative_frame_check_with_no_frames) {
+ regs_.set_pc(0x23000);
+ regs_.set_sp(0x10000);
+ regs_.FakeSetReturnAddress(0x23100);
+ regs_.FakeSetReturnAddressValid(true);
+
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
+
+ std::vector<std::string> skip_names{"libanother.so"};
+ unwinder.Unwind(&skip_names);
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+ ASSERT_EQ(0U, unwinder.NumFrames());
+}
+
// Verify that an unwind stops when a frame is in given suffix.
TEST_F(UnwinderTest, map_ignore_suffixes) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 3e8417e..fb7ca32 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -22,11 +22,13 @@
"liblog_headers",
"libsystem_headers",
"libcutils_headers",
+ "libprocessgroup_headers",
],
export_header_lib_headers: [
"liblog_headers",
"libsystem_headers",
"libcutils_headers",
+ "libprocessgroup_headers",
],
export_include_dirs: ["include"],
@@ -82,6 +84,7 @@
shared_libs: [
"libcutils",
+ "libprocessgroup",
"libdl",
"libvndksupport",
],
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 64bc402..31ca138 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -36,7 +36,7 @@
#include <utils/Log.h>
-#include <cutils/sched_policy.h>
+#include <processgroup/sched_policy.h>
#if defined(__ANDROID__)
# define __android_unused
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 5f0a51f..24a745a 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -275,25 +275,6 @@
return ss-s;
}
-
-char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n)
-{
- char16_t *q = dst;
- const char16_t *p = src;
- char ch;
-
- while (n) {
- n--;
- *q++ = ch = *p++;
- if ( !ch )
- break;
- }
-
- *q = 0;
-
- return dst;
-}
-
size_t strnlen16(const char16_t *s, size_t maxlen)
{
const char16_t *ss = s;
diff --git a/libutils/include/utils/Unicode.h b/libutils/include/utils/Unicode.h
index 61a1b4f..a2aaa47 100644
--- a/libutils/include/utils/Unicode.h
+++ b/libutils/include/utils/Unicode.h
@@ -28,7 +28,6 @@
size_t strlen16(const char16_t *);
size_t strnlen16(const char16_t *, size_t);
char16_t *strcpy16(char16_t *, const char16_t *);
-char16_t *strncpy16(char16_t *, const char16_t *, size_t);
char16_t *strstr16(const char16_t*, const char16_t*);
// Version of comparison that supports embedded NULs.
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index 903d0e2..f9ed57c 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -5,6 +5,7 @@
shared_libs: [
"libcutils",
"liblog",
+ "libprocessgroup",
],
static_libs: [
"libstatslogc",
diff --git a/logcat/Android.bp b/logcat/Android.bp
index 0543aba..5030b15 100644
--- a/logcat/Android.bp
+++ b/logcat/Android.bp
@@ -24,8 +24,8 @@
],
shared_libs: [
"libbase",
- "libcutils",
"libpcrecpp",
+ "libprocessgroup",
],
static_libs: ["liblog"],
logtags: ["event.logtags"],
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 87bc6ae..15e07fe 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -49,11 +49,11 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
#include <log/event_tag_map.h>
#include <log/logprint.h>
#include <private/android_logger.h>
+#include <processgroup/sched_policy.h>
#include <system/thread_defs.h>
#include <pcrecpp.h>
diff --git a/logd/Android.bp b/logd/Android.bp
index 3abfc21..360f2fe 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -73,8 +73,16 @@
"libcutils",
"libbase",
"libpackagelistparser",
+ "libprocessgroup",
"libcap",
],
cflags: ["-Werror"],
}
+
+
+prebuilt_etc {
+ name: "logtagd.rc",
+ src: "logtagd.rc",
+ sub_dir: "init",
+}
diff --git a/logd/Android.mk b/logd/Android.mk
deleted file mode 100644
index aafa28d..0000000
--- a/logd/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := logtagd.rc
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init
-
-include $(BUILD_PREBUILT)
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 470ffed..a21555c 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -111,7 +111,7 @@
}
std::map<std::string, std::string> LogAudit::populateDenialMap() {
- std::ifstream bug_file("/system/etc/selinux/selinux_denial_metadata");
+ std::ifstream bug_file("/vendor/etc/selinux/selinux_denial_metadata");
std::string line;
// allocate a map for the static map pointer in auditParse to keep track of,
// this function only runs once
diff --git a/logd/main.cpp b/logd/main.cpp
index 8c38d9a..fd3cdf8 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -38,12 +38,12 @@
#include <android-base/macros.h>
#include <cutils/android_get_control_file.h>
#include <cutils/properties.h>
-#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
#include <log/event_tag_map.h>
#include <packagelistparser/packagelistparser.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
+#include <processgroup/sched_policy.h>
#include <utils/threads.h>
#include "CommandListener.h"
diff --git a/mkbootimg/include/bootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h
index 4432f9e..9ee7869 100644
--- a/mkbootimg/include/bootimg/bootimg.h
+++ b/mkbootimg/include/bootimg/bootimg.h
@@ -115,7 +115,7 @@
uint32_t header_size;
} __attribute__((packed));
-/* When the boot image header has a version of 1, the structure of the boot
+/* When the boot image header has a version of 2, the structure of the boot
* image is as follows:
*
* +---------------------+
@@ -129,17 +129,21 @@
* +---------------------+
* | recovery dtbo/acpio | p pages
* +---------------------+
+ * | dtb | q 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
* p = (recovery_dtbo_size + page_size - 1) / page_size
+ * q = (dtb_size + page_size - 1) / page_size
*
* 0. all entities are page_size aligned in flash
- * 1. kernel and ramdisk are required (size != 0)
+ * 1. kernel, ramdisk and DTB are required (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
+ * 4. load each element (kernel, ramdisk, second, dtb) at
* the specified physical address (kernel_addr, etc)
* 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
@@ -150,3 +154,7 @@
* 8. if second_size != 0: jump to second_addr
* else: jump to kernel_addr
*/
+struct boot_img_hdr_v2 : public boot_img_hdr_v1 {
+ uint32_t dtb_size; /* size in bytes for DTB image */
+ uint64_t dtb_addr; /* physical load address for DTB image */
+} __attribute__((packed));
diff --git a/mkbootimg/mkbootimg.py b/mkbootimg/mkbootimg.py
index 2eb2bab..92b11a5 100644
--- a/mkbootimg/mkbootimg.py
+++ b/mkbootimg/mkbootimg.py
@@ -62,7 +62,13 @@
def write_header(args):
+ BOOT_IMAGE_HEADER_V1_SIZE = 1648
+ BOOT_IMAGE_HEADER_V2_SIZE = 1660
BOOT_MAGIC = 'ANDROID!'.encode()
+
+ if (args.header_version > 2):
+ raise ValueError('Boot header version %d not supported' % args.header_version)
+
args.output.write(pack('8s', BOOT_MAGIC))
args.output.write(pack('10I',
filesize(args.kernel), # size in bytes
@@ -85,6 +91,8 @@
if args.header_version > 0:
update_sha(sha, args.recovery_dtbo)
+ if args.header_version > 1:
+ update_sha(sha, args.dtb)
img_id = pack('32s', sha.digest())
@@ -97,8 +105,16 @@
args.output.write(pack('Q', get_recovery_dtbo_offset(args))) # recovery dtbo offset
else:
args.output.write(pack('Q', 0)) # Will be set to 0 for devices without a recovery dtbo
- args.output.write(pack('I', args.output.tell() + 4)) # size of boot header
+ # Populate boot image header size for header versions 1 and 2.
+ if args.header_version == 1:
+ args.output.write(pack('I', BOOT_IMAGE_HEADER_V1_SIZE))
+ elif args.header_version == 2:
+ args.output.write(pack('I', BOOT_IMAGE_HEADER_V2_SIZE))
+
+ if args.header_version > 1:
+ args.output.write(pack('I', filesize(args.dtb))) # size in bytes
+ args.output.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
pad_file(args.output, args.pagesize)
return img_id
@@ -161,6 +177,7 @@
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('--dtb', help='path to dtb', 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',
@@ -172,6 +189,8 @@
parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int, default=0x01000000)
parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
default=0x00f00000)
+ parser.add_argument('--dtb_offset', help='dtb offset', type=parse_int, default=0x01f00000)
+
parser.add_argument('--os_version', help='operating system version', type=parse_os_version,
default=0)
parser.add_argument('--os_patch_level', help='operating system patch level',
@@ -196,6 +215,8 @@
if args.header_version > 0:
write_padded_file(args.output, args.recovery_dtbo, args.pagesize)
+ if args.header_version > 1:
+ write_padded_file(args.output, args.dtb, args.pagesize)
def main():
args = parse_cmdline()
diff --git a/mkbootimg/unpack_bootimg.py b/mkbootimg/unpack_bootimg.py
old mode 100644
new mode 100755
index c37acd5..6b5d5d0
--- a/mkbootimg/unpack_bootimg.py
+++ b/mkbootimg/unpack_bootimg.py
@@ -15,7 +15,7 @@
"""unpacks the bootimage.
-Extracts the kernel, ramdisk, second bootloader and recovery dtbo images.
+Extracts the kernel, ramdisk, second bootloader, dtb and recovery dtbo images.
"""
from __future__ import print_function
@@ -82,6 +82,14 @@
print('boot header size: %s' % boot_header_size)
else:
recovery_dtbo_size = 0
+ if version > 1:
+ dtb_size = unpack('I', args.boot_img.read(4))[0]
+ print('dtb size: %s' % dtb_size)
+ dtb_load_address = unpack('Q', args.boot_img.read(8))[0]
+ print('dtb address: %s' % dtb_load_address)
+ else:
+ dtb_size = 0
+
# The first page contains the boot header
num_header_pages = 1
@@ -103,6 +111,15 @@
if recovery_dtbo_size > 0:
image_info_list.append((recovery_dtbo_offset, recovery_dtbo_size,
'recovery_dtbo'))
+ if dtb_size > 0:
+ num_second_pages = get_number_of_pages(second_size, page_size)
+ num_recovery_dtbo_pages = get_number_of_pages(recovery_dtbo_size, page_size)
+ dtb_offset = page_size * (
+ num_header_pages + num_kernel_pages + num_ramdisk_pages + num_second_pages +
+ num_recovery_dtbo_pages
+ )
+
+ image_info_list.append((dtb_offset, dtb_size, 'dtb'))
for image_info in image_info_list:
extract_image(image_info[0], image_info[1], args.boot_img,
@@ -113,7 +130,7 @@
"""parse command line arguments"""
parser = ArgumentParser(
description='Unpacks boot.img/recovery.img, extracts the kernel,'
- 'ramdisk, second bootloader and recovery dtbo')
+ 'ramdisk, second bootloader, recovery dtbo and dtb')
parser.add_argument(
'--boot_img',
help='path to boot image',
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 85c7e9e..5a6f41b 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -24,6 +24,26 @@
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init
+# Start of runtime APEX compatibility.
+#
+# Meta-comment:
+# The placing of this section is somewhat arbitrary. The LOCAL_POST_INSTALL_CMD
+# entries need to be associated with something that goes into /system.
+# init-debug.rc qualifies but it could be anything else in /system until soong
+# supports creation of symlinks. http://b/123333111
+#
+# Keeping the appearance of files/dirs having old locations for apps that have
+# come to rely on them.
+
+# http://b/121248172 - create a link from /system/usr/icu to
+# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file.
+# A symlink can't overwrite a directory and the /system/usr/icu directory once
+# existed so the required structure must be created whatever we find.
+LOCAL_POST_INSTALL_CMD = mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
+LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu
+
+# End of runtime APEX compatibilty.
+
include $(BUILD_PREBUILT)
#######################################
@@ -253,14 +273,11 @@
include $(LOCAL_PATH)/update_and_install_ld_config.mk
endef
-# For VNDK snapshot versions prior to 28, ld.config.txt is installed from the
-# prebuilt under /prebuilts/vndk
vndk_snapshots := $(wildcard prebuilts/vndk/*)
supported_vndk_snapshot_versions := \
- $(strip $(foreach ver,$(patsubst prebuilts/vndk/v%,%,$(vndk_snapshots)),\
- $(if $(call math_gt_or_eq,$(ver),28),$(ver),)))
-$(eval $(foreach ver,$(supported_vndk_snapshot_versions),\
- $(call build_versioned_ld_config,$(ver))))
+ $(strip $(patsubst prebuilts/vndk/v%,%,$(vndk_snapshots)))
+$(foreach ver,$(supported_vndk_snapshot_versions),\
+ $(eval $(call build_versioned_ld_config,$(ver))))
vndk_snapshots :=
supported_vndk_snapshot_versions :=
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index 461184a..6d9d810 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -32,6 +32,73 @@
namespace.default.asan.search.paths += /odm/${LIB}
###############################################################################
+# APEX related namespaces.
+###############################################################################
+
+additional.namespaces = runtime,conscrypt,media
+namespace.default.asan.permitted.paths += /apex/com.android.resolv/${LIB}
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.default.links = runtime
+namespace.default.asan.links = runtime
+# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
+# libart.
+namespace.default.visible = true
+namespace.default.link.runtime.shared_libs = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs += libnativebridge.so
+namespace.default.link.runtime.shared_libs += libnativehelper.so
+namespace.default.link.runtime.shared_libs += libnativeloader.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
+###############################################################################
+# "media" APEX namespace
+#
+# This namespace is for libraries within the media APEX.
+###############################################################################
+namespace.media.isolated = true
+namespace.media.visible = true
+
+namespace.media.search.paths = /apex/com.android.media/${LIB}
+namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
+
+namespace.media.links = default
+namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.media.link.default.shared_libs += libandroid.so
+namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# "conscrypt" APEX namespace
+#
+# This namespace is for libraries within the conscrypt APEX.
+###############################################################################
+namespace.conscrypt.isolated = true
+namespace.conscrypt.visible = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.links = default
+namespace.conscrypt.link.default.shared_libs = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+namespace.conscrypt.link.default.shared_libs += libdl.so
+
+###############################################################################
# Namespace config for binaries under /postinstall.
# Only one default namespace is defined and it has no directories other than
# /system/lib and /product/lib in the search paths. This is because linker
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 3804c86..05f75bf 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -109,7 +109,11 @@
# Keep in sync with ld.config.txt in the com.android.runtime APEX.
namespace.default.links = runtime
+# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
+# libart.
+namespace.default.visible = true
namespace.default.link.runtime.shared_libs = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
namespace.default.link.runtime.shared_libs += libnativebridge.so
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -123,6 +127,7 @@
# Keep in sync with ld.config.txt in the com.android.runtime APEX.
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = default
# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
# when it exists.
@@ -137,11 +142,13 @@
namespace.media.visible = true
namespace.media.search.paths = /apex/com.android.media/${LIB}
+namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
namespace.media.links = default
namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.media.link.default.shared_libs += libandroid.so
namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libmediametrics.so
namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
@@ -152,11 +159,13 @@
namespace.conscrypt.isolated = true
namespace.conscrypt.visible = true
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
-namespace.conscrypt.link.default.allow_all_shared_libs = true
+namespace.conscrypt.link.default.shared_libs = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+namespace.conscrypt.link.default.shared_libs += libdl.so
###############################################################################
# "sphal" namespace
@@ -310,7 +319,7 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
-additional.namespaces = system,vndk
+additional.namespaces = runtime,system,vndk
###############################################################################
# "default" namespace
@@ -321,6 +330,9 @@
# partition (VNDK and LLNDK libraries) are not loaded here but from the
# separate namespace 'system'. The delegation to the system namespace is done
# via the 'namespace.default.link.system.shared_libs' property below.
+#
+# '#VNDK27#' TAG is only for building ld.config.27.txt for backward
+# compatibility. (TODO:b/123390078) Move them to a separate file.
###############################################################################
namespace.default.isolated = true
namespace.default.visible = true
@@ -330,11 +342,17 @@
namespace.default.permitted.paths = /odm
namespace.default.permitted.paths += /vendor
+#VNDK27#namespace.default.search.paths += /vendor/${LIB}/hw
+#VNDK27#namespace.default.search.paths += /vendor/${LIB}/egl
namespace.default.asan.search.paths = /data/asan/odm/${LIB}
namespace.default.asan.search.paths += /odm/${LIB}
namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
namespace.default.asan.search.paths += /vendor/${LIB}
+#VNDK27#namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/hw
+#VNDK27#namespace.default.asan.search.paths += /vendor/${LIB}/hw
+#VNDK27#namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/egl
+#VNDK27#namespace.default.asan.search.paths += /vendor/${LIB}/egl
namespace.default.asan.permitted.paths = /data/asan/odm
namespace.default.asan.permitted.paths += /odm
@@ -347,6 +365,20 @@
namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = system
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.system.allow_all_shared_libs = true
+
+###############################################################################
# "vndk" namespace
#
# This namespace is where VNDK and VNDK-SP libraries are loaded for
@@ -403,6 +435,9 @@
namespace.system.asan.search.paths += /data/asan/product_services/${LIB}
namespace.system.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
+namespace.system.links = runtime
+namespace.system.link.runtime.shared_libs = libdexfile_external.so
+
###############################################################################
# Namespace config for binaries under /postinstall.
# Only default namespace is defined and default has no directories
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 2ce25b5..335369e 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -55,9 +55,14 @@
namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
namespace.default.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# Keep in sync with the platform namespace in the com.android.runtime APEX
+# ld.config.txt.
namespace.default.links = runtime
+# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
+# libart.
+namespace.default.visible = true
namespace.default.link.runtime.shared_libs = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -68,8 +73,10 @@
###############################################################################
namespace.runtime.isolated = true
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# Keep in sync with the default namespace in the com.android.runtime APEX
+# ld.config.txt.
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = default
# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
# when it exists.
@@ -84,11 +91,13 @@
namespace.media.visible = true
namespace.media.search.paths = /apex/com.android.media/${LIB}
+namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
namespace.media.links = default
namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.media.link.default.shared_libs += libandroid.so
namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libmediametrics.so
namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
@@ -99,11 +108,13 @@
namespace.conscrypt.isolated = true
namespace.conscrypt.visible = true
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
namespace.conscrypt.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
-namespace.conscrypt.link.default.allow_all_shared_libs = true
+namespace.conscrypt.link.default.shared_libs = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+namespace.conscrypt.link.default.shared_libs += libdl.so
###############################################################################
# "sphal" namespace
@@ -251,6 +262,8 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
+additional.namespaces = runtime
+
namespace.default.isolated = false
namespace.default.search.paths = /odm/${LIB}
@@ -290,6 +303,23 @@
namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
namespace.default.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
+namespace.default.links = runtime
+namespace.default.link.runtime.shared_libs = libdexfile_external.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
###############################################################################
# Namespace config for binaries under /postinstall.
# Only default namespace is defined and default has no directories
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 2e95687..e8c5d8e 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -4,6 +4,7 @@
user root
group root readproc reserved_disk
socket zygote stream 660 root system
+ socket blastula_pool stream 660 root system
updatable
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 1cfc3d6..9c7e807 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -4,6 +4,7 @@
user root
group root readproc reserved_disk
socket zygote stream 660 root system
+ socket blastula_pool stream 660 root system
updatable
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -20,6 +21,7 @@
user root
group root readproc reserved_disk
socket zygote_secondary stream 660 root system
+ socket blastula_pool_secondary stream 660 root system
updatable
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 8ab012d..9908c99 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -4,6 +4,7 @@
user root
group root readproc reserved_disk
socket zygote stream 660 root system
+ socket blastula_pool stream 660 root system
updatable
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 5abf149..0b5edff 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -4,6 +4,7 @@
user root
group root readproc reserved_disk
socket zygote stream 660 root system
+ socket blastula_pool stream 660 root system
updatable
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -20,6 +21,7 @@
user root
group root readproc reserved_disk
socket zygote_secondary stream 660 root system
+ socket blastula_pool_secondary stream 660 root system
updatable
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index 79bed7b..450be66 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -88,6 +88,7 @@
$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_SUFFIX := $(vndk_version_suffix)
$(LOCAL_BUILT_MODULE): PRIVATE_INTERMEDIATES_DIR := $(intermediates_dir)
$(LOCAL_BUILT_MODULE): PRIVATE_COMP_CHECK_SCRIPT := $(compatibility_check_script)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_TAG := \#VNDK$(vndk_version)\#
deps := $(llndk_libraries_file) $(vndksp_libraries_file) $(vndkcore_libraries_file) \
$(vndkprivate_libraries_file)
ifeq ($(check_backward_compatibility),true)
@@ -114,10 +115,12 @@
paste -sd ":" $(PRIVATE_INTERMEDIATES_DIR)/private_llndk | \
sed -i.bak -e "s?%PRIVATE_LLNDK_LIBRARIES%?$$(cat -)?g" $@
- $(hide) sed -i.bak -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
- $(hide) sed -i.bak -e 's?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g' $@
- $(hide) sed -i.bak -e 's?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g' $@
- $(hide) sed -i.bak -e 's?%PRODUCT_SERVICES%?$(TARGET_COPY_OUT_PRODUCT_SERVICES)?g' $@
+ $(hide) sed -i.bak -e "s?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g" $@
+ $(hide) sed -i.bak -e "s?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g" $@
+ $(hide) sed -i.bak -e "s?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g" $@
+ $(hide) sed -i.bak -e "s?%PRODUCT_SERVICES%?$(TARGET_COPY_OUT_PRODUCT_SERVICES)?g" $@
+ $(hide) sed -i.bak -e "s?^$(PRIVATE_VNDK_VERSION_TAG)??g" $@
+ $(hide) sed -i.bak "/^\#VNDK[0-9]\{2\}\#.*$$/d" $@
$(hide) rm -f $@.bak
ld_config_template :=
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index cb5c5cb..5ce43d5 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -19,6 +19,7 @@
"reboot",
"sh",
"simpleperf",
+ "simpleperf_app_runner",
"tcpdump",
"toolbox",
"toybox",