Merge "Increase fastboot timeout to 30 seconds"
diff --git a/adb/Android.bp b/adb/Android.bp
index 07f052f..a18dc1a 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -277,26 +277,113 @@
},
}
+// libadbd_core contains the common sources to build libadbd and libadbd_services.
cc_library_static {
+ name: "libadbd_core",
+ defaults: ["adb_defaults"],
+ recovery_available: true,
+
+ // libminadbd wants both, as it's used to build native tests.
+ compile_multilib: "both",
+
+ srcs: libadb_srcs + libadb_posix_srcs + [
+ "daemon/auth.cpp",
+ "daemon/jdwp_service.cpp",
+ "daemon/usb.cpp",
+ ],
+
+ local_include_dirs: [
+ "daemon/include",
+ ],
+
+ static_libs: [
+ "libdiagnose_usb",
+ "libqemu_pipe",
+ ],
+
+ shared_libs: [
+ "libasyncio",
+ "libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "liblog",
+ ],
+}
+
+cc_library {
+ name: "libadbd_services",
+ defaults: ["adb_defaults"],
+ recovery_available: true,
+ compile_multilib: "both",
+
+ srcs: [
+ "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",
+ ],
+
+ cflags: [
+ "-D_GNU_SOURCE",
+ "-Wno-deprecated-declarations",
+ ],
+
+ static_libs: [
+ "libadbd_core",
+ "libavb_user",
+ "libdiagnose_usb",
+ "libqemu_pipe",
+
+ // `daemon/shell_service.cpp` uses selinux_android_setcon(), which is not exposed by
+ // libselinux.
+ "libselinux",
+ ],
+
+ shared_libs: [
+ "libasyncio",
+ "libbase",
+ "libbootloader_message",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "libext4_utils",
+ "libfec",
+ "libfec_rs",
+ "libfs_mgr",
+ "liblog",
+ "libmdnssd",
+ ],
+}
+
+cc_library {
name: "libadbd",
defaults: ["adb_defaults"],
recovery_available: true,
- // libminadbd wants both, for some reason.
+ // Avoid getting duplicate symbol of android::build::GetBuildNumber().
+ use_version_lib: false,
+
+ // libminadbd wants both, as it's used to build native tests.
compile_multilib: "both",
- srcs: libadb_srcs + libadb_posix_srcs + [
- "daemon/auth.cpp",
- "daemon/usb.cpp",
- "daemon/jdwp_service.cpp",
+
+ // libadbd doesn't build any additional source, but to expose libadbd_core as a shared library.
+ whole_static_libs: [
+ "libadbd_core",
],
- static_libs: [
+ shared_libs: [
+ "libadbd_services",
"libasyncio",
- "libcrypto_utils",
- "libcrypto",
- "libdiagnose_usb",
- "libqemu_pipe",
"libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "liblog",
],
export_include_dirs: [
@@ -307,19 +394,10 @@
cc_binary {
name: "adbd",
defaults: ["adb_defaults"],
-
recovery_available: true,
srcs: [
"daemon/main.cpp",
- "daemon/mdns.cpp",
- "daemon/file_sync_service.cpp",
- "daemon/framebuffer_service.cpp",
- "daemon/remount_service.cpp",
- "daemon/set_verity_enable_state_service.cpp",
- "daemon/services.cpp",
- "daemon/shell_service.cpp",
- "shell_service_protocol.cpp",
],
cflags: [
@@ -331,27 +409,16 @@
keep_symbols: true,
},
- static_libs: [
+ shared_libs: [
"libadbd",
- "libasyncio",
- "libavb_user",
- "libbootloader_message",
- "libcrypto_utils",
+ "libadbd_services",
+ "libbase",
+ "libcap",
"libcrypto",
- "libdiagnose_usb",
- "libfec",
- "libfec_rs",
- "libfs_mgr",
+ "libcutils",
"liblog",
- "libext4_utils",
- "libmdnssd",
"libminijail",
"libselinux",
- "libsquashfs_utils",
- "libqemu_pipe",
-
- "libbase",
- "libcutils",
],
}
@@ -382,21 +449,20 @@
test_suites: ["device-tests"],
}
-python_binary_host {
+python_test_host {
name: "adb_integration_test_adb",
main: "test_adb.py",
srcs: [
"test_adb.py",
],
- libs: [
- "adb_py",
- ],
+ test_config: "adb_integration_test_adb.xml",
+ test_suites: ["general-tests"],
version: {
py2: {
- enabled: true,
+ enabled: false,
},
py3: {
- enabled: false,
+ enabled: true,
},
},
}
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 38c6f62..8e028f4 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -891,6 +891,10 @@
// child side of the fork
pipe_read.reset();
+ // android::base::Pipe unconditionally opens the pipe with O_CLOEXEC.
+ // Undo this manually.
+ fcntl(pipe_write.get(), F_SETFD, 0);
+
char reply_fd[30];
snprintf(reply_fd, sizeof(reply_fd), "%d", pipe_write.get());
// child process
@@ -1040,7 +1044,7 @@
return 0;
}
-int handle_host_request(const char* service, TransportType type, const char* serial,
+bool handle_host_request(const char* service, TransportType type, const char* serial,
TransportId transport_id, int reply_fd, asocket* s) {
if (strcmp(service, "kill") == 0) {
fprintf(stderr, "adb server killed by remote request\n");
@@ -1066,7 +1070,7 @@
transport_id = strtoll(service, const_cast<char**>(&service), 10);
if (*service != '\0') {
SendFail(reply_fd, "invalid transport id");
- return 1;
+ return true;
}
} else if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
type = kTransportUsb;
@@ -1084,10 +1088,13 @@
if (t != nullptr) {
s->transport = t;
SendOkay(reply_fd);
+
+ // We succesfully handled the device selection, but there's another request coming.
+ return false;
} else {
SendFail(reply_fd, error);
+ return true;
}
- return 1;
}
// return a list of all connected devices
@@ -1097,9 +1104,9 @@
D("Getting device list...");
std::string device_list = list_transports(long_listing);
D("Sending device list...");
- return SendOkay(reply_fd, device_list);
+ SendOkay(reply_fd, device_list);
}
- return 1;
+ return true;
}
if (!strcmp(service, "reconnect-offline")) {
@@ -1115,7 +1122,7 @@
response.resize(response.size() - 1);
}
SendOkay(reply_fd, response);
- return 0;
+ return true;
}
if (!strcmp(service, "features")) {
@@ -1126,7 +1133,7 @@
} else {
SendFail(reply_fd, error);
}
- return 0;
+ return true;
}
if (!strcmp(service, "host-features")) {
@@ -1137,7 +1144,7 @@
}
features.insert(kFeaturePushSync);
SendOkay(reply_fd, FeatureSetToString(features));
- return 0;
+ return true;
}
// remove TCP transport
@@ -1145,7 +1152,8 @@
const std::string address(service + 11);
if (address.empty()) {
kick_all_tcp_devices();
- return SendOkay(reply_fd, "disconnected everything");
+ SendOkay(reply_fd, "disconnected everything");
+ return true;
}
std::string serial;
@@ -1153,21 +1161,24 @@
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
std::string error;
if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
- return SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
- address.c_str(), error.c_str()));
+ SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
+ address.c_str(), error.c_str()));
+ return true;
}
atransport* t = find_transport(serial.c_str());
if (t == nullptr) {
- return SendFail(reply_fd, android::base::StringPrintf("no such device '%s'",
- serial.c_str()));
+ SendFail(reply_fd, android::base::StringPrintf("no such device '%s'", serial.c_str()));
+ return true;
}
kick_transport(t);
- return SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str()));
+ SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str()));
+ return true;
}
// Returns our value for ADB_SERVER_VERSION.
if (!strcmp(service, "version")) {
- return SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
+ SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
+ return true;
}
// These always report "unknown" rather than the actual error, for scripts.
@@ -1175,28 +1186,31 @@
std::string error;
atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (t) {
- return SendOkay(reply_fd, !t->serial.empty() ? t->serial : "unknown");
+ SendOkay(reply_fd, !t->serial.empty() ? t->serial : "unknown");
} else {
- return SendFail(reply_fd, error);
+ SendFail(reply_fd, error);
}
+ return true;
}
if (!strcmp(service, "get-devpath")) {
std::string error;
atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (t) {
- return SendOkay(reply_fd, !t->devpath.empty() ? t->devpath : "unknown");
+ SendOkay(reply_fd, !t->devpath.empty() ? t->devpath : "unknown");
} else {
- return SendFail(reply_fd, error);
+ SendFail(reply_fd, error);
}
+ return true;
}
if (!strcmp(service, "get-state")) {
std::string error;
atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (t) {
- return SendOkay(reply_fd, t->connection_state_name());
+ SendOkay(reply_fd, t->connection_state_name());
} else {
- return SendFail(reply_fd, error);
+ SendFail(reply_fd, error);
}
+ return true;
}
// Indicates a new emulator instance has started.
@@ -1204,7 +1218,7 @@
int port = atoi(service+9);
local_connect(port);
/* we don't even need to send a reply */
- return 0;
+ return true;
}
if (!strcmp(service, "reconnect")) {
@@ -1215,7 +1229,8 @@
response =
"reconnecting " + t->serial_name() + " [" + t->connection_state_name() + "]\n";
}
- return SendOkay(reply_fd, response);
+ SendOkay(reply_fd, response);
+ return true;
}
if (handle_forward_request(service,
@@ -1224,10 +1239,10 @@
error);
},
reply_fd)) {
- return 0;
+ return true;
}
- return -1;
+ return false;
}
static auto& init_mutex = *new std::mutex();
diff --git a/adb/adb.h b/adb/adb.h
index e6af780..f434e2d 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -210,8 +210,8 @@
#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
#endif
-int handle_host_request(const char* service, TransportType type, const char* serial,
- TransportId transport_id, int reply_fd, asocket* s);
+bool handle_host_request(const char* service, TransportType type, const char* serial,
+ TransportId transport_id, int reply_fd, asocket* s);
void handle_online(atransport* t);
void handle_offline(atransport* t);
diff --git a/adb/adb_integration_test_adb.xml b/adb/adb_integration_test_adb.xml
new file mode 100644
index 0000000..e722956
--- /dev/null
+++ b/adb/adb_integration_test_adb.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config to run adb integration tests">
+ <option name="test-suite-tag" value="adb_tests" />
+ <option name="test-suite-tag" value="adb_integration" />
+ <target_preparer class="com.android.tradefed.targetprep.SemaphoreTokenTargetPreparer">
+ <option name="disable" value="false" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.adb.AdbStopServerPreparer" />
+ <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
+ <option name="par-file-name" value="adb_integration_test_adb" />
+ <option name="inject-android-serial" value="true" />
+ <option name="test-timeout" value="2m" />
+ </test>
+</configuration>
diff --git a/adb/adb_unique_fd.cpp b/adb/adb_unique_fd.cpp
index 2079be1..dec73bc 100644
--- a/adb/adb_unique_fd.cpp
+++ b/adb/adb_unique_fd.cpp
@@ -21,45 +21,8 @@
#include "sysdeps.h"
-#if !defined(_WIN32)
-bool Pipe(unique_fd* read, unique_fd* write, int flags) {
- int pipefd[2];
-#if !defined(__APPLE__)
- if (pipe2(pipefd, flags) != 0) {
- return false;
- }
-#else
- // Darwin doesn't have pipe2. Implement it ourselves.
- if (flags != 0 && (flags & ~(O_CLOEXEC | O_NONBLOCK)) != 0) {
- errno = EINVAL;
- return false;
- }
-
- if (pipe(pipefd) != 0) {
- return false;
- }
-
- if (flags & O_CLOEXEC) {
- if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 ||
- fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) {
- adb_close(pipefd[0]);
- adb_close(pipefd[1]);
- return false;
- }
- }
-
- if (flags & O_NONBLOCK) {
- if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0 ||
- fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) {
- adb_close(pipefd[0]);
- adb_close(pipefd[1]);
- return false;
- }
- }
-#endif
-
- read->reset(pipefd[0]);
- write->reset(pipefd[1]);
- return true;
+#if defined(_WIN32)
+void AdbCloser::Close(int fd) {
+ adb_close(fd);
}
#endif
diff --git a/adb/adb_unique_fd.h b/adb/adb_unique_fd.h
index bad501a..d47213d 100644
--- a/adb/adb_unique_fd.h
+++ b/adb/adb_unique_fd.h
@@ -21,15 +21,15 @@
#include <android-base/unique_fd.h>
+#if defined(_WIN32)
// Helper to automatically close an FD when it goes out of scope.
struct AdbCloser {
static void Close(int fd);
};
using unique_fd = android::base::unique_fd_impl<AdbCloser>;
-
-#if !defined(_WIN32)
-bool Pipe(unique_fd* read, unique_fd* write, int flags = 0);
+#else
+using unique_fd = android::base::unique_fd;
#endif
template <typename T>
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 0c3327f..ffac315 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -274,10 +274,6 @@
return android_dir;
}
-void AdbCloser::Close(int fd) {
- adb_close(fd);
-}
-
int syntax_error(const char* fmt, ...) {
fprintf(stderr, "adb: usage: ");
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 5fbef09..71c19b8 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -465,6 +465,7 @@
if (key == nullptr) {
// No more private keys to try, send the public key.
t->SetConnectionState(kCsUnauthorized);
+ t->SetConnectionEstablished(true);
send_auth_publickey(t);
return;
}
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 3fb14f3..41ac663 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1326,9 +1326,9 @@
}
int adb_commandline(int argc, const char** argv) {
- int no_daemon = 0;
- int is_daemon = 0;
- int is_server = 0;
+ bool no_daemon = false;
+ bool is_daemon = false;
+ bool is_server = false;
int r;
TransportType transport_type = kTransportAny;
int ack_reply_fd = -1;
@@ -1348,12 +1348,12 @@
while (argc > 0) {
if (!strcmp(argv[0],"server")) {
- is_server = 1;
+ is_server = true;
} else if (!strcmp(argv[0],"nodaemon")) {
- no_daemon = 1;
+ no_daemon = true;
} else if (!strcmp(argv[0], "fork-server")) {
/* this is a special flag used only when the ADB client launches the ADB Server */
- is_daemon = 1;
+ is_daemon = true;
} else if (!strcmp(argv[0], "--reply-fd")) {
if (argc < 2) return syntax_error("--reply-fd requires an argument");
const char* reply_fd_str = argv[1];
@@ -1925,7 +1925,8 @@
for (int i = argc - 1; i >= 0; i--) {
const char* file = argv[i];
- if (android::base::EndsWithIgnoreCase(file, ".apk")) {
+ if (android::base::EndsWithIgnoreCase(file, ".apk") ||
+ android::base::EndsWithIgnoreCase(file, ".dm")) {
struct stat sb;
if (stat(file, &sb) != -1) total_size += sb.st_size;
first_apk = i;
@@ -1986,9 +1987,8 @@
}
std::string cmd = android::base::StringPrintf(
- "%s install-write -S %" PRIu64 " %d %d_%s -",
- install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i,
- android::base::Basename(file).c_str());
+ "%s install-write -S %" PRIu64 " %d %s -", install_cmd.c_str(),
+ static_cast<uint64_t>(sb.st_size), session_id, android::base::Basename(file).c_str());
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index de6c723..095ad98 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -118,10 +118,20 @@
init_transport_registration();
init_reconnect_handler();
- init_mdns_transport_discovery();
- usb_init();
- local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+ if (!getenv("ADB_MDNS") || strcmp(getenv("ADB_MDNS"), "0") != 0) {
+ init_mdns_transport_discovery();
+ }
+
+ if (!getenv("ADB_USB") || strcmp(getenv("ADB_USB"), "0") != 0) {
+ usb_init();
+ } else {
+ adb_notify_device_scan_complete();
+ }
+
+ if (!getenv("ADB_EMU") || strcmp(getenv("ADB_EMU"), "0") != 0) {
+ local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+ }
std::string error;
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index 0e79d82..f7017dd 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -30,6 +30,7 @@
#include <sys/vfs.h>
#include <unistd.h>
+#include <memory>
#include <set>
#include <string>
#include <vector>
@@ -38,28 +39,30 @@
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
#include <ext4_utils/ext4_utils.h>
+#include <fs_mgr.h>
+#include <fs_mgr_overlayfs.h>
#include "adb.h"
#include "adb_io.h"
#include "adb_unique_fd.h"
#include "adb_utils.h"
-#include "fs_mgr.h"
#include "set_verity_enable_state_service.h"
-// Returns the device used to mount a directory in /proc/mounts.
+// Returns the last device used to mount a directory in /proc/mounts.
+// This will find overlayfs entry where upperdir=lowerdir, to make sure
+// remount is associated with the correct directory.
static std::string find_proc_mount(const char* dir) {
std::unique_ptr<FILE, int(*)(FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
- if (!fp) {
- return "";
- }
+ std::string mnt_fsname;
+ if (!fp) return mnt_fsname;
mntent* e;
while ((e = getmntent(fp.get())) != nullptr) {
if (strcmp(dir, e->mnt_dir) == 0) {
- return e->mnt_fsname;
+ mnt_fsname = e->mnt_fsname;
}
}
- return "";
+ return mnt_fsname;
}
// Returns the device used to mount a directory in the fstab.
@@ -81,6 +84,7 @@
}
bool make_block_device_writable(const std::string& dev) {
+ if ((dev == "overlay") || (dev == "overlayfs")) return true;
int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
return false;
@@ -234,6 +238,14 @@
partitions.push_back("/system");
}
+ bool verity_enabled = (system_verified || vendor_verified);
+
+ // If we can use overlayfs, lets get it in place first
+ // before we struggle with determining deduplication operations.
+ if (!verity_enabled && fs_mgr_overlayfs_setup() && fs_mgr_overlayfs_mount_all()) {
+ WriteFdExactly(fd.get(), "overlayfs mounted\n");
+ }
+
// Find partitions that are deduplicated, and can be un-deduplicated.
std::set<std::string> dedup;
for (const auto& partition : partitions) {
@@ -246,8 +258,6 @@
}
}
- bool verity_enabled = (system_verified || vendor_verified);
-
// Reboot now if the user requested it (and an operation needs a reboot).
if (user_requested_reboot) {
if (!dedup.empty() || verity_enabled) {
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 1f59d64..dfcc52d 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -94,7 +94,7 @@
WriteFdExactly(fd.get(), "restarting in USB mode\n");
}
-bool reboot_service_impl(unique_fd fd, const std::string& arg) {
+void reboot_service(unique_fd fd, const std::string& arg) {
std::string reboot_arg = arg;
bool auto_reboot = false;
@@ -108,7 +108,7 @@
if (reboot_arg == "sideload") {
if (getuid() != 0) {
WriteFdExactly(fd.get(), "'adb root' is required for 'adb reboot sideload'.\n");
- return false;
+ return;
}
const std::vector<std::string> options = {auto_reboot ? "--sideload_auto_reboot"
@@ -116,7 +116,7 @@
std::string err;
if (!write_bootloader_message(options, &err)) {
D("Failed to set bootloader message: %s", err.c_str());
- return false;
+ return;
}
reboot_arg = "recovery";
@@ -128,16 +128,9 @@
std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
WriteFdFmt(fd.get(), "reboot (%s) failed\n", reboot_string.c_str());
- return false;
- }
-
- return true;
-}
-
-void reboot_service(unique_fd fd, const std::string& arg) {
- if (!reboot_service_impl(std::move(fd), arg)) {
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) {
diff --git a/adb/daemon/set_verity_enable_state_service.cpp b/adb/daemon/set_verity_enable_state_service.cpp
index 2b6ec21..3676de5 100644
--- a/adb/daemon/set_verity_enable_state_service.cpp
+++ b/adb/daemon/set_verity_enable_state_service.cpp
@@ -19,6 +19,7 @@
#include "set_verity_enable_state_service.h"
#include "sysdeps.h"
+#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libavb_user/libavb_user.h>
@@ -28,12 +29,14 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <fs_mgr.h>
+#include <fs_mgr_overlayfs.h>
+#include <fstab/fstab.h>
#include <log/log_properties.h>
#include "adb.h"
#include "adb_io.h"
#include "adb_unique_fd.h"
-#include "fs_mgr.h"
#include "remount_service.h"
#include "fec/io.h"
@@ -46,6 +49,10 @@
static const bool kAllowDisableVerity = false;
#endif
+void suggest_run_adb_root(int fd) {
+ if (getuid() != 0) WriteFdExactly(fd, "Maybe run adb root?\n");
+}
+
/* Turn verity on/off */
static bool set_verity_enabled_state(int fd, const char* block_device, const char* mount_point,
bool enable) {
@@ -59,7 +66,7 @@
if (!fh) {
WriteFdFmt(fd, "Could not open block device %s (%s).\n", block_device, strerror(errno));
- WriteFdFmt(fd, "Maybe run adb root?\n");
+ suggest_run_adb_root(fd);
return false;
}
@@ -87,6 +94,17 @@
return false;
}
+ auto change = false;
+ errno = 0;
+ if (enable ? fs_mgr_overlayfs_teardown(mount_point, &change)
+ : fs_mgr_overlayfs_setup(nullptr, mount_point, &change)) {
+ if (change) {
+ WriteFdFmt(fd, "%s overlayfs for %s\n", enable ? "disabling" : "using", mount_point);
+ }
+ } else if (errno) {
+ WriteFdFmt(fd, "Overlayfs %s for %s failed with error %s\n", enable ? "teardown" : "setup",
+ mount_point, strerror(errno));
+ }
WriteFdFmt(fd, "Verity %s on %s\n", enable ? "enabled" : "disabled", mount_point);
return true;
}
@@ -103,6 +121,22 @@
return android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked";
}
+static bool overlayfs_setup(int fd, bool enable) {
+ auto change = false;
+ errno = 0;
+ if (enable ? fs_mgr_overlayfs_teardown(nullptr, &change)
+ : fs_mgr_overlayfs_setup(nullptr, nullptr, &change)) {
+ if (change) {
+ WriteFdFmt(fd, "%s overlayfs\n", enable ? "disabling" : "using");
+ }
+ } else if (errno) {
+ WriteFdFmt(fd, "Overlayfs %s failed with error %s\n", enable ? "teardown" : "setup",
+ strerror(errno));
+ suggest_run_adb_root(fd);
+ }
+ return change;
+}
+
/* Use AVB to turn verity on/off */
static bool set_avb_verity_enabled_state(int fd, AvbOps* ops, bool enable_verity) {
std::string ab_suffix = get_ab_suffix();
@@ -128,6 +162,7 @@
return false;
}
+ overlayfs_setup(fd, enable_verity);
WriteFdFmt(fd, "Successfully %s verity\n", enable_verity ? "enabled" : "disabled");
return true;
}
@@ -150,6 +185,7 @@
}
if (!android::base::GetBoolProperty("ro.secure", false)) {
+ overlayfs_setup(fd, enable);
WriteFdExactly(fd.get(), "verity not enabled - ENG build\n");
return;
}
@@ -177,13 +213,14 @@
// Not using AVB - assume VB1.0.
// read all fstab entries at once from all sources
- fstab = fs_mgr_read_fstab_default();
+ if (!fstab) fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- WriteFdExactly(fd.get(), "Failed to read fstab\nMaybe run adb root?\n");
+ WriteFdExactly(fd.get(), "Failed to read fstab\n");
+ suggest_run_adb_root(fd.get());
return;
}
- // Loop through entries looking for ones that vold manages.
+ // Loop through entries looking for ones that verity manages.
for (int i = 0; i < fstab->num_entries; i++) {
if (fs_mgr_is_verified(&fstab->recs[i])) {
if (set_verity_enabled_state(fd.get(), fstab->recs[i].blk_device,
@@ -193,6 +230,7 @@
}
}
}
+ if (!any_changed) any_changed = overlayfs_setup(fd, enable);
if (any_changed) {
WriteFdExactly(fd.get(), "Now reboot your device for settings to take effect\n");
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 69b5180..1534792 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -685,13 +685,9 @@
if (service) {
asocket* s2;
- /* some requests are handled immediately -- in that
- ** case the handle_host_request() routine has sent
- ** the OKAY or FAIL message and all we have to do
- ** is clean up.
- */
- if (handle_host_request(service, type, serial, transport_id, s->peer->fd, s) == 0) {
- /* XXX fail message? */
+ // Some requests are handled immediately -- in that case the handle_host_request() routine
+ // has sent the OKAY or FAIL message and all we have to do is clean up.
+ if (handle_host_request(service, type, serial, transport_id, s->peer->fd, s)) {
D("SS(%d): handled host service '%s'", s->id, service);
goto fail;
}
diff --git a/adb/test_adb.py b/adb/test_adb.py
old mode 100644
new mode 100755
index ddd3ff0..d4c98e4
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (C) 2015 The Android Open Source Project
#
@@ -19,9 +19,7 @@
This differs from things in test_device.py in that there is no API for these
things. Most of these tests involve specific error messages or the help text.
"""
-from __future__ import print_function
-import binascii
import contextlib
import os
import random
@@ -32,8 +30,6 @@
import threading
import unittest
-import adb
-
@contextlib.contextmanager
def fake_adbd(protocol=socket.AF_INET, port=0):
@@ -42,61 +38,61 @@
serversock = socket.socket(protocol, socket.SOCK_STREAM)
serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if protocol == socket.AF_INET:
- serversock.bind(('127.0.0.1', port))
+ serversock.bind(("127.0.0.1", port))
else:
- serversock.bind(('::1', port))
+ serversock.bind(("::1", port))
serversock.listen(1)
# A pipe that is used to signal the thread that it should terminate.
- readpipe, writepipe = os.pipe()
+ readsock, writesock = socket.socketpair()
- def _adb_packet(command, arg0, arg1, data):
- bin_command = struct.unpack('I', command)[0]
- buf = struct.pack('IIIIII', bin_command, arg0, arg1, len(data), 0,
+ def _adb_packet(command: bytes, arg0: int, arg1: int, data: bytes) -> bytes:
+ bin_command = struct.unpack("I", command)[0]
+ buf = struct.pack("IIIIII", bin_command, arg0, arg1, len(data), 0,
bin_command ^ 0xffffffff)
buf += data
return buf
- def _handle():
- rlist = [readpipe, serversock]
- cnxn_sent = {}
- while True:
- read_ready, _, _ = select.select(rlist, [], [])
- for ready in read_ready:
- if ready == readpipe:
- # Closure pipe
- os.close(ready)
- serversock.shutdown(socket.SHUT_RDWR)
- serversock.close()
- return
- elif ready == serversock:
- # Server socket
- conn, _ = ready.accept()
- rlist.append(conn)
- else:
- # Client socket
- data = ready.recv(1024)
- if not data or data.startswith('OPEN'):
+ def _handle(sock):
+ with contextlib.closing(sock) as serversock:
+ rlist = [readsock, serversock]
+ cnxn_sent = {}
+ while True:
+ read_ready, _, _ = select.select(rlist, [], [])
+ for ready in read_ready:
+ if ready == readsock:
+ # Closure pipe
+ for f in rlist:
+ f.close()
+ return
+ elif ready == serversock:
+ # Server socket
+ conn, _ = ready.accept()
+ rlist.append(conn)
+ else:
+ # Client socket
+ data = ready.recv(1024)
+ if not data or data.startswith(b"OPEN"):
+ if ready in cnxn_sent:
+ del cnxn_sent[ready]
+ ready.shutdown(socket.SHUT_RDWR)
+ ready.close()
+ rlist.remove(ready)
+ continue
if ready in cnxn_sent:
- del cnxn_sent[ready]
- ready.shutdown(socket.SHUT_RDWR)
- ready.close()
- rlist.remove(ready)
- continue
- if ready in cnxn_sent:
- continue
- cnxn_sent[ready] = True
- ready.sendall(_adb_packet('CNXN', 0x01000001, 1024 * 1024,
- 'device::ro.product.name=fakeadb'))
+ continue
+ cnxn_sent[ready] = True
+ ready.sendall(_adb_packet(b"CNXN", 0x01000001, 1024 * 1024,
+ b"device::ro.product.name=fakeadb"))
port = serversock.getsockname()[1]
- server_thread = threading.Thread(target=_handle)
+ server_thread = threading.Thread(target=_handle, args=(serversock,))
server_thread.start()
try:
yield port
finally:
- os.close(writepipe)
+ writesock.close()
server_thread.join()
@@ -107,14 +103,15 @@
This automatically disconnects when done with the connection.
"""
- output = subprocess.check_output(['adb', 'connect', serial])
- unittest.assertEqual(output.strip(), 'connected to {}'.format(serial))
+ output = subprocess.check_output(["adb", "connect", serial])
+ unittest.assertEqual(output.strip(),
+ "connected to {}".format(serial).encode("utf8"))
try:
yield
finally:
# Perform best-effort disconnection. Discard the output.
- subprocess.Popen(['adb', 'disconnect', serial],
+ subprocess.Popen(["adb", "disconnect", serial],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()
@@ -123,21 +120,22 @@
def adb_server():
"""Context manager for an ADB server.
- This creates an ADB server and returns the port it's listening on.
+ This creates an ADB server and returns the port it"s listening on.
"""
port = 5038
# Kill any existing server on this non-default port.
- subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
+ subprocess.check_output(["adb", "-P", str(port), "kill-server"],
stderr=subprocess.STDOUT)
read_pipe, write_pipe = os.pipe()
- proc = subprocess.Popen(['adb', '-L', 'tcp:localhost:{}'.format(port),
- 'fork-server', 'server',
- '--reply-fd', str(write_pipe)])
+ os.set_inheritable(write_pipe, True)
+ proc = subprocess.Popen(["adb", "-L", "tcp:localhost:{}".format(port),
+ "fork-server", "server",
+ "--reply-fd", str(write_pipe)], close_fds=False)
try:
os.close(write_pipe)
greeting = os.read(read_pipe, 1024)
- assert greeting == 'OK\n', repr(greeting)
+ assert greeting == b"OK\n", repr(greeting)
yield port
finally:
proc.terminate()
@@ -150,35 +148,37 @@
def test_help(self):
"""Make sure we get _something_ out of help."""
out = subprocess.check_output(
- ['adb', 'help'], stderr=subprocess.STDOUT)
+ ["adb", "help"], stderr=subprocess.STDOUT)
self.assertGreater(len(out), 0)
def test_version(self):
"""Get a version number out of the output of adb."""
- lines = subprocess.check_output(['adb', 'version']).splitlines()
+ lines = subprocess.check_output(["adb", "version"]).splitlines()
version_line = lines[0]
- self.assertRegexpMatches(
- version_line, r'^Android Debug Bridge version \d+\.\d+\.\d+$')
+ self.assertRegex(
+ version_line, rb"^Android Debug Bridge version \d+\.\d+\.\d+$")
if len(lines) == 2:
# Newer versions of ADB have a second line of output for the
# version that includes a specific revision (git SHA).
revision_line = lines[1]
- self.assertRegexpMatches(
- revision_line, r'^Revision [0-9a-f]{12}-android$')
+ self.assertRegex(
+ revision_line, rb"^Revision [0-9a-f]{12}-android$")
def test_tcpip_error_messages(self):
"""Make sure 'adb tcpip' parsing is sane."""
- proc = subprocess.Popen(['adb', 'tcpip'], stdout=subprocess.PIPE,
+ proc = subprocess.Popen(["adb", "tcpip"],
+ stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
out, _ = proc.communicate()
self.assertEqual(1, proc.returncode)
- self.assertIn('requires an argument', out)
+ self.assertIn(b"requires an argument", out)
- proc = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
+ proc = subprocess.Popen(["adb", "tcpip", "foo"],
+ stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
out, _ = proc.communicate()
self.assertEqual(1, proc.returncode)
- self.assertIn('invalid port', out)
+ self.assertIn(b"invalid port", out)
class ServerTest(unittest.TestCase):
@@ -214,12 +214,12 @@
port = 5038
# Kill any existing server on this non-default port.
- subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
+ subprocess.check_output(["adb", "-P", str(port), "kill-server"],
stderr=subprocess.STDOUT)
try:
# Run the adb client and have it start the adb server.
- proc = subprocess.Popen(['adb', '-P', str(port), 'start-server'],
+ proc = subprocess.Popen(["adb", "-P", str(port), "start-server"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
@@ -229,14 +229,12 @@
stdout_thread = threading.Thread(
target=ServerTest._read_pipe_and_set_event,
args=(proc.stdout, stdout_event))
- stdout_thread.daemon = True
stdout_thread.start()
stderr_event = threading.Event()
stderr_thread = threading.Thread(
target=ServerTest._read_pipe_and_set_event,
args=(proc.stderr, stderr_event))
- stderr_thread.daemon = True
stderr_thread.start()
# Wait for the adb client to finish. Once that has occurred, if
@@ -250,7 +248,8 @@
# probably letting the adb server inherit stdin which would be
# wrong.
with self.assertRaises(IOError):
- proc.stdin.write('x')
+ proc.stdin.write(b"x")
+ proc.stdin.flush()
# Wait a few seconds for stdout/stderr to be closed (in the success
# case, this won't wait at all). If there is a timeout, that means
@@ -259,9 +258,11 @@
# inherit stdout/stderr which would be wrong.
self.assertTrue(stdout_event.wait(5), "adb stdout not closed")
self.assertTrue(stderr_event.wait(5), "adb stderr not closed")
+ stdout_thread.join()
+ stderr_thread.join()
finally:
# If we started a server, kill it.
- subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
+ subprocess.check_output(["adb", "-P", str(port), "kill-server"],
stderr=subprocess.STDOUT)
@@ -271,7 +272,7 @@
def _reset_socket_on_close(self, sock):
"""Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
# The linger structure is two shorts on Windows, but two ints on Unix.
- linger_format = 'hh' if os.name == 'nt' else 'ii'
+ linger_format = "hh" if os.name == "nt" else "ii"
l_onoff = 1
l_linger = 0
@@ -292,33 +293,33 @@
# Use SO_REUSEADDR so subsequent runs of the test can grab the port
# even if it is in TIME_WAIT.
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- listener.bind(('127.0.0.1', 0))
+ listener.bind(("127.0.0.1", 0))
listener.listen(4)
port = listener.getsockname()[1]
# Now that listening has started, start adb emu kill, telling it to
# connect to our mock emulator.
proc = subprocess.Popen(
- ['adb', '-s', 'emulator-' + str(port), 'emu', 'kill'],
+ ["adb", "-s", "emulator-" + str(port), "emu", "kill"],
stderr=subprocess.STDOUT)
accepted_connection, addr = listener.accept()
with contextlib.closing(accepted_connection) as conn:
# If WSAECONNABORTED (10053) is raised by any socket calls,
# then adb probably isn't reading the data that we sent it.
- conn.sendall('Android Console: type \'help\' for a list ' +
- 'of commands\r\n')
- conn.sendall('OK\r\n')
+ conn.sendall(("Android Console: type 'help' for a list "
+ "of commands\r\n").encode("utf8"))
+ conn.sendall(b"OK\r\n")
with contextlib.closing(conn.makefile()) as connf:
line = connf.readline()
- if line.startswith('auth'):
+ if line.startswith("auth"):
# Ignore the first auth line.
line = connf.readline()
- self.assertEqual('kill\n', line)
- self.assertEqual('quit\n', connf.readline())
+ self.assertEqual("kill\n", line)
+ self.assertEqual("quit\n", connf.readline())
- conn.sendall('OK: killing emulator, bye bye\r\n')
+ conn.sendall(b"OK: killing emulator, bye bye\r\n")
# Use SO_LINGER to send TCP RST segment to test whether adb
# ignores WSAECONNRESET on Windows. This happens with the
@@ -342,31 +343,31 @@
"""
with adb_server() as server_port:
with fake_adbd() as port:
- serial = 'emulator-{}'.format(port - 1)
+ serial = "emulator-{}".format(port - 1)
# Ensure that the emulator is not there.
try:
- subprocess.check_output(['adb', '-P', str(server_port),
- '-s', serial, 'get-state'],
+ subprocess.check_output(["adb", "-P", str(server_port),
+ "-s", serial, "get-state"],
stderr=subprocess.STDOUT)
- self.fail('Device should not be available')
+ self.fail("Device should not be available")
except subprocess.CalledProcessError as err:
self.assertEqual(
err.output.strip(),
- 'error: device \'{}\' not found'.format(serial))
+ "error: device '{}' not found".format(serial).encode("utf8"))
# Let the ADB server know that the emulator has started.
with contextlib.closing(
- socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
- sock.connect(('localhost', server_port))
- command = 'host:emulator:{}'.format(port)
- sock.sendall('%04x%s' % (len(command), command))
+ socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
+ sock.connect(("localhost", server_port))
+ command = "host:emulator:{}".format(port).encode("utf8")
+ sock.sendall(b"%04x%s" % (len(command), command))
# Ensure the emulator is there.
- subprocess.check_call(['adb', '-P', str(server_port),
- '-s', serial, 'wait-for-device'])
- output = subprocess.check_output(['adb', '-P', str(server_port),
- '-s', serial, 'get-state'])
- self.assertEqual(output.strip(), 'device')
+ subprocess.check_call(["adb", "-P", str(server_port),
+ "-s", serial, "wait-for-device"])
+ output = subprocess.check_output(["adb", "-P", str(server_port),
+ "-s", serial, "get-state"])
+ self.assertEqual(output.strip(), b"device")
class ConnectionTest(unittest.TestCase):
@@ -380,7 +381,7 @@
for protocol in (socket.AF_INET, socket.AF_INET6):
try:
with fake_adbd(protocol=protocol) as port:
- serial = 'localhost:{}'.format(port)
+ serial = "localhost:{}".format(port)
with adb_connect(self, serial):
pass
except socket.error:
@@ -391,49 +392,51 @@
"""Ensure that an already-connected device stays connected."""
with fake_adbd() as port:
- serial = 'localhost:{}'.format(port)
+ serial = "localhost:{}".format(port)
with adb_connect(self, serial):
# b/31250450: this always returns 0 but probably shouldn't.
- output = subprocess.check_output(['adb', 'connect', serial])
+ output = subprocess.check_output(["adb", "connect", serial])
self.assertEqual(
- output.strip(), 'already connected to {}'.format(serial))
+ output.strip(),
+ "already connected to {}".format(serial).encode("utf8"))
def test_reconnect(self):
"""Ensure that a disconnected device reconnects."""
with fake_adbd() as port:
- serial = 'localhost:{}'.format(port)
+ serial = "localhost:{}".format(port)
with adb_connect(self, serial):
- output = subprocess.check_output(['adb', '-s', serial,
- 'get-state'])
- self.assertEqual(output.strip(), 'device')
+ output = subprocess.check_output(["adb", "-s", serial,
+ "get-state"])
+ self.assertEqual(output.strip(), b"device")
# This will fail.
- proc = subprocess.Popen(['adb', '-s', serial, 'shell', 'true'],
+ proc = subprocess.Popen(["adb", "-s", serial, "shell", "true"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
output, _ = proc.communicate()
- self.assertEqual(output.strip(), 'error: closed')
+ self.assertEqual(output.strip(), b"error: closed")
- subprocess.check_call(['adb', '-s', serial, 'wait-for-device'])
+ subprocess.check_call(["adb", "-s", serial, "wait-for-device"])
- output = subprocess.check_output(['adb', '-s', serial,
- 'get-state'])
- self.assertEqual(output.strip(), 'device')
+ output = subprocess.check_output(["adb", "-s", serial,
+ "get-state"])
+ self.assertEqual(output.strip(), b"device")
# Once we explicitly kick a device, it won't attempt to
# reconnect.
- output = subprocess.check_output(['adb', 'disconnect', serial])
+ output = subprocess.check_output(["adb", "disconnect", serial])
self.assertEqual(
- output.strip(), 'disconnected {}'.format(serial))
+ output.strip(),
+ "disconnected {}".format(serial).encode("utf8"))
try:
- subprocess.check_output(['adb', '-s', serial, 'get-state'],
+ subprocess.check_output(["adb", "-s", serial, "get-state"],
stderr=subprocess.STDOUT)
- self.fail('Device should not be available')
+ self.fail("Device should not be available")
except subprocess.CalledProcessError as err:
self.assertEqual(
err.output.strip(),
- 'error: device \'{}\' not found'.format(serial))
+ "error: device '{}' not found".format(serial).encode("utf8"))
def main():
@@ -442,5 +445,5 @@
unittest.main(verbosity=3)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/adb/test_device.py b/adb/test_device.py
index 4abe7a7..42aadc4 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -762,9 +762,10 @@
os.chmod(host_dir, 0o700)
# Create an empty directory.
- os.mkdir(os.path.join(host_dir, 'empty'))
+ empty_dir_path = os.path.join(host_dir, 'empty')
+ os.mkdir(empty_dir_path);
- self.device.push(host_dir, self.DEVICE_TEMP_DIR)
+ self.device.push(empty_dir_path, self.DEVICE_TEMP_DIR)
test_empty_cmd = ['[', '-d',
os.path.join(self.DEVICE_TEMP_DIR, 'empty')]
@@ -1032,7 +1033,8 @@
if host_dir is not None:
shutil.rmtree(host_dir)
- def test_pull_symlink_dir(self):
+ # selinux prevents adbd from accessing symlinks on /data/local/tmp.
+ def disabled_test_pull_symlink_dir(self):
"""Pull a symlink to a directory of symlinks to files."""
try:
host_dir = tempfile.mkdtemp()
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 9222008..4cd19f9 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -33,7 +33,7 @@
#include <deque>
#include <list>
#include <mutex>
-#include <queue>
+#include <set>
#include <thread>
#include <android-base/logging.h>
@@ -108,9 +108,11 @@
size_t attempts_left;
bool operator<(const ReconnectAttempt& rhs) const {
- // std::priority_queue returns the largest element first, so we want attempts that have
- // less time remaining (i.e. smaller time_points) to compare greater.
- return reconnect_time > rhs.reconnect_time;
+ if (reconnect_time == rhs.reconnect_time) {
+ return reinterpret_cast<uintptr_t>(transport) <
+ reinterpret_cast<uintptr_t>(rhs.transport);
+ }
+ return reconnect_time < rhs.reconnect_time;
}
};
@@ -123,7 +125,7 @@
bool running_ GUARDED_BY(reconnect_mutex_) = true;
std::thread handler_thread_;
std::condition_variable reconnect_cv_;
- std::priority_queue<ReconnectAttempt> reconnect_queue_ GUARDED_BY(reconnect_mutex_);
+ std::set<ReconnectAttempt> reconnect_queue_ GUARDED_BY(reconnect_mutex_);
DISALLOW_COPY_AND_ASSIGN(ReconnectHandler);
};
@@ -145,8 +147,8 @@
// Drain the queue to free all resources.
std::lock_guard<std::mutex> lock(reconnect_mutex_);
while (!reconnect_queue_.empty()) {
- ReconnectAttempt attempt = reconnect_queue_.top();
- reconnect_queue_.pop();
+ ReconnectAttempt attempt = *reconnect_queue_.begin();
+ reconnect_queue_.erase(reconnect_queue_.begin());
remove_transport(attempt.transport);
}
}
@@ -176,7 +178,7 @@
// system_clock as its clock, so we're probably hosed if the clock changes,
// even if we use steady_clock throughout. This problem goes away once we
// switch to libc++.
- reconnect_cv_.wait_until(lock, reconnect_queue_.top().reconnect_time);
+ reconnect_cv_.wait_until(lock, reconnect_queue_.begin()->reconnect_time);
} else {
reconnect_cv_.wait(lock);
}
@@ -187,12 +189,12 @@
// Go back to sleep in case |reconnect_cv_| woke up spuriously and we still
// have more time to wait for the current attempt.
auto now = std::chrono::steady_clock::now();
- if (reconnect_queue_.top().reconnect_time > now) {
+ if (reconnect_queue_.begin()->reconnect_time > now) {
continue;
}
- attempt = reconnect_queue_.top();
- reconnect_queue_.pop();
+ attempt = *reconnect_queue_.begin();
+ reconnect_queue_.erase(reconnect_queue_.begin());
if (attempt.transport->kicked()) {
D("transport %s was kicked. giving up on it.", attempt.transport->serial.c_str());
remove_transport(attempt.transport);
@@ -1190,43 +1192,40 @@
}
#endif // ADB_HOST
-int register_socket_transport(unique_fd s, const char* serial, int port, int local,
- atransport::ReconnectCallback reconnect) {
+bool register_socket_transport(unique_fd s, std::string serial, int port, int local,
+ atransport::ReconnectCallback reconnect, int* error) {
atransport* t = new atransport(std::move(reconnect), kCsOffline);
- if (!serial) {
- char buf[32];
- snprintf(buf, sizeof(buf), "T-%p", t);
- serial = buf;
- }
-
- D("transport: %s init'ing for socket %d, on port %d", serial, s.get(), port);
+ D("transport: %s init'ing for socket %d, on port %d", serial.c_str(), s.get(), port);
if (init_socket_transport(t, std::move(s), port, local) < 0) {
delete t;
- return -1;
+ if (error) *error = errno;
+ return false;
}
std::unique_lock<std::recursive_mutex> lock(transport_lock);
for (const auto& transport : pending_list) {
- if (strcmp(serial, transport->serial.c_str()) == 0) {
+ if (serial == transport->serial) {
VLOG(TRANSPORT) << "socket transport " << transport->serial
<< " is already in pending_list and fails to register";
delete t;
- return -EALREADY;
+ if (error) *error = EALREADY;
+ return false;
}
}
for (const auto& transport : transport_list) {
- if (strcmp(serial, transport->serial.c_str()) == 0) {
+ if (serial == transport->serial) {
VLOG(TRANSPORT) << "socket transport " << transport->serial
<< " is already in transport_list and fails to register";
delete t;
- return -EALREADY;
+ if (error) *error = EALREADY;
+ return false;
}
}
+ t->serial = std::move(serial);
pending_list.push_front(t);
- t->serial = serial;
lock.unlock();
@@ -1235,10 +1234,20 @@
if (local == 1) {
// Do not wait for emulator transports.
- return 0;
+ return true;
}
- return waitable->WaitForConnection(std::chrono::seconds(10)) ? 0 : -1;
+ if (!waitable->WaitForConnection(std::chrono::seconds(10))) {
+ if (error) *error = ETIMEDOUT;
+ return false;
+ }
+
+ if (t->GetConnectionState() == kCsUnauthorized) {
+ if (error) *error = EPERM;
+ return false;
+ }
+
+ return true;
}
#if ADB_HOST
diff --git a/adb/transport.h b/adb/transport.h
index 1844ae8..f362f24 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -364,8 +364,8 @@
void connect_device(const std::string& address, std::string* response);
/* cause new transports to be init'd and added to the list */
-int register_socket_transport(unique_fd s, const char* serial, int port, int local,
- atransport::ReconnectCallback reconnect);
+bool register_socket_transport(unique_fd s, std::string serial, int port, int local,
+ atransport::ReconnectCallback reconnect, int* error = nullptr);
// This should only be used for transports with connection_state == kCsNoPerm.
void unregister_usb_transport(usb_handle* usb);
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 9398ceb..1431252 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -125,11 +125,12 @@
return init_socket_transport(t, std::move(fd), port, 0) >= 0;
};
- int ret =
- register_socket_transport(std::move(fd), serial.c_str(), port, 0, std::move(reconnect));
- if (ret < 0) {
- if (ret == -EALREADY) {
+ int error;
+ if (!register_socket_transport(std::move(fd), serial, port, 0, std::move(reconnect), &error)) {
+ if (error == EALREADY) {
*response = android::base::StringPrintf("already connected to %s", serial.c_str());
+ } else if (error == EPERM) {
+ *response = android::base::StringPrintf("failed to authenticate to %s", serial.c_str());
} else {
*response = android::base::StringPrintf("failed to connect to %s", serial.c_str());
}
@@ -162,8 +163,8 @@
close_on_exec(fd.get());
disable_tcp_nagle(fd.get());
std::string serial = getEmulatorSerialString(console_port);
- if (register_socket_transport(std::move(fd), serial.c_str(), adb_port, 1,
- [](atransport*) { return false; }) == 0) {
+ if (register_socket_transport(std::move(fd), std::move(serial), adb_port, 1,
+ [](atransport*) { return false; })) {
return 0;
}
}
@@ -265,7 +266,7 @@
close_on_exec(fd.get());
disable_tcp_nagle(fd.get());
std::string serial = android::base::StringPrintf("host-%d", fd.get());
- register_socket_transport(std::move(fd), serial.c_str(), port, 1,
+ register_socket_transport(std::move(fd), std::move(serial), port, 1,
[](atransport*) { return false; });
}
}
@@ -362,7 +363,7 @@
* 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), serial.c_str(), port, 1,
+ register_socket_transport(std::move(fd), std::move(serial), port, 1,
[](atransport*) { return false; });
}
@@ -454,10 +455,6 @@
return it->second;
}
-std::string getEmulatorSerialString(int console_port) {
- return android::base::StringPrintf("emulator-%d", console_port);
-}
-
atransport* find_emulator_transport_by_adb_port(int adb_port) {
std::lock_guard<std::mutex> lock(local_transports_lock);
return find_emulator_transport_by_adb_port_locked(adb_port);
@@ -468,6 +465,10 @@
}
#endif
+std::string getEmulatorSerialString(int console_port) {
+ return android::base::StringPrintf("emulator-%d", console_port);
+}
+
int init_socket_transport(atransport* t, unique_fd fd, int adb_port, int local) {
int fail = 0;
diff --git a/adf/libadf/Android.bp b/adf/libadf/Android.bp
index 8eef2ea..49e3721 100644
--- a/adf/libadf/Android.bp
+++ b/adf/libadf/Android.bp
@@ -14,6 +14,7 @@
cc_library {
name: "libadf",
+ recovery_available: true,
vendor_available: true,
vndk: {
enabled: true,
diff --git a/adf/libadf/adf.cpp b/adf/libadf/adf.cpp
index 60d8ef0..fd9c208 100644
--- a/adf/libadf/adf.cpp
+++ b/adf/libadf/adf.cpp
@@ -132,8 +132,11 @@
void adf_free_device_data(struct adf_device_data *data)
{
delete [] data->attachments;
+ data->attachments = nullptr;
delete [] data->allowed_attachments;
+ data->allowed_attachments = nullptr;
delete [] static_cast<char *>(data->custom_data);
+ data->custom_data = nullptr;
}
int adf_device_post(struct adf_device *dev,
@@ -236,9 +239,10 @@
return err;
std::vector<adf_id_t> ids;
- for (size_t i = 0; i < data.n_allowed_attachments; i++)
- if (data.allowed_attachments[i].overlay_engine == overlay_engine)
- ids.push_back(data.allowed_attachments[i].interface);
+ if (data.allowed_attachments != nullptr)
+ for (size_t i = 0; i < data.n_allowed_attachments; i++)
+ if (data.allowed_attachments[i].overlay_engine == overlay_engine)
+ ids.push_back(data.allowed_attachments[i].interface);
adf_free_device_data(&data);
return adf_id_vector_to_array(ids, interfaces);
@@ -450,9 +454,10 @@
return err;
std::vector<adf_id_t> ids;
- for (size_t i = 0; i < data.n_allowed_attachments; i++)
- if (data.allowed_attachments[i].interface == interface)
- ids.push_back(data.allowed_attachments[i].overlay_engine);
+ if (data.allowed_attachments != nullptr)
+ for (size_t i = 0; i < data.n_allowed_attachments; i++)
+ if (data.allowed_attachments[i].interface == interface)
+ ids.push_back(data.allowed_attachments[i].overlay_engine);
return adf_id_vector_to_array(ids, overlay_engines);
}
@@ -551,7 +556,9 @@
void adf_free_overlay_engine_data(struct adf_overlay_engine_data *data)
{
delete [] data->supported_formats;
+ data->supported_formats = nullptr;
delete [] static_cast<char *>(data->custom_data);
+ data->custom_data = nullptr;
}
bool adf_overlay_engine_supports_format(int fd, __u32 format)
@@ -564,10 +571,12 @@
if (err < 0)
return false;
- for (i = 0; i < data.n_supported_formats; i++) {
- if (data.supported_formats[i] == format) {
- ret = true;
- break;
+ if (data.supported_formats != nullptr) {
+ for (i = 0; i < data.n_supported_formats; i++) {
+ if (data.supported_formats[i] == format) {
+ ret = true;
+ break;
+ }
}
}
@@ -638,18 +647,18 @@
const __u32 *formats, size_t n_formats,
adf_id_t interface, adf_id_t *overlay_engine)
{
- adf_id_t *engs;
+ adf_id_t *engs = nullptr;
ssize_t n_engs = adf_overlay_engines_for_interface(dev, interface, &engs);
- if (n_engs <= 0)
+ if (engs == nullptr)
return false;
- adf_id_t *filtered_engs;
+ adf_id_t *filtered_engs = nullptr;
ssize_t n_filtered_engs = adf_overlay_engines_filter_by_format(dev,
formats, n_formats, engs, n_engs, &filtered_engs);
free(engs);
- if (n_filtered_engs <= 0)
+ if (filtered_engs == nullptr)
return false;
*overlay_engine = filtered_engs[0];
@@ -700,17 +709,17 @@
if (n_intfs < 0)
return n_intfs;
- else if (!n_intfs)
+ else if (!intfs)
return -ENODEV;
- adf_id_t *primary_intfs;
+ adf_id_t *primary_intfs = nullptr;
ssize_t n_primary_intfs = adf_interfaces_filter_by_flag(dev,
ADF_INTF_FLAG_PRIMARY, intfs, n_intfs, &primary_intfs);
free(intfs);
if (n_primary_intfs < 0)
return n_primary_intfs;
- else if (!n_primary_intfs)
+ else if (!primary_intfs)
return -ENODEV;
if (!formats) {
diff --git a/base/Android.bp b/base/Android.bp
index 46a0233..3d80d97 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -135,7 +135,6 @@
"strings_test.cpp",
"test_main.cpp",
"test_utils_test.cpp",
- "unique_fd_test.cpp",
],
target: {
android: {
diff --git a/base/include/android-base/parsedouble.h b/base/include/android-base/parsedouble.h
index c273c61..ccffba2 100644
--- a/base/include/android-base/parsedouble.h
+++ b/base/include/android-base/parsedouble.h
@@ -20,28 +20,58 @@
#include <stdlib.h>
#include <limits>
+#include <string>
namespace android {
namespace base {
-// Parse double value in the string 's' and sets 'out' to that value.
+// Parse floating value in the string 's' and sets 'out' to that value if it exists.
// Optionally allows the caller to define a 'min' and 'max' beyond which
// otherwise valid values will be rejected. Returns boolean success.
-static inline bool ParseDouble(const char* s, double* out,
- double min = std::numeric_limits<double>::lowest(),
- double max = std::numeric_limits<double>::max()) {
+template <typename T, T (*strtox)(const char* str, char** endptr)>
+static inline bool ParseFloatingPoint(const char* s, T* out, T min, T max) {
errno = 0;
char* end;
- double result = strtod(s, &end);
+ T result = strtox(s, &end);
if (errno != 0 || s == end || *end != '\0') {
return false;
}
if (result < min || max < result) {
return false;
}
- *out = result;
+ if (out != nullptr) {
+ *out = result;
+ }
return true;
}
+// Parse double value in the string 's' and sets 'out' to that value if it exists.
+// Optionally allows the caller to define a 'min' and 'max' beyond which
+// otherwise valid values will be rejected. Returns boolean success.
+static inline bool ParseDouble(const char* s, double* out,
+ double min = std::numeric_limits<double>::lowest(),
+ double max = std::numeric_limits<double>::max()) {
+ return ParseFloatingPoint<double, strtod>(s, out, min, max);
+}
+static inline bool ParseDouble(const std::string& s, double* out,
+ double min = std::numeric_limits<double>::lowest(),
+ double max = std::numeric_limits<double>::max()) {
+ return ParseFloatingPoint<double, strtod>(s.c_str(), out, min, max);
+}
+
+// Parse float value in the string 's' and sets 'out' to that value if it exists.
+// Optionally allows the caller to define a 'min' and 'max' beyond which
+// otherwise valid values will be rejected. Returns boolean success.
+static inline bool ParseFloat(const char* s, float* out,
+ float min = std::numeric_limits<float>::lowest(),
+ float max = std::numeric_limits<float>::max()) {
+ return ParseFloatingPoint<float, strtof>(s, out, min, max);
+}
+static inline bool ParseFloat(const std::string& s, float* out,
+ float min = std::numeric_limits<float>::lowest(),
+ float max = std::numeric_limits<float>::max()) {
+ return ParseFloatingPoint<float, strtof>(s.c_str(), out, min, max);
+}
+
} // namespace base
} // namespace android
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index bb54c99..55f1ed3 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -27,9 +27,9 @@
namespace base {
// Parses the unsigned decimal or hexadecimal integer in the string 's' and sets
-// 'out' to that value. Optionally allows the caller to define a 'max' beyond
-// which otherwise valid values will be rejected. Returns boolean success; 'out'
-// is untouched if parsing fails.
+// 'out' to that value if it is specified. Optionally allows the caller to define
+// a 'max' beyond which otherwise valid values will be rejected. Returns boolean
+// success; 'out' is untouched if parsing fails.
template <typename T>
bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
bool allow_suffixes = false) {
@@ -72,9 +72,9 @@
}
// Parses the signed decimal or hexadecimal integer in the string 's' and sets
-// 'out' to that value. Optionally allows the caller to define a 'min' and 'max'
-// beyond which otherwise valid values will be rejected. Returns boolean
-// success; 'out' is untouched if parsing fails.
+// 'out' to that value if it is specified. Optionally allows the caller to define
+// a 'min' and 'max' beyond which otherwise valid values will be rejected. Returns
+// boolean success; 'out' is untouched if parsing fails.
template <typename T>
bool ParseInt(const char* s, T* out,
T min = std::numeric_limits<T>::min(),
diff --git a/base/include/android-base/utf8.h b/base/include/android-base/utf8.h
old mode 100755
new mode 100644
diff --git a/base/parsedouble_test.cpp b/base/parsedouble_test.cpp
index 8734c42..ec3c10c 100644
--- a/base/parsedouble_test.cpp
+++ b/base/parsedouble_test.cpp
@@ -18,7 +18,7 @@
#include <gtest/gtest.h>
-TEST(parsedouble, smoke) {
+TEST(parsedouble, double_smoke) {
double d;
ASSERT_FALSE(android::base::ParseDouble("", &d));
ASSERT_FALSE(android::base::ParseDouble("x", &d));
@@ -35,4 +35,33 @@
ASSERT_FALSE(android::base::ParseDouble("3.0", &d, -1.0, 2.0));
ASSERT_TRUE(android::base::ParseDouble("1.0", &d, 0.0, 2.0));
ASSERT_DOUBLE_EQ(1.0, d);
+
+ ASSERT_FALSE(android::base::ParseDouble("123.4x", nullptr));
+ ASSERT_TRUE(android::base::ParseDouble("-123.4", nullptr));
+ ASSERT_FALSE(android::base::ParseDouble("3.0", nullptr, -1.0, 2.0));
+ ASSERT_TRUE(android::base::ParseDouble("1.0", nullptr, 0.0, 2.0));
+}
+
+TEST(parsedouble, float_smoke) {
+ float f;
+ ASSERT_FALSE(android::base::ParseFloat("", &f));
+ ASSERT_FALSE(android::base::ParseFloat("x", &f));
+ ASSERT_FALSE(android::base::ParseFloat("123.4x", &f));
+
+ ASSERT_TRUE(android::base::ParseFloat("123.4", &f));
+ ASSERT_FLOAT_EQ(123.4, f);
+ ASSERT_TRUE(android::base::ParseFloat("-123.4", &f));
+ ASSERT_FLOAT_EQ(-123.4, f);
+
+ ASSERT_TRUE(android::base::ParseFloat("0", &f, 0.0));
+ ASSERT_FLOAT_EQ(0.0, f);
+ ASSERT_FALSE(android::base::ParseFloat("0", &f, 1e-9));
+ ASSERT_FALSE(android::base::ParseFloat("3.0", &f, -1.0, 2.0));
+ ASSERT_TRUE(android::base::ParseFloat("1.0", &f, 0.0, 2.0));
+ ASSERT_FLOAT_EQ(1.0, f);
+
+ ASSERT_FALSE(android::base::ParseFloat("123.4x", nullptr));
+ ASSERT_TRUE(android::base::ParseFloat("-123.4", nullptr));
+ ASSERT_FALSE(android::base::ParseFloat("3.0", nullptr, -1.0, 2.0));
+ ASSERT_TRUE(android::base::ParseFloat("1.0", nullptr, 0.0, 2.0));
}
diff --git a/base/unique_fd_test.cpp b/base/unique_fd_test.cpp
deleted file mode 100644
index 3fdf12a..0000000
--- a/base/unique_fd_test.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.
- */
-
-#include "android-base/unique_fd.h"
-
-#include <gtest/gtest.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-using android::base::unique_fd;
-
-TEST(unique_fd, unowned_close) {
-#if defined(__BIONIC__)
- unique_fd fd(open("/dev/null", O_RDONLY));
- EXPECT_DEATH(close(fd.get()), "incorrect tag");
-#endif
-}
-
-TEST(unique_fd, untag_on_release) {
- unique_fd fd(open("/dev/null", O_RDONLY));
- close(fd.release());
-}
-
-TEST(unique_fd, move) {
- unique_fd fd(open("/dev/null", O_RDONLY));
- unique_fd fd_moved = std::move(fd);
- ASSERT_EQ(-1, fd.get());
- ASSERT_GT(fd_moved.get(), -1);
-}
-
-TEST(unique_fd, unowned_close_after_move) {
-#if defined(__BIONIC__)
- unique_fd fd(open("/dev/null", O_RDONLY));
- unique_fd fd_moved = std::move(fd);
- ASSERT_EQ(-1, fd.get());
- ASSERT_GT(fd_moved.get(), -1);
- EXPECT_DEATH(close(fd_moved.get()), "incorrect tag");
-#endif
-}
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index 8fc2171..5e2d171 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -63,6 +63,9 @@
name: "bootstat",
defaults: ["bootstat_defaults"],
static_libs: ["libbootstat"],
+ shared_libs: [
+ "libstatslog"
+ ],
init_rc: ["bootstat.rc"],
product_variables: {
pdk: {
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 4d9f1ac..c17e00f 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -45,6 +45,7 @@
#include <cutils/android_reboot.h>
#include <cutils/properties.h>
#include <metricslogger/metrics_logger.h>
+#include <statslog.h>
#include "boot_event_record_store.h"
@@ -185,7 +186,7 @@
{"wdog_bark", 42},
{"wdog_bite", 43},
{"wdog_reset", 44},
- {"shutdown,", 45}, // Trailing comma is intentional.
+ {"shutdown,", 45}, // Trailing comma is intentional. Do NOT use.
{"shutdown,userrequested", 46},
{"reboot,bootloader", 47},
{"reboot,cold", 48},
@@ -261,8 +262,8 @@
{"oem_rpm_undef_error", 116},
{"oem_crash_on_the_lk", 117},
{"oem_rpm_reset", 118},
- {"oem_lpass_cfg", 119},
- {"oem_xpu_ns_error", 120},
+ {"REUSE1", 119}, // Former dupe, can be re-used
+ {"REUSE2", 120}, // Former dupe, can be re-used
{"factory_cable", 121},
{"oem_ar6320_failed_to_powerup", 122},
{"watchdog_rpm_bite", 123},
@@ -1026,6 +1027,16 @@
return timings;
}
+// Returns the total bootloader boot time from the ro.boot.boottime system property.
+int32_t GetBootloaderTime(const BootloaderTimingMap& bootloader_timings) {
+ int32_t total_time = 0;
+ for (const auto& timing : bootloader_timings) {
+ total_time += timing.second;
+ }
+
+ return total_time;
+}
+
// Parses and records the set of bootloader stages and associated boot times
// from the ro.boot.boottime system property.
void RecordBootloaderTimings(BootEventRecordStore* boot_event_store,
@@ -1039,11 +1050,10 @@
boot_event_store->AddBootEventWithValue("boottime.bootloader.total", total_time);
}
-// Records the closest estimation to the absolute device boot time, i.e.,
+// Returns the closest estimation to the absolute device boot time, i.e.,
// from power on to boot_complete, including bootloader times.
-void RecordAbsoluteBootTime(BootEventRecordStore* boot_event_store,
- const BootloaderTimingMap& bootloader_timings,
- std::chrono::milliseconds uptime) {
+std::chrono::milliseconds GetAbsoluteBootTime(const BootloaderTimingMap& bootloader_timings,
+ std::chrono::milliseconds uptime) {
int32_t bootloader_time_ms = 0;
for (const auto& timing : bootloader_timings) {
@@ -1053,23 +1063,36 @@
}
auto bootloader_duration = std::chrono::milliseconds(bootloader_time_ms);
- auto absolute_total =
- std::chrono::duration_cast<std::chrono::seconds>(bootloader_duration + uptime);
- boot_event_store->AddBootEventWithValue("absolute_boot_time", absolute_total.count());
+ return bootloader_duration + uptime;
}
-// Gets the boot time offset. This is useful when Android is running in a
-// container, because the boot_clock is not reset when Android reboots.
-std::chrono::nanoseconds GetBootTimeOffset() {
- static const int64_t boottime_offset =
- android::base::GetIntProperty<int64_t>("ro.boot.boottime_offset", 0);
- return std::chrono::nanoseconds(boottime_offset);
+// Records the closest estimation to the absolute device boot time in seconds.
+// i.e. from power on to boot_complete, including bootloader times.
+void RecordAbsoluteBootTime(BootEventRecordStore* boot_event_store,
+ std::chrono::milliseconds absolute_total) {
+ auto absolute_total_sec = std::chrono::duration_cast<std::chrono::seconds>(absolute_total);
+ boot_event_store->AddBootEventWithValue("absolute_boot_time", absolute_total_sec.count());
}
-// Returns the current uptime, accounting for any offset in the CLOCK_BOOTTIME
-// clock.
-android::base::boot_clock::duration GetUptime() {
- return android::base::boot_clock::now().time_since_epoch() - GetBootTimeOffset();
+// Logs the total boot time and reason to statsd.
+void LogBootInfoToStatsd(std::chrono::milliseconds end_time,
+ std::chrono::milliseconds total_duration, int32_t bootloader_duration_ms,
+ double time_since_last_boot_sec) {
+ const std::string reason(GetProperty(bootloader_reboot_reason_property));
+
+ if (reason.empty()) {
+ android::util::stats_write(android::util::BOOT_SEQUENCE_REPORTED, "<EMPTY>", "<EMPTY>",
+ end_time.count(), total_duration.count(),
+ (int64_t)bootloader_duration_ms,
+ (int64_t)time_since_last_boot_sec * 1000);
+ return;
+ }
+
+ const std::string system_reason(GetProperty(system_reboot_reason_property));
+ android::util::stats_write(android::util::BOOT_SEQUENCE_REPORTED, reason.c_str(),
+ system_reason.c_str(), end_time.count(), total_duration.count(),
+ (int64_t)bootloader_duration_ms,
+ (int64_t)time_since_last_boot_sec * 1000);
}
void SetSystemBootReason() {
@@ -1088,6 +1111,20 @@
SetProperty(last_reboot_reason_property, "");
}
+// Gets the boot time offset. This is useful when Android is running in a
+// container, because the boot_clock is not reset when Android reboots.
+std::chrono::nanoseconds GetBootTimeOffset() {
+ static const int64_t boottime_offset =
+ android::base::GetIntProperty<int64_t>("ro.boot.boottime_offset", 0);
+ return std::chrono::nanoseconds(boottime_offset);
+}
+
+// Returns the current uptime, accounting for any offset in the CLOCK_BOOTTIME
+// clock.
+android::base::boot_clock::duration GetUptime() {
+ return android::base::boot_clock::now().time_since_epoch() - GetBootTimeOffset();
+}
+
// Records several metrics related to the time it takes to boot the device,
// including disambiguating boot time on encrypted or non-encrypted devices.
void RecordBootComplete() {
@@ -1097,10 +1134,11 @@
auto uptime_ns = GetUptime();
auto uptime_s = std::chrono::duration_cast<std::chrono::seconds>(uptime_ns);
time_t current_time_utc = time(nullptr);
+ time_t time_since_last_boot = 0;
if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
time_t last_boot_time_utc = record.second;
- time_t time_since_last_boot = difftime(current_time_utc, last_boot_time_utc);
+ time_since_last_boot = difftime(current_time_utc, last_boot_time_utc);
boot_event_store.AddBootEventWithValue("time_since_last_boot", time_since_last_boot);
}
@@ -1140,10 +1178,18 @@
RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.cold_boot_wait");
const BootloaderTimingMap bootloader_timings = GetBootLoaderTimings();
+ int32_t bootloader_boot_duration = GetBootloaderTime(bootloader_timings);
RecordBootloaderTimings(&boot_event_store, bootloader_timings);
auto uptime_ms = std::chrono::duration_cast<std::chrono::milliseconds>(uptime_ns);
- RecordAbsoluteBootTime(&boot_event_store, bootloader_timings, uptime_ms);
+ auto absolute_boot_time = GetAbsoluteBootTime(bootloader_timings, uptime_ms);
+ RecordAbsoluteBootTime(&boot_event_store, absolute_boot_time);
+
+ auto boot_end_time_point = std::chrono::system_clock::now().time_since_epoch();
+ auto boot_end_time = std::chrono::duration_cast<std::chrono::milliseconds>(boot_end_time_point);
+
+ LogBootInfoToStatsd(boot_end_time, absolute_boot_time, bootloader_boot_duration,
+ time_since_last_boot);
}
// Records the boot_reason metric by querying the ro.boot.bootreason system
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 1b20157..03b3287 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -43,7 +43,7 @@
export_include_dirs: ["tombstoned/include"],
}
-// Utility library to tombstoned and get an output fd.
+// Utility library to talk to tombstoned and get an output fd.
cc_library_static {
name: "libtombstoned_client_static",
defaults: ["debuggerd_defaults"],
@@ -166,6 +166,9 @@
local_include_dirs: ["libdebuggerd/include"],
export_include_dirs: ["libdebuggerd/include"],
+ // Needed for private/bionic_fdsan.h
+ include_dirs: ["bionic/libc"],
+
static_libs: [
"libbacktrace",
"libunwindstack",
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 40cf6c3..93f7572 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -249,24 +249,48 @@
}
static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
- std::unique_ptr<unwindstack::Regs>* regs, uintptr_t* abort_address) {
+ std::unique_ptr<unwindstack::Regs>* regs, uintptr_t* abort_msg_address,
+ uintptr_t* fdsan_table_address) {
std::aligned_storage<sizeof(CrashInfo) + 1, alignof(CrashInfo)>::type buf;
+ CrashInfo* crash_info = reinterpret_cast<CrashInfo*>(&buf);
ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &buf, sizeof(buf)));
if (rc == -1) {
PLOG(FATAL) << "failed to read target ucontext";
- } else if (rc != sizeof(CrashInfo)) {
- LOG(FATAL) << "read " << rc << " bytes when reading target crash information, expected "
- << sizeof(CrashInfo);
+ } else {
+ ssize_t expected_size = 0;
+ switch (crash_info->header.version) {
+ case 1:
+ expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV1);
+ break;
+
+ case 2:
+ expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2);
+ break;
+
+ default:
+ LOG(FATAL) << "unexpected CrashInfo version: " << crash_info->header.version;
+ break;
+ };
+
+ if (rc != expected_size) {
+ LOG(FATAL) << "read " << rc << " bytes when reading target crash information, expected "
+ << expected_size;
+ }
}
- CrashInfo* crash_info = reinterpret_cast<CrashInfo*>(&buf);
- if (crash_info->version != 1) {
- LOG(FATAL) << "version mismatch, expected 1, received " << crash_info->version;
- }
+ *fdsan_table_address = 0;
+ switch (crash_info->header.version) {
+ case 2:
+ *fdsan_table_address = crash_info->data.v2.fdsan_table_address;
+ case 1:
+ *abort_msg_address = crash_info->data.v1.abort_msg_address;
+ *siginfo = crash_info->data.v1.siginfo;
+ regs->reset(Regs::CreateFromUcontext(Regs::CurrentArch(), &crash_info->data.v1.ucontext));
+ break;
- *siginfo = crash_info->siginfo;
- regs->reset(Regs::CreateFromUcontext(Regs::CurrentArch(), &crash_info->ucontext));
- *abort_address = crash_info->abort_msg_address;
+ default:
+ __builtin_unreachable();
+ }
}
// Wait for a process to clone and return the child's pid.
@@ -369,7 +393,8 @@
ATRACE_NAME("after reparent");
pid_t pseudothread_tid;
DebuggerdDumpType dump_type;
- uintptr_t abort_address = 0;
+ uintptr_t abort_msg_address = 0;
+ uintptr_t fdsan_table_address = 0;
Initialize(argv);
ParseArgs(argc, argv, &pseudothread_tid, &dump_type);
@@ -387,7 +412,7 @@
OpenFilesList open_files;
{
ATRACE_NAME("open files");
- populate_open_files_list(g_target_thread, &open_files);
+ populate_open_files_list(&open_files, g_target_thread);
}
// In order to reduce the duration that we pause the process for, we ptrace
@@ -429,7 +454,8 @@
if (thread == g_target_thread) {
// Read the thread's registers along with the rest of the crash info out of the pipe.
- ReadCrashInfo(input_pipe, &siginfo, &info.registers, &abort_address);
+ ReadCrashInfo(input_pipe, &siginfo, &info.registers, &abort_msg_address,
+ &fdsan_table_address);
info.siginfo = &siginfo;
info.signo = info.siginfo->si_signo;
} else {
@@ -504,8 +530,8 @@
g_output_fd = std::move(devnull);
}
- LOG(INFO) << "performing dump of process " << target_process << " (target tid = " << g_target_thread
- << ")";
+ LOG(INFO) << "performing dump of process " << target_process
+ << " (target tid = " << g_target_thread << ")";
int signo = siginfo.si_signo;
bool fatal_signal = signo != DEBUGGER_SIGNAL;
@@ -541,9 +567,16 @@
ATRACE_NAME("dump_backtrace");
dump_backtrace(std::move(g_output_fd), map.get(), thread_info, g_target_thread);
} else {
- ATRACE_NAME("engrave_tombstone");
- engrave_tombstone(std::move(g_output_fd), map.get(), process_memory.get(), thread_info,
- g_target_thread, abort_address, &open_files, &amfd_data);
+ {
+ ATRACE_NAME("fdsan table dump");
+ populate_fdsan_table(&open_files, process_memory, fdsan_table_address);
+ }
+
+ {
+ ATRACE_NAME("engrave_tombstone");
+ engrave_tombstone(std::move(g_output_fd), map.get(), process_memory.get(), thread_info,
+ g_target_thread, abort_msg_address, &open_files, &amfd_data);
+ }
}
if (fatal_signal) {
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 615fb46..91e6f71 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -108,6 +108,7 @@
int saved_errno_;
};
+extern "C" void* android_fdsan_get_fd_table();
extern "C" void debuggerd_fallback_handler(siginfo_t*, ucontext_t*, void*);
static debuggerd_callbacks_t g_callbacks;
@@ -286,6 +287,7 @@
siginfo_t* siginfo;
void* ucontext;
uintptr_t abort_msg;
+ uintptr_t fdsan_table;
};
// Logging and contacting debuggerd requires free file descriptors, which we might not have.
@@ -330,23 +332,23 @@
}
// ucontext_t is absurdly large on AArch64, so piece it together manually with writev.
- uint32_t version = 1;
- constexpr size_t expected =
- sizeof(version) + sizeof(siginfo_t) + sizeof(ucontext_t) + sizeof(uintptr_t);
+ uint32_t version = 2;
+ constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2);
errno = 0;
if (fcntl(output_write.get(), F_SETPIPE_SZ, expected) < static_cast<int>(expected)) {
- fatal_errno("failed to set pipe bufer size");
+ fatal_errno("failed to set pipe buffer size");
}
- struct iovec iovs[4] = {
+ struct iovec iovs[5] = {
{.iov_base = &version, .iov_len = sizeof(version)},
{.iov_base = thread_info->siginfo, .iov_len = sizeof(siginfo_t)},
{.iov_base = thread_info->ucontext, .iov_len = sizeof(ucontext_t)},
{.iov_base = &thread_info->abort_msg, .iov_len = sizeof(uintptr_t)},
+ {.iov_base = &thread_info->fdsan_table, .iov_len = sizeof(uintptr_t)},
};
- ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, 4));
+ ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, 5));
if (rc == -1) {
fatal_errno("failed to write crash info");
} else if (rc != expected) {
@@ -504,6 +506,7 @@
.siginfo = info,
.ucontext = context,
.abort_msg = reinterpret_cast<uintptr_t>(abort_message),
+ .fdsan_table = reinterpret_cast<uintptr_t>(android_fdsan_get_fd_table()),
};
// Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us.
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h b/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h
index 4727ca4..d47f2dd 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h
@@ -14,23 +14,31 @@
* limitations under the License.
*/
-#ifndef _DEBUGGERD_OPEN_FILES_LIST_H
-#define _DEBUGGERD_OPEN_FILES_LIST_H
+#pragma once
+#include <stdint.h>
#include <sys/types.h>
+#include <map>
+#include <optional>
#include <string>
#include <utility>
-#include <vector>
#include "utility.h"
-typedef std::vector<std::pair<int, std::string>> OpenFilesList;
+struct FDInfo {
+ std::optional<std::string> path;
+ std::optional<uint64_t> fdsan_owner;
+};
-/* Populates the given list with open files for the given process. */
-void populate_open_files_list(pid_t pid, OpenFilesList* list);
+using OpenFilesList = std::map<int, FDInfo>;
-/* Dumps the open files list to the log. */
+// Populates the given list with open files for the given process.
+void populate_open_files_list(OpenFilesList* list, pid_t pid);
+
+// Populates the given list with the target process's fdsan table.
+void populate_fdsan_table(OpenFilesList* list, std::shared_ptr<unwindstack::Memory> memory,
+ uint64_t fdsan_table_address);
+
+// Dumps the open files list to the log.
void dump_open_files_list(log_t* log, const OpenFilesList& files, const char* prefix);
-
-#endif // _DEBUGGERD_OPEN_FILES_LIST_H
diff --git a/debuggerd/libdebuggerd/open_files_list.cpp b/debuggerd/libdebuggerd/open_files_list.cpp
index b12703e..1fdf236 100644
--- a/debuggerd/libdebuggerd/open_files_list.cpp
+++ b/debuggerd/libdebuggerd/open_files_list.cpp
@@ -32,10 +32,12 @@
#include <android-base/file.h>
#include <log/log.h>
+#include <unwindstack/Memory.h>
#include "libdebuggerd/utility.h"
+#include "private/bionic_fdsan.h"
-void populate_open_files_list(pid_t pid, OpenFilesList* list) {
+void populate_open_files_list(OpenFilesList* list, pid_t pid) {
std::string fd_dir_name = "/proc/" + std::to_string(pid) + "/fd";
std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(fd_dir_name.c_str()), closedir);
if (dir == nullptr) {
@@ -53,17 +55,84 @@
std::string path = fd_dir_name + "/" + std::string(de->d_name);
std::string target;
if (android::base::Readlink(path, &target)) {
- list->emplace_back(fd, target);
+ (*list)[fd].path = target;
} else {
+ (*list)[fd].path = "???";
ALOGE("failed to readlink %s: %s", path.c_str(), strerror(errno));
- list->emplace_back(fd, "???");
}
}
}
+void populate_fdsan_table(OpenFilesList* list, std::shared_ptr<unwindstack::Memory> memory,
+ uint64_t fdsan_table_address) {
+ constexpr size_t inline_fds = sizeof(FdTable::entries) / sizeof(*FdTable::entries);
+ static_assert(inline_fds == 128);
+ size_t entry_offset = offsetof(FdTable, entries);
+ for (size_t i = 0; i < inline_fds; ++i) {
+ uint64_t address = fdsan_table_address + entry_offset + sizeof(FdEntry) * i;
+ FdEntry entry;
+ if (!memory->Read(address, &entry, sizeof(entry))) {
+ ALOGE("failed to read fdsan table entry %zu: %s", i, strerror(errno));
+ return;
+ }
+ ALOGE("fd %zu = %#" PRIx64, i, entry.close_tag.load());
+ if (entry.close_tag) {
+ (*list)[i].fdsan_owner = entry.close_tag.load();
+ }
+ }
+
+ size_t overflow_offset = offsetof(FdTable, overflow);
+ uintptr_t overflow = 0;
+ if (!memory->Read(fdsan_table_address + overflow_offset, &overflow, sizeof(overflow))) {
+ ALOGE("failed to read fdsan table overflow pointer: %s", strerror(errno));
+ return;
+ }
+
+ if (!overflow) {
+ return;
+ }
+
+ size_t overflow_length;
+ if (!memory->Read(overflow, &overflow_length, sizeof(overflow_length))) {
+ ALOGE("failed to read fdsan overflow table length: %s", strerror(errno));
+ return;
+ }
+
+ if (overflow_length > 131072) {
+ ALOGE("unreasonable large fdsan overflow table size %zu, bailing out", overflow_length);
+ return;
+ }
+
+ for (size_t i = 0; i < overflow_length; ++i) {
+ int fd = i + inline_fds;
+ uint64_t address = overflow + offsetof(FdTableOverflow, entries) + i * sizeof(FdEntry);
+ FdEntry entry;
+ if (!memory->Read(address, &entry, sizeof(entry))) {
+ ALOGE("failed to read fdsan overflow entry for fd %d: %s", fd, strerror(errno));
+ return;
+ }
+ if (entry.close_tag) {
+ (*list)[fd].fdsan_owner = entry.close_tag;
+ }
+ }
+ return;
+}
+
void dump_open_files_list(log_t* log, const OpenFilesList& files, const char* prefix) {
- for (auto& file : files) {
- _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s\n", prefix, file.first, file.second.c_str());
+ for (auto& [fd, entry] : files) {
+ const std::optional<std::string>& path = entry.path;
+ const std::optional<uint64_t>& fdsan_owner = entry.fdsan_owner;
+ if (path && fdsan_owner) {
+ _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s (owned by %#" PRIx64 ")\n", prefix, fd,
+ path->c_str(), *fdsan_owner);
+ } else if (path && !fdsan_owner) {
+ _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s (unowned)\n", prefix, fd, path->c_str());
+ } else if (!path && fdsan_owner) {
+ _LOG(log, logtype::OPEN_FILES, "%sfd %i: <MISSING> (owned by %#" PRIx64 ")\n", prefix, fd,
+ *fdsan_owner);
+ } else {
+ ALOGE("OpenFilesList contains an entry (fd %d) with no path or owner", fd);
+ }
}
}
diff --git a/debuggerd/libdebuggerd/test/open_files_list_test.cpp b/debuggerd/libdebuggerd/test/open_files_list_test.cpp
index acac72c..d7036fd 100644
--- a/debuggerd/libdebuggerd/test/open_files_list_test.cpp
+++ b/debuggerd/libdebuggerd/test/open_files_list_test.cpp
@@ -34,13 +34,13 @@
// Get the list of open files for this process.
OpenFilesList list;
- populate_open_files_list(getpid(), &list);
+ populate_open_files_list(&list, getpid());
// Verify our open file is in the list.
bool found = false;
- for (auto& file : list) {
+ for (auto& file : list) {
if (file.first == tf.fd) {
- EXPECT_EQ(file.second, std::string(tf.path));
+ EXPECT_EQ(file.second.path.value_or(""), std::string(tf.path));
found = true;
break;
}
diff --git a/debuggerd/protocol.h b/debuggerd/protocol.h
index 6903b0e..bfd0fbb 100644
--- a/debuggerd/protocol.h
+++ b/debuggerd/protocol.h
@@ -81,9 +81,24 @@
};
// Sent from handler to crash_dump via pipe.
-struct __attribute__((__packed__)) CrashInfo {
- uint32_t version; // must be 1.
+struct __attribute__((__packed__)) CrashInfoHeader {
+ uint32_t version;
+};
+
+struct __attribute__((__packed__)) CrashInfoDataV1 {
siginfo_t siginfo;
ucontext_t ucontext;
uintptr_t abort_msg_address;
};
+
+struct __attribute__((__packed__)) CrashInfoDataV2 : public CrashInfoDataV1 {
+ uintptr_t fdsan_table_address;
+};
+
+struct __attribute__((__packed__)) CrashInfo {
+ CrashInfoHeader header;
+ union {
+ CrashInfoDataV1 v1;
+ CrashInfoDataV2 v2;
+ } data;
+};
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 2b4a954..3414d53 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -1,3 +1,17 @@
+// 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.
+
cc_library_host_static {
name: "libfastboot2",
@@ -54,3 +68,57 @@
export_include_dirs: ["."],
}
+
+cc_defaults {
+ name: "fastboot_defaults",
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wvla",
+ ],
+ rtti: true,
+
+ clang_cflags: [
+ "-Wthread-safety",
+ ],
+}
+
+cc_binary {
+ name: "fastbootd",
+ defaults: ["fastboot_defaults"],
+
+ recovery: true,
+
+ srcs: [
+ "device/commands.cpp",
+ "device/fastboot_device.cpp",
+ "device/flashing.cpp",
+ "device/main.cpp",
+ "device/usb_client.cpp",
+ "device/utility.cpp",
+ "device/variables.cpp",
+ ],
+
+ shared_libs: [
+ "android.hardware.boot@1.0",
+ "libadbd",
+ "libasyncio",
+ "libbase",
+ "libbootloader_message",
+ "libcutils",
+ "libext2_uuid",
+ "libext4_utils",
+ "libfs_mgr",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "liblp",
+ "libsparse",
+ "libutils",
+ ],
+
+ cpp_std: "c++17",
+}
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 5e7e955..43daab0 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -27,7 +27,12 @@
#define FB_CMD_REBOOT "reboot"
#define FB_CMD_SHUTDOWN "shutdown"
#define FB_CMD_REBOOT_BOOTLOADER "reboot-bootloader"
+#define FB_CMD_REBOOT_RECOVERY "reboot-recovery"
+#define FB_CMD_REBOOT_FASTBOOT "reboot-fastboot"
#define FB_CMD_POWERDOWN "powerdown"
+#define FB_CMD_CREATE_PARTITION "create-logical-partition"
+#define FB_CMD_DELETE_PARTITION "delete-logical-partition"
+#define FB_CMD_RESIZE_PARTITION "resize-logical-partition"
#define RESPONSE_OKAY "OKAY"
#define RESPONSE_FAIL "FAIL"
@@ -49,3 +54,7 @@
#define FB_VAR_HAS_SLOT "has-slot"
#define FB_VAR_SLOT_COUNT "slot-count"
#define FB_VAR_PARTITION_SIZE "partition-size"
+#define FB_VAR_SLOT_SUCCESSFUL "slot-successful"
+#define FB_VAR_SLOT_UNBOOTABLE "slot-unbootable"
+#define FB_VAR_IS_LOGICAL "is-logical"
+#define FB_VAR_IS_USERSPACE "is-userspace"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
new file mode 100644
index 0000000..690bfa8
--- /dev/null
+++ b/fastboot/device/commands.cpp
@@ -0,0 +1,338 @@
+/*
+ * 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.
+ */
+
+#include "commands.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/android_reboot.h>
+#include <ext4_utils/wipe.h>
+#include <liblp/builder.h>
+#include <liblp/liblp.h>
+#include <uuid/uuid.h>
+
+#include "constants.h"
+#include "fastboot_device.h"
+#include "flashing.h"
+#include "utility.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::boot::V1_0::BoolResult;
+using ::android::hardware::boot::V1_0::CommandResult;
+using ::android::hardware::boot::V1_0::Slot;
+using namespace android::fs_mgr;
+
+bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ using VariableHandler = std::function<bool(FastbootDevice*, const std::vector<std::string>&)>;
+ const std::unordered_map<std::string, VariableHandler> kVariableMap = {
+ {FB_VAR_VERSION, GetVersion},
+ {FB_VAR_VERSION_BOOTLOADER, GetBootloaderVersion},
+ {FB_VAR_VERSION_BASEBAND, GetBasebandVersion},
+ {FB_VAR_PRODUCT, GetProduct},
+ {FB_VAR_SERIALNO, GetSerial},
+ {FB_VAR_SECURE, GetSecure},
+ {FB_VAR_UNLOCKED, GetUnlocked},
+ {FB_VAR_MAX_DOWNLOAD_SIZE, GetMaxDownloadSize},
+ {FB_VAR_CURRENT_SLOT, ::GetCurrentSlot},
+ {FB_VAR_SLOT_COUNT, GetSlotCount},
+ {FB_VAR_HAS_SLOT, GetHasSlot},
+ {FB_VAR_SLOT_SUCCESSFUL, GetSlotSuccessful},
+ {FB_VAR_SLOT_UNBOOTABLE, GetSlotUnbootable},
+ {FB_VAR_PARTITION_SIZE, GetPartitionSize},
+ {FB_VAR_IS_LOGICAL, GetPartitionIsLogical},
+ {FB_VAR_IS_USERSPACE, GetIsUserspace}};
+
+ // args[0] is command name, args[1] is variable.
+ auto found_variable = kVariableMap.find(args[1]);
+ if (found_variable == kVariableMap.end()) {
+ return device->WriteStatus(FastbootResult::FAIL, "Unknown variable");
+ }
+
+ std::vector<std::string> getvar_args(args.begin() + 2, args.end());
+ return found_variable->second(device, getvar_args);
+}
+
+bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 2) {
+ return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
+ }
+ PartitionHandle handle;
+ if (!OpenPartition(device, args[1], &handle)) {
+ return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
+ }
+ if (wipe_block_device(handle.fd(), get_block_device_size(handle.fd())) == 0) {
+ return device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
+ }
+ return device->WriteStatus(FastbootResult::FAIL, "Erasing failed");
+}
+
+bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 2) {
+ return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
+ }
+ // arg[0] is the command name, arg[1] contains size of data to be downloaded
+ unsigned int size;
+ if (!android::base::ParseUint("0x" + args[1], &size, UINT_MAX)) {
+ return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
+ }
+ device->download_data().resize(size);
+ if (!device->WriteStatus(FastbootResult::DATA, android::base::StringPrintf("%08x", size))) {
+ return false;
+ }
+
+ if (device->HandleData(true, &device->download_data())) {
+ return device->WriteStatus(FastbootResult::OKAY, "");
+ }
+
+ PLOG(ERROR) << "Couldn't download data";
+ return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data");
+}
+
+bool FlashHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 2) {
+ return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
+ }
+ int ret = Flash(device, args[1]);
+ if (ret < 0) {
+ return device->WriteStatus(FastbootResult::FAIL, strerror(-ret));
+ }
+ return device->WriteStatus(FastbootResult::OKAY, "Flashing succeeded");
+}
+
+bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 2) {
+ return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument");
+ }
+
+ // Slot suffix needs to be between 'a' and 'z'.
+ Slot slot;
+ if (!GetSlotNumber(args[1], &slot)) {
+ return device->WriteStatus(FastbootResult::FAIL, "Bad slot suffix");
+ }
+
+ // Non-A/B devices will not have a boot control HAL.
+ auto boot_control_hal = device->boot_control_hal();
+ if (!boot_control_hal) {
+ return device->WriteStatus(FastbootResult::FAIL,
+ "Cannot set slot: boot control HAL absent");
+ }
+ if (slot >= boot_control_hal->getNumberSlots()) {
+ return device->WriteStatus(FastbootResult::FAIL, "Slot out of range");
+ }
+ CommandResult ret;
+ auto cb = [&ret](CommandResult result) { ret = result; };
+ auto result = boot_control_hal->setActiveBootSlot(slot, cb);
+ if (result.isOk() && ret.success) return device->WriteStatus(FastbootResult::OKAY, "");
+ return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot");
+}
+
+bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Shutting down");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,fastboot");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,from_fastboot");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting bootloader");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting fastboot");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+static bool EnterRecovery() {
+ const char msg_switch_to_recovery = 'r';
+
+ android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
+ if (sock < 0) {
+ PLOG(ERROR) << "Couldn't create sock";
+ return false;
+ }
+
+ struct sockaddr_un addr = {.sun_family = AF_UNIX};
+ strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
+ if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ PLOG(ERROR) << "Couldn't connect to recovery";
+ return false;
+ }
+ // Switch to recovery will not update the boot reason since it does not
+ // require a reboot.
+ auto ret = write(sock, &msg_switch_to_recovery, sizeof(msg_switch_to_recovery));
+ if (ret != sizeof(msg_switch_to_recovery)) {
+ PLOG(ERROR) << "Couldn't write message to switch to recovery";
+ return false;
+ }
+
+ return true;
+}
+
+bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto status = true;
+ if (EnterRecovery()) {
+ status = device->WriteStatus(FastbootResult::OKAY, "Rebooting to recovery");
+ } else {
+ status = device->WriteStatus(FastbootResult::FAIL, "Unable to reboot to recovery");
+ }
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return status;
+}
+
+// Helper class for opening a handle to a MetadataBuilder and writing the new
+// partition table to the same place it was read.
+class PartitionBuilder {
+ public:
+ explicit PartitionBuilder(FastbootDevice* device);
+
+ bool Write();
+ bool Valid() const { return !!builder_; }
+ MetadataBuilder* operator->() const { return builder_.get(); }
+
+ private:
+ std::string super_device_;
+ uint32_t slot_number_;
+ std::unique_ptr<MetadataBuilder> builder_;
+};
+
+PartitionBuilder::PartitionBuilder(FastbootDevice* device) {
+ auto super_device = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
+ if (!super_device) {
+ return;
+ }
+ super_device_ = *super_device;
+
+ std::string slot = device->GetCurrentSlot();
+ slot_number_ = SlotNumberForSlotSuffix(slot);
+ builder_ = MetadataBuilder::New(super_device_, slot_number_);
+}
+
+bool PartitionBuilder::Write() {
+ std::unique_ptr<LpMetadata> metadata = builder_->Export();
+ if (!metadata) {
+ return false;
+ }
+ return UpdatePartitionTable(super_device_, *metadata.get(), slot_number_);
+}
+
+bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 3) {
+ return device->WriteFail("Invalid partition name and size");
+ }
+
+ uint64_t partition_size;
+ std::string partition_name = args[1];
+ if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
+ return device->WriteFail("Invalid partition size");
+ }
+
+ PartitionBuilder builder(device);
+ if (!builder.Valid()) {
+ return device->WriteFail("Could not open super partition");
+ }
+ // TODO(112433293) Disallow if the name is in the physical table as well.
+ if (builder->FindPartition(partition_name)) {
+ return device->WriteFail("Partition already exists");
+ }
+
+ // Make a random UUID, since they're not currently used.
+ uuid_t uuid;
+ char uuid_str[37];
+ uuid_generate_random(uuid);
+ uuid_unparse(uuid, uuid_str);
+
+ Partition* partition = builder->AddPartition(partition_name, uuid_str, 0);
+ if (!partition) {
+ return device->WriteFail("Failed to add partition");
+ }
+ if (!builder->ResizePartition(partition, partition_size)) {
+ builder->RemovePartition(partition_name);
+ return device->WriteFail("Not enough space for partition");
+ }
+ if (!builder.Write()) {
+ return device->WriteFail("Failed to write partition table");
+ }
+ return device->WriteOkay("Partition created");
+}
+
+bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 2) {
+ return device->WriteFail("Invalid partition name and size");
+ }
+
+ PartitionBuilder builder(device);
+ if (!builder.Valid()) {
+ return device->WriteFail("Could not open super partition");
+ }
+ builder->RemovePartition(args[1]);
+ if (!builder.Write()) {
+ return device->WriteFail("Failed to write partition table");
+ }
+ return device->WriteOkay("Partition deleted");
+}
+
+bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 3) {
+ return device->WriteFail("Invalid partition name and size");
+ }
+
+ uint64_t partition_size;
+ std::string partition_name = args[1];
+ if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
+ return device->WriteFail("Invalid partition size");
+ }
+
+ PartitionBuilder builder(device);
+ if (!builder.Valid()) {
+ return device->WriteFail("Could not open super partition");
+ }
+
+ Partition* partition = builder->FindPartition(partition_name);
+ if (!partition) {
+ return device->WriteFail("Partition does not exist");
+ }
+ if (!builder->ResizePartition(partition, partition_size)) {
+ return device->WriteFail("Not enough space to resize partition");
+ }
+ if (!builder.Write()) {
+ return device->WriteFail("Failed to write partition table");
+ }
+ return device->WriteOkay("Partition resized");
+}
diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h
new file mode 100644
index 0000000..f67df91
--- /dev/null
+++ b/fastboot/device/commands.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <functional>
+#include <string>
+#include <vector>
+
+class FastbootDevice;
+
+enum class FastbootResult {
+ OKAY,
+ FAIL,
+ INFO,
+ DATA,
+};
+
+// Execute a command with the given arguments (possibly empty).
+using CommandHandler = std::function<bool(FastbootDevice*, const std::vector<std::string>&)>;
+
+bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool FlashHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args);
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
new file mode 100644
index 0000000..c306e67
--- /dev/null
+++ b/fastboot/device/fastboot_device.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#include "fastboot_device.h"
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
+
+#include <algorithm>
+
+#include "constants.h"
+#include "flashing.h"
+#include "usb_client.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::boot::V1_0::IBootControl;
+using ::android::hardware::boot::V1_0::Slot;
+namespace sph = std::placeholders;
+
+FastbootDevice::FastbootDevice()
+ : kCommandMap({
+ {FB_CMD_SET_ACTIVE, SetActiveHandler},
+ {FB_CMD_DOWNLOAD, DownloadHandler},
+ {FB_CMD_GETVAR, GetVarHandler},
+ {FB_CMD_SHUTDOWN, ShutDownHandler},
+ {FB_CMD_REBOOT, RebootHandler},
+ {FB_CMD_REBOOT_BOOTLOADER, RebootBootloaderHandler},
+ {FB_CMD_REBOOT_FASTBOOT, RebootFastbootHandler},
+ {FB_CMD_REBOOT_RECOVERY, RebootRecoveryHandler},
+ {FB_CMD_ERASE, EraseHandler},
+ {FB_CMD_FLASH, FlashHandler},
+ {FB_CMD_CREATE_PARTITION, CreatePartitionHandler},
+ {FB_CMD_DELETE_PARTITION, DeletePartitionHandler},
+ {FB_CMD_RESIZE_PARTITION, ResizePartitionHandler},
+ }),
+ transport_(std::make_unique<ClientUsbTransport>()),
+ boot_control_hal_(IBootControl::getService()) {}
+
+FastbootDevice::~FastbootDevice() {
+ CloseDevice();
+}
+
+void FastbootDevice::CloseDevice() {
+ transport_->Close();
+}
+
+std::string FastbootDevice::GetCurrentSlot() {
+ // Non-A/B devices must not have boot control HALs.
+ if (!boot_control_hal_) {
+ return "";
+ }
+ std::string suffix;
+ auto cb = [&suffix](hidl_string s) { suffix = s; };
+ boot_control_hal_->getSuffix(boot_control_hal_->getCurrentSlot(), cb);
+ return suffix;
+}
+
+bool FastbootDevice::WriteStatus(FastbootResult result, const std::string& message) {
+ constexpr size_t kResponseReasonSize = 4;
+ constexpr size_t kNumResponseTypes = 4; // "FAIL", "OKAY", "INFO", "DATA"
+
+ char buf[FB_RESPONSE_SZ];
+ constexpr size_t kMaxMessageSize = sizeof(buf) - kResponseReasonSize;
+ size_t msg_len = std::min(kMaxMessageSize, message.size());
+
+ constexpr const char* kResultStrings[kNumResponseTypes] = {RESPONSE_OKAY, RESPONSE_FAIL,
+ RESPONSE_INFO, RESPONSE_DATA};
+
+ if (static_cast<size_t>(result) >= kNumResponseTypes) {
+ return false;
+ }
+
+ memcpy(buf, kResultStrings[static_cast<size_t>(result)], kResponseReasonSize);
+ memcpy(buf + kResponseReasonSize, message.c_str(), msg_len);
+
+ size_t response_len = kResponseReasonSize + msg_len;
+ auto write_ret = this->get_transport()->Write(buf, response_len);
+ if (write_ret != static_cast<ssize_t>(response_len)) {
+ PLOG(ERROR) << "Failed to write " << message;
+ return false;
+ }
+
+ return true;
+}
+
+bool FastbootDevice::HandleData(bool read, std::vector<char>* data) {
+ auto read_write_data_size = read ? this->get_transport()->Read(data->data(), data->size())
+ : this->get_transport()->Write(data->data(), data->size());
+ if (read_write_data_size == -1 || static_cast<size_t>(read_write_data_size) != data->size()) {
+ return false;
+ }
+ return true;
+}
+
+void FastbootDevice::ExecuteCommands() {
+ char command[FB_RESPONSE_SZ + 1];
+ for (;;) {
+ auto bytes_read = transport_->Read(command, FB_RESPONSE_SZ);
+ if (bytes_read == -1) {
+ PLOG(ERROR) << "Couldn't read command";
+ return;
+ }
+ command[bytes_read] = '\0';
+
+ LOG(INFO) << "Fastboot command: " << command;
+ auto args = android::base::Split(command, ":");
+ auto found_command = kCommandMap.find(args[0]);
+ if (found_command == kCommandMap.end()) {
+ WriteStatus(FastbootResult::FAIL, "Unrecognized command");
+ continue;
+ }
+ if (!found_command->second(this, args)) {
+ return;
+ }
+ }
+}
+
+bool FastbootDevice::WriteOkay(const std::string& message) {
+ return WriteStatus(FastbootResult::OKAY, message);
+}
+
+bool FastbootDevice::WriteFail(const std::string& message) {
+ return WriteStatus(FastbootResult::FAIL, message);
+}
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
new file mode 100644
index 0000000..addc2ef
--- /dev/null
+++ b/fastboot/device/fastboot_device.h
@@ -0,0 +1,58 @@
+/*
+ * 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 <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <android/hardware/boot/1.0/IBootControl.h>
+
+#include "commands.h"
+#include "transport.h"
+#include "variables.h"
+
+class FastbootDevice {
+ public:
+ FastbootDevice();
+ ~FastbootDevice();
+
+ void CloseDevice();
+ void ExecuteCommands();
+ bool WriteStatus(FastbootResult result, const std::string& message);
+ bool HandleData(bool read, std::vector<char>* data);
+ std::string GetCurrentSlot();
+
+ // Shortcuts for writing OKAY and FAIL status results.
+ bool WriteOkay(const std::string& message);
+ bool WriteFail(const std::string& message);
+
+ std::vector<char>& download_data() { return download_data_; }
+ Transport* get_transport() { return transport_.get(); }
+ android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal() {
+ return boot_control_hal_;
+ }
+
+ private:
+ const std::unordered_map<std::string, CommandHandler> kCommandMap;
+
+ std::unique_ptr<Transport> transport_;
+ android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal_;
+ std::vector<char> download_data_;
+};
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
new file mode 100644
index 0000000..b5ed170
--- /dev/null
+++ b/fastboot/device/flashing.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+#include "flashing.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <memory>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <ext4_utils/ext4_utils.h>
+#include <sparse/sparse.h>
+
+#include "fastboot_device.h"
+#include "utility.h"
+
+namespace {
+
+constexpr uint32_t SPARSE_HEADER_MAGIC = 0xed26ff3a;
+
+} // namespace
+
+int FlashRawDataChunk(int fd, const char* data, size_t len) {
+ size_t ret = 0;
+ while (ret < len) {
+ int this_len = std::min(static_cast<size_t>(1048576UL * 8), len - ret);
+ int this_ret = write(fd, data, this_len);
+ if (this_ret < 0) {
+ PLOG(ERROR) << "Failed to flash data of len " << len;
+ return -1;
+ }
+ data += this_ret;
+ ret += this_ret;
+ }
+ return 0;
+}
+
+int FlashRawData(int fd, const std::vector<char>& downloaded_data) {
+ int ret = FlashRawDataChunk(fd, downloaded_data.data(), downloaded_data.size());
+ if (ret < 0) {
+ return -errno;
+ }
+ return ret;
+}
+
+int WriteCallback(void* priv, const void* data, size_t len) {
+ int fd = reinterpret_cast<long long>(priv);
+ if (!data) {
+ return lseek64(fd, len, SEEK_CUR) >= 0 ? 0 : -errno;
+ }
+ return FlashRawDataChunk(fd, reinterpret_cast<const char*>(data), len);
+}
+
+int FlashSparseData(int fd, std::vector<char>& downloaded_data) {
+ struct sparse_file* file = sparse_file_import_buf(downloaded_data.data(), true, false);
+ if (!file) {
+ return -ENOENT;
+ }
+ return sparse_file_callback(file, false, false, WriteCallback, reinterpret_cast<void*>(fd));
+}
+
+int FlashBlockDevice(int fd, std::vector<char>& downloaded_data) {
+ lseek64(fd, 0, SEEK_SET);
+ if (downloaded_data.size() >= sizeof(SPARSE_HEADER_MAGIC) &&
+ *reinterpret_cast<uint32_t*>(downloaded_data.data()) == SPARSE_HEADER_MAGIC) {
+ return FlashSparseData(fd, downloaded_data);
+ } else {
+ return FlashRawData(fd, downloaded_data);
+ }
+}
+
+int Flash(FastbootDevice* device, const std::string& partition_name) {
+ PartitionHandle handle;
+ if (!OpenPartition(device, partition_name, &handle)) {
+ return -ENOENT;
+ }
+
+ std::vector<char> data = std::move(device->download_data());
+ if (data.size() == 0) {
+ return -EINVAL;
+ } else if (data.size() > get_block_device_size(handle.fd())) {
+ return -EOVERFLOW;
+ }
+ return FlashBlockDevice(handle.fd(), data);
+}
diff --git a/init/watchdogd.h b/fastboot/device/flashing.h
similarity index 69%
copy from init/watchdogd.h
copy to fastboot/device/flashing.h
index 73f77d5..206a407 100644
--- a/init/watchdogd.h
+++ b/fastboot/device/flashing.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -14,15 +14,11 @@
* limitations under the License.
*/
-#ifndef _INIT_WATCHDOGD_H_
-#define _INIT_WATCHDOGD_H_
+#pragma once
-namespace android {
-namespace init {
+#include <string>
+#include <vector>
-int watchdogd_main(int argc, char **argv);
+class FastbootDevice;
-} // namespace init
-} // namespace android
-
-#endif
+int Flash(FastbootDevice* device, const std::string& partition_name);
diff --git a/init/watchdogd.h b/fastboot/device/main.cpp
similarity index 63%
copy from init/watchdogd.h
copy to fastboot/device/main.cpp
index 73f77d5..df9c900 100644
--- a/init/watchdogd.h
+++ b/fastboot/device/main.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#ifndef _INIT_WATCHDOGD_H_
-#define _INIT_WATCHDOGD_H_
+#include <android-base/logging.h>
-namespace android {
-namespace init {
+#include "fastboot_device.h"
-int watchdogd_main(int argc, char **argv);
+int main(int /*argc*/, char* argv[]) {
+ android::base::InitLogging(argv, &android::base::KernelLogger);
-} // namespace init
-} // namespace android
-
-#endif
+ while (true) {
+ FastbootDevice device;
+ device.ExecuteCommands();
+ }
+}
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
new file mode 100644
index 0000000..215f99a
--- /dev/null
+++ b/fastboot/device/usb_client.cpp
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+#include "usb_client.h"
+
+#include <endian.h>
+#include <fcntl.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+constexpr int kMaxPacketSizeFs = 64;
+constexpr int kMaxPacketSizeHs = 512;
+constexpr int kMaxPacketsizeSs = 1024;
+
+constexpr size_t kFbFfsNumBufs = 16;
+constexpr size_t kFbFfsBufSize = 32768;
+
+constexpr const char* kUsbFfsFastbootEp0 = "/dev/usb-ffs/fastboot/ep0";
+constexpr const char* kUsbFfsFastbootOut = "/dev/usb-ffs/fastboot/ep1";
+constexpr const char* kUsbFfsFastbootIn = "/dev/usb-ffs/fastboot/ep2";
+
+struct FuncDesc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_endpoint_descriptor_no_audio sink;
+} __attribute__((packed));
+
+struct SsFuncDesc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_ss_ep_comp_descriptor source_comp;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_ss_ep_comp_descriptor sink_comp;
+} __attribute__((packed));
+
+struct DescV2 {
+ struct usb_functionfs_descs_head_v2 header;
+ // The rest of the structure depends on the flags in the header.
+ __le32 fs_count;
+ __le32 hs_count;
+ __le32 ss_count;
+ struct FuncDesc fs_descs, hs_descs;
+ struct SsFuncDesc ss_descs;
+} __attribute__((packed));
+
+struct usb_interface_descriptor fastboot_interface = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 66,
+ .bInterfaceProtocol = 3,
+ .iInterface = 1, /* first string from the provided table */
+};
+
+static struct FuncDesc fs_descriptors = {
+ .intf = fastboot_interface,
+ .source =
+ {
+ .bLength = sizeof(fs_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeFs,
+ },
+ .sink =
+ {
+ .bLength = sizeof(fs_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeFs,
+ },
+};
+
+static struct FuncDesc hs_descriptors = {
+ .intf = fastboot_interface,
+ .source =
+ {
+ .bLength = sizeof(hs_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeHs,
+ },
+ .sink =
+ {
+ .bLength = sizeof(hs_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeHs,
+ },
+};
+
+static struct SsFuncDesc ss_descriptors = {
+ .intf = fastboot_interface,
+ .source =
+ {
+ .bLength = sizeof(ss_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketsizeSs,
+ },
+ .source_comp =
+ {
+ .bLength = sizeof(ss_descriptors.source_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 15,
+ },
+ .sink =
+ {
+ .bLength = sizeof(ss_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketsizeSs,
+ },
+ .sink_comp =
+ {
+ .bLength = sizeof(ss_descriptors.sink_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 15,
+ },
+};
+
+#define STR_INTERFACE_ "fastboot"
+
+static const struct {
+ struct usb_functionfs_strings_head header;
+ struct {
+ __le16 code;
+ const char str1[sizeof(STR_INTERFACE_)];
+ } __attribute__((packed)) lang0;
+} __attribute__((packed)) strings = {
+ .header =
+ {
+ .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = htole32(sizeof(strings)),
+ .str_count = htole32(1),
+ .lang_count = htole32(1),
+ },
+ .lang0 =
+ {
+ htole16(0x0409), /* en-us */
+ STR_INTERFACE_,
+ },
+};
+
+static struct DescV2 v2_descriptor = {
+ .header =
+ {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .length = htole32(sizeof(v2_descriptor)),
+ .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC,
+ },
+ .fs_count = 3,
+ .hs_count = 3,
+ .ss_count = 5,
+ .fs_descs = fs_descriptors,
+ .hs_descs = hs_descriptors,
+ .ss_descs = ss_descriptors,
+};
+
+// Reimplementing since usb_ffs_close() does not close the control FD.
+static void CloseFunctionFs(usb_handle* h) {
+ if (h->bulk_in > 0) {
+ close(h->bulk_in);
+ h->bulk_in = -1;
+ }
+ if (h->bulk_out > 0) {
+ close(h->bulk_out);
+ h->bulk_out = -1;
+ }
+ if (h->control > 0) {
+ close(h->control);
+ h->control = -1;
+ }
+}
+
+static bool InitFunctionFs(usb_handle* h) {
+ LOG(INFO) << "initializing functionfs";
+
+ if (h->control < 0) { // might have already done this before
+ LOG(INFO) << "opening control endpoint " << kUsbFfsFastbootEp0;
+ h->control = open(kUsbFfsFastbootEp0, O_RDWR);
+ if (h->control < 0) {
+ PLOG(ERROR) << "cannot open control endpoint " << kUsbFfsFastbootEp0;
+ goto err;
+ }
+
+ auto ret = write(h->control, &v2_descriptor, sizeof(v2_descriptor));
+ if (ret < 0) {
+ PLOG(ERROR) << "cannot write descriptors " << kUsbFfsFastbootEp0;
+ goto err;
+ }
+
+ ret = write(h->control, &strings, sizeof(strings));
+ if (ret < 0) {
+ PLOG(ERROR) << "cannot write strings " << kUsbFfsFastbootEp0;
+ goto err;
+ }
+ // Signal only when writing the descriptors to ffs
+ android::base::SetProperty("sys.usb.ffs.ready", "1");
+ }
+
+ h->bulk_out = open(kUsbFfsFastbootOut, O_RDONLY);
+ if (h->bulk_out < 0) {
+ PLOG(ERROR) << "cannot open bulk-out endpoint " << kUsbFfsFastbootOut;
+ goto err;
+ }
+
+ h->bulk_in = open(kUsbFfsFastbootIn, O_WRONLY);
+ if (h->bulk_in < 0) {
+ PLOG(ERROR) << "cannot open bulk-in endpoint " << kUsbFfsFastbootIn;
+ goto err;
+ }
+
+ h->read_aiob.fd = h->bulk_out;
+ h->write_aiob.fd = h->bulk_in;
+ h->reads_zero_packets = false;
+ return true;
+
+err:
+ CloseFunctionFs(h);
+ return false;
+}
+
+ClientUsbTransport::ClientUsbTransport()
+ : handle_(std::unique_ptr<usb_handle>(create_usb_handle(kFbFfsNumBufs, kFbFfsBufSize))) {
+ if (!InitFunctionFs(handle_.get())) {
+ handle_.reset(nullptr);
+ }
+}
+
+ssize_t ClientUsbTransport::Read(void* data, size_t len) {
+ if (handle_ == nullptr || len > SSIZE_MAX) {
+ return -1;
+ }
+ char* char_data = static_cast<char*>(data);
+ size_t bytes_read_total = 0;
+ while (bytes_read_total < len) {
+ auto bytes_to_read = std::min(len - bytes_read_total, kFbFfsNumBufs * kFbFfsBufSize);
+ auto bytes_read_now = handle_->read(handle_.get(), char_data, bytes_to_read);
+ if (bytes_read_now < 0) {
+ return bytes_read_total;
+ }
+ bytes_read_total += bytes_read_now;
+ char_data += bytes_read_now;
+ if (static_cast<size_t>(bytes_read_now) < bytes_to_read) {
+ break;
+ }
+ }
+ return bytes_read_total;
+}
+
+ssize_t ClientUsbTransport::Write(const void* data, size_t len) {
+ if (handle_ == nullptr || len > SSIZE_MAX) {
+ return -1;
+ }
+ const char* char_data = reinterpret_cast<const char*>(data);
+ size_t bytes_written_total = 0;
+ while (bytes_written_total < len) {
+ auto bytes_to_write = std::min(len - bytes_written_total, kFbFfsNumBufs * kFbFfsBufSize);
+ auto bytes_written_now = handle_->write(handle_.get(), data, bytes_to_write);
+ if (bytes_written_now < 0) {
+ return bytes_written_total;
+ }
+ bytes_written_total += bytes_written_now;
+ char_data += bytes_written_now;
+ if (static_cast<size_t>(bytes_written_now) < bytes_to_write) {
+ break;
+ }
+ }
+ return bytes_written_total;
+}
+
+int ClientUsbTransport::Close() {
+ if (handle_ == nullptr) {
+ return -1;
+ }
+ CloseFunctionFs(handle_.get());
+ return 0;
+}
diff --git a/fastboot/device/usb_client.h b/fastboot/device/usb_client.h
new file mode 100644
index 0000000..3694f9a
--- /dev/null
+++ b/fastboot/device/usb_client.h
@@ -0,0 +1,37 @@
+/*
+ * 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 <memory>
+
+#include <adbd/usb.h>
+
+#include "transport.h"
+
+class ClientUsbTransport : public Transport {
+ public:
+ ClientUsbTransport();
+ ~ClientUsbTransport() override = default;
+
+ ssize_t Read(void* data, size_t len) override;
+ ssize_t Write(const void* data, size_t len) override;
+ int Close() override;
+
+ private:
+ std::unique_ptr<usb_handle> handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientUsbTransport);
+};
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
new file mode 100644
index 0000000..ec84576
--- /dev/null
+++ b/fastboot/device/utility.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+#include "utility.h"
+
+#include <android-base/logging.h>
+#include <fs_mgr_dm_linear.h>
+#include <liblp/liblp.h>
+
+#include "fastboot_device.h"
+
+using namespace android::fs_mgr;
+using android::base::unique_fd;
+using android::hardware::boot::V1_0::Slot;
+
+static bool OpenPhysicalPartition(const std::string& name, PartitionHandle* handle) {
+ std::optional<std::string> path = FindPhysicalPartition(name);
+ if (!path) {
+ return false;
+ }
+ *handle = PartitionHandle(*path);
+ return true;
+}
+
+static bool OpenLogicalPartition(const std::string& name, const std::string& slot,
+ PartitionHandle* handle) {
+ std::optional<std::string> path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
+ if (!path) {
+ return false;
+ }
+ uint32_t slot_number = SlotNumberForSlotSuffix(slot);
+ std::string dm_path;
+ if (!CreateLogicalPartition(path->c_str(), slot_number, name, true, &dm_path)) {
+ LOG(ERROR) << "Could not map partition: " << name;
+ return false;
+ }
+ auto closer = [name]() -> void { DestroyLogicalPartition(name); };
+ *handle = PartitionHandle(dm_path, std::move(closer));
+ return true;
+}
+
+bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle) {
+ // We prioritize logical partitions over physical ones, and do this
+ // consistently for other partition operations (like getvar:partition-size).
+ if (LogicalPartitionExists(name, device->GetCurrentSlot())) {
+ if (!OpenLogicalPartition(name, device->GetCurrentSlot(), handle)) {
+ return false;
+ }
+ } else if (!OpenPhysicalPartition(name, handle)) {
+ LOG(ERROR) << "No such partition: " << name;
+ return false;
+ }
+
+ unique_fd fd(TEMP_FAILURE_RETRY(open(handle->path().c_str(), O_WRONLY | O_EXCL)));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to open block device: " << handle->path();
+ return false;
+ }
+ handle->set_fd(std::move(fd));
+ return true;
+}
+
+std::optional<std::string> FindPhysicalPartition(const std::string& name) {
+ std::string path = "/dev/block/by-name/" + name;
+ if (access(path.c_str(), R_OK | W_OK) < 0) {
+ return {};
+ }
+ return path;
+}
+
+static const LpMetadataPartition* FindLogicalPartition(const LpMetadata& metadata,
+ const std::string& name) {
+ for (const auto& partition : metadata.partitions) {
+ if (GetPartitionName(partition) == name) {
+ return &partition;
+ }
+ }
+ return nullptr;
+}
+
+bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix,
+ bool* is_zero_length) {
+ auto path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
+ if (!path) {
+ return false;
+ }
+
+ uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
+ std::unique_ptr<LpMetadata> metadata = ReadMetadata(path->c_str(), slot_number);
+ if (!metadata) {
+ return false;
+ }
+ const LpMetadataPartition* partition = FindLogicalPartition(*metadata.get(), name);
+ if (!partition) {
+ return false;
+ }
+ if (is_zero_length) {
+ *is_zero_length = (partition->num_extents == 0);
+ }
+ return true;
+}
+
+bool GetSlotNumber(const std::string& slot, Slot* number) {
+ if (slot.size() != 1) {
+ return false;
+ }
+ if (slot[0] < 'a' || slot[0] > 'z') {
+ return false;
+ }
+ *number = slot[0] - 'a';
+ return true;
+}
diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h
new file mode 100644
index 0000000..0931fc3
--- /dev/null
+++ b/fastboot/device/utility.h
@@ -0,0 +1,60 @@
+/*
+ * 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 <optional>
+#include <string>
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
+
+// Logical partitions are only mapped to a block device as needed, and
+// immediately unmapped when no longer needed. In order to enforce this we
+// require accessing partitions through a Handle abstraction, which may perform
+// additional operations after closing its file descriptor.
+class PartitionHandle {
+ public:
+ PartitionHandle() {}
+ explicit PartitionHandle(const std::string& path) : path_(path) {}
+ PartitionHandle(const std::string& path, std::function<void()>&& closer)
+ : path_(path), closer_(std::move(closer)) {}
+ PartitionHandle(PartitionHandle&& other) = default;
+ PartitionHandle& operator=(PartitionHandle&& other) = default;
+ ~PartitionHandle() {
+ if (closer_) {
+ // Make sure the device is closed first.
+ fd_ = {};
+ closer_();
+ }
+ }
+ const std::string& path() const { return path_; }
+ int fd() const { return fd_.get(); }
+ void set_fd(android::base::unique_fd&& fd) { fd_ = std::move(fd); }
+
+ private:
+ std::string path_;
+ android::base::unique_fd fd_;
+ std::function<void()> closer_;
+};
+
+class FastbootDevice;
+
+std::optional<std::string> FindPhysicalPartition(const std::string& name);
+bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix,
+ bool* is_zero_length = nullptr);
+bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle);
+
+bool GetSlotNumber(const std::string& slot, android::hardware::boot::V1_0::Slot* number);
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
new file mode 100644
index 0000000..a5dead2
--- /dev/null
+++ b/fastboot/device/variables.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#include "variables.h"
+
+#include <inttypes.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <ext4_utils/ext4_utils.h>
+
+#include "fastboot_device.h"
+#include "flashing.h"
+#include "utility.h"
+
+using ::android::hardware::boot::V1_0::BoolResult;
+using ::android::hardware::boot::V1_0::Slot;
+
+constexpr int kMaxDownloadSizeDefault = 0x20000000;
+constexpr char kFastbootProtocolVersion[] = "0.4";
+
+bool GetVersion(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteOkay(kFastbootProtocolVersion);
+}
+
+bool GetBootloaderVersion(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteOkay(android::base::GetProperty("ro.bootloader", ""));
+}
+
+bool GetBasebandVersion(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteOkay(android::base::GetProperty("ro.build.expect.baseband", ""));
+}
+
+bool GetProduct(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteOkay(android::base::GetProperty("ro.product.device", ""));
+}
+
+bool GetSerial(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteOkay(android::base::GetProperty("ro.serialno", ""));
+}
+
+bool GetSecure(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteOkay(android::base::GetBoolProperty("ro.secure", "") ? "yes" : "no");
+}
+
+bool GetCurrentSlot(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ std::string suffix = device->GetCurrentSlot();
+ std::string slot = suffix.size() == 2 ? suffix.substr(1) : suffix;
+ return device->WriteOkay(slot);
+}
+
+bool GetSlotCount(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto boot_control_hal = device->boot_control_hal();
+ if (!boot_control_hal) {
+ return "0";
+ }
+ return device->WriteOkay(std::to_string(boot_control_hal->getNumberSlots()));
+}
+
+bool GetSlotSuccessful(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.empty()) {
+ return device->WriteFail("Missing argument");
+ }
+ Slot slot;
+ if (!GetSlotNumber(args[0], &slot)) {
+ return device->WriteFail("Invalid slot");
+ }
+ auto boot_control_hal = device->boot_control_hal();
+ if (!boot_control_hal) {
+ return device->WriteFail("Device has no slots");
+ }
+ if (boot_control_hal->isSlotMarkedSuccessful(slot) != BoolResult::TRUE) {
+ return device->WriteOkay("no");
+ }
+ return device->WriteOkay("yes");
+}
+
+bool GetSlotUnbootable(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.empty()) {
+ return device->WriteFail("Missing argument");
+ }
+ Slot slot;
+ if (!GetSlotNumber(args[0], &slot)) {
+ return device->WriteFail("Invalid slot");
+ }
+ auto boot_control_hal = device->boot_control_hal();
+ if (!boot_control_hal) {
+ return device->WriteFail("Device has no slots");
+ }
+ if (boot_control_hal->isSlotBootable(slot) != BoolResult::TRUE) {
+ return device->WriteOkay("yes");
+ }
+ return device->WriteOkay("no");
+}
+
+bool GetMaxDownloadSize(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteOkay(std::to_string(kMaxDownloadSizeDefault));
+}
+
+bool GetUnlocked(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteOkay("yes");
+}
+
+bool GetHasSlot(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.empty()) {
+ return device->WriteFail("Missing argument");
+ }
+ std::string slot_suffix = device->GetCurrentSlot();
+ if (slot_suffix.empty()) {
+ return device->WriteFail("Invalid slot");
+ }
+ std::string result = (args[0] == "userdata" ? "no" : "yes");
+ return device->WriteOkay(result);
+}
+
+bool GetPartitionSize(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 1) {
+ return device->WriteFail("Missing argument");
+ }
+ // Zero-length partitions cannot be created through device-mapper, so we
+ // special case them here.
+ bool is_zero_length;
+ if (LogicalPartitionExists(args[0], device->GetCurrentSlot(), &is_zero_length) &&
+ is_zero_length) {
+ return device->WriteOkay("0");
+ }
+ // Otherwise, open the partition as normal.
+ PartitionHandle handle;
+ if (!OpenPartition(device, args[0], &handle)) {
+ return device->WriteFail("Could not open partition");
+ }
+ uint64_t size = get_block_device_size(handle.fd());
+ return device->WriteOkay(android::base::StringPrintf("%" PRIX64, size));
+}
+
+bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 1) {
+ return device->WriteFail("Missing argument");
+ }
+ // Note: if a partition name is in both the GPT and the super partition, we
+ // return "true", to be consistent with prefering to flash logical partitions
+ // over physical ones.
+ std::string partition_name = args[0];
+ if (LogicalPartitionExists(partition_name, device->GetCurrentSlot())) {
+ return device->WriteOkay("yes");
+ }
+ if (FindPhysicalPartition(partition_name)) {
+ return device->WriteOkay("no");
+ }
+ return device->WriteFail("Partition not found");
+}
+
+bool GetIsUserspace(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteOkay("yes");
+}
diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h
new file mode 100644
index 0000000..554a080
--- /dev/null
+++ b/fastboot/device/variables.h
@@ -0,0 +1,39 @@
+/*
+ * 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 <functional>
+#include <string>
+#include <vector>
+
+class FastbootDevice;
+
+bool GetVersion(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetBootloaderVersion(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetBasebandVersion(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetProduct(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetSerial(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetSecure(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetCurrentSlot(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetSlotCount(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetSlotSuccessful(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetSlotUnbootable(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetMaxDownloadSize(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetUnlocked(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetHasSlot(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetPartitionSize(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetIsUserspace(FastbootDevice* device, const std::vector<std::string>& args);
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 63ee2af..6890643 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -155,6 +155,21 @@
total);
}
+void fb_queue_create_partition(const std::string& partition, const std::string& size) {
+ Action& a = queue_action(OP_COMMAND, FB_CMD_CREATE_PARTITION ":" + partition + ":" + size);
+ a.msg = "Creating '" + partition + "'";
+}
+
+void fb_queue_delete_partition(const std::string& partition) {
+ Action& a = queue_action(OP_COMMAND, FB_CMD_DELETE_PARTITION ":" + partition);
+ a.msg = "Deleting '" + partition + "'";
+}
+
+void fb_queue_resize_partition(const std::string& partition, const std::string& size) {
+ Action& a = queue_action(OP_COMMAND, FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size);
+ a.msg = "Resizing '" + partition + "'";
+}
+
static int match(const char* str, const char** value, unsigned count) {
unsigned n;
diff --git a/fastboot/engine.h b/fastboot/engine.h
index 74aaa6a..8aebdd7 100644
--- a/fastboot/engine.h
+++ b/fastboot/engine.h
@@ -69,6 +69,9 @@
void fb_queue_upload(const std::string& outfile);
void fb_queue_notice(const std::string& notice);
void fb_queue_wait_for_disconnect(void);
+void fb_queue_create_partition(const std::string& partition, const std::string& size);
+void fb_queue_delete_partition(const std::string& partition);
+void fb_queue_resize_partition(const std::string& partition, const std::string& size);
int64_t fb_execute_queue();
void fb_set_active(const std::string& slot);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index c830321..dc94952 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -111,12 +111,13 @@
const char* img_name;
const char* sig_name;
const char* part_name;
- bool is_optional;
- bool is_secondary;
+ bool optional_if_no_image;
+ bool optional_if_no_partition;
+ bool IsSecondary() const { return nickname == nullptr; }
} images[] = {
// clang-format off
{ "boot", "boot.img", "boot.sig", "boot", false, false },
- { nullptr, "boot_other.img", "boot.sig", "boot", true, true },
+ { nullptr, "boot_other.img", "boot.sig", "boot", true, false },
{ "dtbo", "dtbo.img", "dtbo.sig", "dtbo", true, false },
{ "dts", "dt.img", "dt.sig", "dts", true, false },
{ "odm", "odm.img", "odm.sig", "odm", true, false },
@@ -124,14 +125,15 @@
{ "product-services",
"product-services.img",
"product-services.sig",
- "product-services",
- true, false },
+ "product_services",
+ true, true },
{ "recovery", "recovery.img", "recovery.sig", "recovery", true, false },
- { "system", "system.img", "system.sig", "system", false, false },
- { nullptr, "system_other.img", "system.sig", "system", true, true },
+ { "super", "super.img", "super.sig", "super", true, true },
+ { "system", "system.img", "system.sig", "system", false, true },
+ { nullptr, "system_other.img", "system.sig", "system", true, false },
{ "vbmeta", "vbmeta.img", "vbmeta.sig", "vbmeta", true, false },
- { "vendor", "vendor.img", "vendor.sig", "vendor", true, false },
- { nullptr, "vendor_other.img", "vendor.sig", "vendor", true, true },
+ { "vendor", "vendor.img", "vendor.sig", "vendor", true, true },
+ { nullptr, "vendor_other.img", "vendor.sig", "vendor", true, false },
// clang-format on
};
@@ -636,7 +638,8 @@
// "require partition-exists=x" is a special case, added because of the trouble we had when
// Pixel 2 shipped with new partitions and users used old versions of fastboot to flash them,
// missing out new partitions. A device with new partitions can use "partition-exists" to
- // override the `is_optional` field in the `images` array.
+ // override the fields `optional_if_no_image` and 'optional_if_no_partition' in the `images`
+ // array.
if (!strcmp(name, "partition-exists")) {
const char* partition_name = val[0];
std::string has_slot;
@@ -647,7 +650,8 @@
bool known_partition = false;
for (size_t i = 0; i < arraysize(images); ++i) {
if (images[i].nickname && !strcmp(images[i].nickname, partition_name)) {
- images[i].is_optional = false;
+ images[i].optional_if_no_image = false;
+ images[i].optional_if_no_partition = false;
known_partition = true;
}
}
@@ -1040,6 +1044,25 @@
}
}
+static bool if_partition_exists(const std::string& partition, const std::string& slot) {
+ std::string has_slot;
+ std::string partition_name = partition;
+
+ if (fb_getvar("has-slot:" + partition, &has_slot) && has_slot == "yes") {
+ if (slot == "") {
+ std::string current_slot = get_current_slot();
+ if (current_slot == "") {
+ die("Failed to identify current slot");
+ }
+ partition_name += "_" + current_slot;
+ } else {
+ partition_name += "_" + slot;
+ }
+ }
+ std::string partition_size;
+ return fb_getvar("partition-size:" + partition_name, &partition_size);
+}
+
static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) {
queue_info_dump();
@@ -1075,7 +1098,7 @@
}
for (size_t i = 0; i < arraysize(images); ++i) {
const char* slot = slot_override.c_str();
- if (images[i].is_secondary) {
+ if (images[i].IsSecondary()) {
if (!skip_secondary) {
slot = secondary.c_str();
} else {
@@ -1085,12 +1108,17 @@
int fd = unzip_to_file(zip, images[i].img_name);
if (fd == -1) {
- if (images[i].is_optional) {
+ if (images[i].optional_if_no_image) {
continue; // An optional file is missing, so ignore it.
}
die("non-optional file %s missing", images[i].img_name);
}
+ if (images[i].optional_if_no_partition &&
+ !if_partition_exists(images[i].part_name, slot)) {
+ continue;
+ }
+
fastboot_buffer buf;
if (!load_buf_fd(fd, &buf)) {
die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
@@ -1162,7 +1190,7 @@
for (size_t i = 0; i < arraysize(images); i++) {
const char* slot = NULL;
- if (images[i].is_secondary) {
+ if (images[i].IsSecondary()) {
if (!skip_secondary) slot = secondary.c_str();
} else {
slot = slot_override.c_str();
@@ -1171,10 +1199,13 @@
fname = find_item_given_name(images[i].img_name);
fastboot_buffer buf;
if (!load_buf(fname.c_str(), &buf)) {
- if (images[i].is_optional) continue;
+ if (images[i].optional_if_no_image) continue;
die("could not load '%s': %s", images[i].img_name, strerror(errno));
}
-
+ if (images[i].optional_if_no_partition &&
+ !if_partition_exists(images[i].part_name, slot)) {
+ continue;
+ }
auto flashall = [&](const std::string &partition) {
do_send_signature(fname.c_str());
flash_buf(partition.c_str(), &buf);
@@ -1332,6 +1363,8 @@
bool wants_wipe = false;
bool wants_reboot = false;
bool wants_reboot_bootloader = false;
+ bool wants_reboot_recovery = false;
+ bool wants_reboot_fastboot = false;
bool skip_reboot = false;
bool wants_set_active = false;
bool skip_secondary = false;
@@ -1554,6 +1587,12 @@
if (what == "bootloader") {
wants_reboot = false;
wants_reboot_bootloader = true;
+ } else if (what == "recovery") {
+ wants_reboot = false;
+ wants_reboot_recovery = true;
+ } else if (what == "fastboot") {
+ wants_reboot = false;
+ wants_reboot_fastboot = true;
} else {
syntax_error("unknown reboot target %s", what.c_str());
}
@@ -1562,6 +1601,10 @@
if (!args.empty()) syntax_error("junk after reboot command");
} else if (command == "reboot-bootloader") {
wants_reboot_bootloader = true;
+ } else if (command == "reboot-recovery") {
+ wants_reboot_recovery = true;
+ } else if (command == "reboot-fastboot") {
+ wants_reboot_fastboot = true;
} else if (command == "continue") {
fb_queue_command("continue", "resuming boot");
} else if (command == "boot") {
@@ -1648,6 +1691,17 @@
} else {
syntax_error("unknown 'flashing' command %s", args[0].c_str());
}
+ } else if (command == "create-logical-partition") {
+ std::string partition = next_arg(&args);
+ std::string size = next_arg(&args);
+ fb_queue_create_partition(partition, size);
+ } else if (command == "delete-logical-partition") {
+ std::string partition = next_arg(&args);
+ fb_queue_delete_partition(partition);
+ } else if (command == "resize-logical-partition") {
+ std::string partition = next_arg(&args);
+ std::string size = next_arg(&args);
+ fb_queue_resize_partition(partition, size);
} else {
syntax_error("unknown command %s", command.c_str());
}
@@ -1679,6 +1733,12 @@
} else if (wants_reboot_bootloader) {
fb_queue_command("reboot-bootloader", "rebooting into bootloader");
fb_queue_wait_for_disconnect();
+ } else if (wants_reboot_recovery) {
+ fb_queue_command("reboot-recovery", "rebooting into recovery");
+ fb_queue_wait_for_disconnect();
+ } else if (wants_reboot_fastboot) {
+ fb_queue_command("reboot-fastboot", "rebooting into fastboot");
+ fb_queue_wait_for_disconnect();
}
int status = fb_execute_queue() ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index aabc620..55ca65d 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -134,7 +134,7 @@
return ret;
}
- std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:d:]]+)");
+ std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
std::smatch sm;
for (auto& s : all) {
@@ -264,11 +264,16 @@
std::vector<std::string>* info) {
RetCode ret;
int dsize;
- if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize)) || dsize == 0) {
- error_ = "Upload request failed";
+ if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize))) {
+ error_ = "Upload request failed: " + error_;
return ret;
}
+ if (!dsize) {
+ error_ = "Upload request failed, device reports 0 bytes available";
+ return BAD_DEV_RESP;
+ }
+
std::vector<char> data;
data.resize(dsize);
@@ -462,10 +467,10 @@
}
RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
+ // ioctl on 0-length buffer causes freezing
if (!size) {
- return SUCCESS;
+ return BAD_ARG;
}
-
// Write the buffer
ssize_t tmp = transport->Write(buf, size);
@@ -521,7 +526,7 @@
// Now we need to send a multiple of chunk size
size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
- if (SendBuffer(data + total, nbytes)) {
+ if (nbytes && SendBuffer(data + total, nbytes)) { // Don't send a ZLP
error_ = ErrnoStr("Send failed in SparseWriteCallback()");
return -1;
}
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index 8af1743..dd199c0 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -103,7 +103,7 @@
/* HELPERS */
void SetInfoCallback(std::function<void(std::string&)> info);
- const std::string RCString(RetCode rc);
+ static const std::string RCString(RetCode rc);
std::string Error();
RetCode WaitForDisconnect();
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index cc1714f..b0ac2ef 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -177,6 +177,8 @@
mkf2fs_args.push_back("encrypt");
mkf2fs_args.push_back("-O");
mkf2fs_args.push_back("quota");
+ mkf2fs_args.push_back("-O");
+ mkf2fs_args.push_back("verity");
mkf2fs_args.push_back(fileName);
mkf2fs_args.push_back(nullptr);
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 196321c..6329d54 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -43,6 +43,7 @@
"fs_mgr_avb.cpp",
"fs_mgr_avb_ops.cpp",
"fs_mgr_dm_linear.cpp",
+ "fs_mgr_overlayfs.cpp",
],
shared_libs: [
"libfec",
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index b3df811..99f2df8 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "fs_mgr.h"
+
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
@@ -51,6 +53,7 @@
#include <ext4_utils/ext4_sb.h>
#include <ext4_utils/ext4_utils.h>
#include <ext4_utils/wipe.h>
+#include <fs_mgr_overlayfs.h>
#include <libdm/dm.h>
#include <linux/fs.h>
#include <linux/loop.h>
@@ -58,7 +61,6 @@
#include <log/log_properties.h>
#include <logwrap/logwrap.h>
-#include "fs_mgr.h"
#include "fs_mgr_avb.h"
#include "fs_mgr_priv.h"
@@ -1035,6 +1037,10 @@
}
}
+#if ALLOW_ADBD_DISABLE_VERITY == 1 // "userdebug" build
+ fs_mgr_overlayfs_mount_all();
+#endif
+
if (error_count) {
return FS_MGR_MNTALL_FAIL;
} else {
@@ -1052,6 +1058,9 @@
return FS_MGR_DOMNT_FAILED;
}
+ // Run fsck if needed
+ prepare_fs_for_mount(rec->blk_device, rec);
+
int ret = __mount(rec->blk_device, rec->mount_point, rec);
if (ret) {
ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
@@ -1177,8 +1186,8 @@
{
int ret;
- ret = mount("tmpfs", n_name, "tmpfs",
- MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS);
+ ret = mount("tmpfs", n_name, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV | MS_NOEXEC,
+ CRYPTO_TMPFS_OPTIONS);
if (ret < 0) {
LERROR << "Cannot mount tmpfs filesystem at " << n_name;
return -1;
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 05e03e1..a91e92e 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -80,13 +80,17 @@
}
static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
- const LpMetadataPartition& partition, std::string* path) {
+ const LpMetadataPartition& partition, bool force_writable,
+ std::string* path) {
DeviceMapper& dm = DeviceMapper::Instance();
DmTable table;
if (!CreateDmTable(block_device, metadata, partition, &table)) {
return false;
}
+ if (force_writable) {
+ table.set_readonly(false);
+ }
std::string name = GetPartitionName(partition);
if (!dm.CreateDevice(name, table)) {
return false;
@@ -106,8 +110,12 @@
return true;
}
for (const auto& partition : metadata->partitions) {
+ if (!partition.num_extents) {
+ LINFO << "Skipping zero-length logical partition: " << GetPartitionName(partition);
+ continue;
+ }
std::string path;
- if (!CreateLogicalPartition(block_device, *metadata.get(), partition, &path)) {
+ if (!CreateLogicalPartition(block_device, *metadata.get(), partition, false, &path)) {
LERROR << "Could not create logical partition: " << GetPartitionName(partition);
return false;
}
@@ -116,7 +124,8 @@
}
bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
- const std::string& partition_name, std::string* path) {
+ const std::string& partition_name, bool force_writable,
+ std::string* path) {
auto metadata = ReadMetadata(block_device.c_str(), metadata_slot);
if (!metadata) {
LOG(ERROR) << "Could not read partition table.";
@@ -124,7 +133,8 @@
}
for (const auto& partition : metadata->partitions) {
if (GetPartitionName(partition) == partition_name) {
- return CreateLogicalPartition(block_device, *metadata.get(), partition, path);
+ return CreateLogicalPartition(block_device, *metadata.get(), partition, force_writable,
+ path);
}
}
LERROR << "Could not find any partition with name: " << partition_name;
@@ -133,7 +143,11 @@
bool DestroyLogicalPartition(const std::string& name) {
DeviceMapper& dm = DeviceMapper::Instance();
- return dm.DeleteDevice(name);
+ if (!dm.DeleteDevice(name)) {
+ return false;
+ }
+ LINFO << "Unmapped logical partition " << name;
+ return true;
}
} // namespace fs_mgr
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 63a6839..845cca9 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -121,6 +121,7 @@
"-f",
"-O", "encrypt",
"-O", "quota",
+ "-O", "verity",
"-w", "4096",
fs_blkdev,
size_str.c_str(),
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 8b46d64..f87a3b1 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -117,21 +117,17 @@
#define EM_ICE 2
#define EM_AES_256_CTS 3
#define EM_AES_256_HEH 4
-#define EM_SPECK_128_256_XTS 5
-#define EM_SPECK_128_256_CTS 6
static const struct flag_list file_contents_encryption_modes[] = {
{"aes-256-xts", EM_AES_256_XTS},
- {"speck128/256-xts", EM_SPECK_128_256_XTS},
{"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
- {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
+ {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
{0, 0},
};
static const struct flag_list file_names_encryption_modes[] = {
{"aes-256-cts", EM_AES_256_CTS},
{"aes-256-heh", EM_AES_256_HEH},
- {"speck128/256-cts", EM_SPECK_128_256_CTS},
{0, 0},
};
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
new file mode 100644
index 0000000..74dfc00
--- /dev/null
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -0,0 +1,478 @@
+/*
+ * 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.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <linux/fs.h>
+#include <selinux/selinux.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <fs_mgr_overlayfs.h>
+#include <fstab/fstab.h>
+
+#include "fs_mgr_priv.h"
+
+using namespace std::literals;
+
+#if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs
+
+bool fs_mgr_overlayfs_mount_all() {
+ return false;
+}
+
+bool fs_mgr_overlayfs_setup(const char*, const char*, bool* change) {
+ if (change) *change = false;
+ return false;
+}
+
+bool fs_mgr_overlayfs_teardown(const char*, bool* change) {
+ if (change) *change = false;
+ return false;
+}
+
+#else // ALLOW_ADBD_DISABLE_VERITY == 0
+
+namespace {
+
+// acceptable overlayfs backing storage
+const auto kOverlayMountPoint = "/cache"s;
+
+// return true if everything is mounted, but before adb is started. At
+// 'trigger firmware_mounts_complete' after 'trigger load_persist_props_action'.
+bool fs_mgr_boot_completed() {
+ return !android::base::GetProperty("ro.boottime.init", "").empty() &&
+ !!access("/dev/.booting", F_OK);
+}
+
+bool fs_mgr_is_dir(const std::string& path) {
+ struct stat st;
+ return !stat(path.c_str(), &st) && S_ISDIR(st.st_mode);
+}
+
+// Similar test as overlayfs workdir= validation in the kernel for read-write
+// validation, except we use fs_mgr_work. Covers space and storage issues.
+bool fs_mgr_dir_is_writable(const std::string& path) {
+ auto test_directory = path + "/fs_mgr_work";
+ rmdir(test_directory.c_str());
+ auto ret = !mkdir(test_directory.c_str(), 0700);
+ return ret | !rmdir(test_directory.c_str());
+}
+
+std::string fs_mgr_get_context(const std::string& mount_point) {
+ char* ctx = nullptr;
+ auto len = getfilecon(mount_point.c_str(), &ctx);
+ if ((len > 0) && ctx) {
+ std::string context(ctx, len);
+ free(ctx);
+ return context;
+ }
+ return "";
+}
+
+bool fs_mgr_overlayfs_enabled(const struct fstab_rec* fsrec) {
+ // readonly filesystem, can not be mount -o remount,rw
+ return "squashfs"s == fsrec->fs_type;
+}
+
+constexpr char upper_name[] = "upper";
+constexpr char work_name[] = "work";
+
+std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) {
+ if (!fs_mgr_is_dir(mount_point)) return "";
+ auto dir = kOverlayMountPoint + "/overlay/" + android::base::Basename(mount_point) + "/";
+ auto upper = dir + upper_name;
+ if (!fs_mgr_is_dir(upper)) return "";
+ auto work = dir + work_name;
+ if (!fs_mgr_is_dir(work)) return "";
+ if (!fs_mgr_dir_is_writable(work)) return "";
+ return dir;
+}
+
+constexpr char lowerdir_option[] = "lowerdir=";
+constexpr char upperdir_option[] = "upperdir=";
+
+// default options for mount_point, returns empty string for none available.
+std::string fs_mgr_get_overlayfs_options(const char* mount_point) {
+ auto fsrec_mount_point = std::string(mount_point);
+ auto candidate = fs_mgr_get_overlayfs_candidate(fsrec_mount_point);
+ if (candidate.empty()) return "";
+
+ auto context = fs_mgr_get_context(fsrec_mount_point);
+ if (!context.empty()) context = ",rootcontext="s + context;
+ return "override_creds=off,"s + lowerdir_option + fsrec_mount_point + "," + upperdir_option +
+ candidate + upper_name + ",workdir=" + candidate + work_name + context;
+}
+
+bool fs_mgr_system_root_image(const fstab* fstab) {
+ if (!fstab) { // can not happen?
+ // This will return empty on init first_stage_mount,
+ // hence why we prefer checking the fstab instead.
+ return android::base::GetBoolProperty("ro.build.system_root_image", false);
+ }
+ for (auto i = 0; i < fstab->num_entries; i++) {
+ const auto fsrec = &fstab->recs[i];
+ auto fsrec_mount_point = fsrec->mount_point;
+ if (!fsrec_mount_point) continue;
+ if ("/system"s == fsrec_mount_point) return false;
+ }
+ return true;
+}
+
+std::string fs_mgr_get_overlayfs_options(const fstab* fstab, const char* mount_point) {
+ if (fs_mgr_system_root_image(fstab) && ("/"s == mount_point)) mount_point = "/system";
+
+ return fs_mgr_get_overlayfs_options(mount_point);
+}
+
+// return true if system supports overlayfs
+bool fs_mgr_wants_overlayfs() {
+ // This will return empty on init first_stage_mount, so speculative
+ // determination, empty (unset) _or_ "1" is true which differs from the
+ // official ro.debuggable policy. ALLOW_ADBD_DISABLE_VERITY == 0 should
+ // protect us from false in any case, so this is insurance.
+ auto debuggable = android::base::GetProperty("ro.debuggable", "1");
+ if (debuggable != "1") return false;
+
+ // Overlayfs available in the kernel, and patched for override_creds?
+ static signed char overlayfs_in_kernel = -1; // cache for constant condition
+ if (overlayfs_in_kernel == -1) {
+ overlayfs_in_kernel = !access("/sys/module/overlay/parameters/override_creds", F_OK);
+ }
+ return overlayfs_in_kernel;
+}
+
+bool fs_mgr_wants_overlayfs(const fstab_rec* fsrec) {
+ if (!fsrec) return false;
+
+ auto fsrec_mount_point = fsrec->mount_point;
+ if (!fsrec_mount_point) return false;
+
+ if (!fsrec->fs_type) return false;
+
+ // Don't check entries that are managed by vold.
+ if (fsrec->fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) return false;
+
+ // Only concerned with readonly partitions.
+ if (!(fsrec->flags & MS_RDONLY)) return false;
+
+ // If unbindable, do not allow overlayfs as this could expose us to
+ // security issues. On Android, this could also be used to turn off
+ // the ability to overlay an otherwise acceptable filesystem since
+ // /system and /vendor are never bound(sic) to.
+ if (fsrec->flags & MS_UNBINDABLE) return false;
+
+ if (!fs_mgr_overlayfs_enabled(fsrec)) return false;
+
+ // Verity enabled?
+ const auto basename_mount_point(android::base::Basename(fsrec_mount_point));
+ auto found = false;
+ fs_mgr_update_verity_state(
+ [&basename_mount_point, &found](fstab_rec*, const char* mount_point, int, int) {
+ if (mount_point && (basename_mount_point == mount_point)) found = true;
+ });
+ return !found;
+}
+
+bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr) {
+ auto save_errno = errno;
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
+ if (!dir) {
+ if (errno == ENOENT) {
+ errno = save_errno;
+ return true;
+ }
+ PERROR << "overlayfs open " << path;
+ return false;
+ }
+ dirent* entry;
+ auto ret = true;
+ while ((entry = readdir(dir.get()))) {
+ if (("."s == entry->d_name) || (".."s == entry->d_name)) continue;
+ auto file = path + "/" + entry->d_name;
+ if (entry->d_type == DT_UNKNOWN) {
+ struct stat st;
+ if (!lstat(file.c_str(), &st) && (st.st_mode & S_IFDIR)) entry->d_type = DT_DIR;
+ }
+ if (entry->d_type == DT_DIR) {
+ ret &= fs_mgr_rm_all(file, change);
+ if (!rmdir(file.c_str())) {
+ if (change) *change = true;
+ } else {
+ ret = false;
+ PERROR << "overlayfs rmdir " << file;
+ }
+ continue;
+ }
+ if (!unlink(file.c_str())) {
+ if (change) *change = true;
+ } else {
+ ret = false;
+ PERROR << "overlayfs rm " << file;
+ }
+ }
+ return ret;
+}
+
+bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& mount_point,
+ bool* change) {
+ auto ret = true;
+ auto fsrec_mount_point = overlay + android::base::Basename(mount_point) + "/";
+ auto save_errno = errno;
+ if (!mkdir(fsrec_mount_point.c_str(), 0755)) {
+ if (change) *change = true;
+ } else if (errno != EEXIST) {
+ ret = false;
+ PERROR << "overlayfs mkdir " << fsrec_mount_point;
+ } else {
+ errno = save_errno;
+ }
+
+ save_errno = errno;
+ if (!mkdir((fsrec_mount_point + work_name).c_str(), 0755)) {
+ if (change) *change = true;
+ } else if (errno != EEXIST) {
+ ret = false;
+ PERROR << "overlayfs mkdir " << fsrec_mount_point << work_name;
+ } else {
+ errno = save_errno;
+ }
+
+ auto new_context = fs_mgr_get_context(mount_point);
+ if (!new_context.empty() && setfscreatecon(new_context.c_str())) {
+ ret = false;
+ PERROR << "overlayfs setfscreatecon " << new_context;
+ }
+ auto upper = fsrec_mount_point + upper_name;
+ save_errno = errno;
+ if (!mkdir(upper.c_str(), 0755)) {
+ if (change) *change = true;
+ } else if (errno != EEXIST) {
+ ret = false;
+ PERROR << "overlayfs mkdir " << upper;
+ } else {
+ errno = save_errno;
+ }
+ if (!new_context.empty()) setfscreatecon(nullptr);
+
+ return ret;
+}
+
+bool fs_mgr_overlayfs_mount(const fstab* fstab, const fstab_rec* fsrec) {
+ if (!fs_mgr_wants_overlayfs(fsrec)) return false;
+ auto fsrec_mount_point = fsrec->mount_point;
+ if (!fsrec_mount_point || !fsrec_mount_point[0]) return false;
+ auto options = fs_mgr_get_overlayfs_options(fstab, fsrec_mount_point);
+ if (options.empty()) return false;
+
+ // hijack __mount() report format to help triage
+ auto report = "__mount(source=overlay,target="s + fsrec_mount_point + ",type=overlay";
+ const auto opt_list = android::base::Split(options, ",");
+ for (const auto opt : opt_list) {
+ if (android::base::StartsWith(opt, upperdir_option)) {
+ report = report + "," + opt;
+ break;
+ }
+ }
+ report = report + ")=";
+
+ auto ret = mount("overlay", fsrec_mount_point, "overlay", MS_RDONLY | MS_RELATIME,
+ options.c_str());
+ if (ret) {
+ PERROR << report << ret;
+ return false;
+ } else {
+ LINFO << report << ret;
+ return true;
+ }
+}
+
+bool fs_mgr_overlayfs_already_mounted(const char* mount_point) {
+ if (!mount_point) return false;
+ std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(
+ fs_mgr_read_fstab("/proc/mounts"), fs_mgr_free_fstab);
+ if (!fstab) return false;
+ const auto lowerdir = std::string(lowerdir_option) + mount_point;
+ for (auto i = 0; i < fstab->num_entries; ++i) {
+ const auto fsrec = &fstab->recs[i];
+ const auto fs_type = fsrec->fs_type;
+ if (!fs_type) continue;
+ if (("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
+ auto fsrec_mount_point = fsrec->mount_point;
+ if (!fsrec_mount_point) continue;
+ if (strcmp(fsrec_mount_point, mount_point)) continue;
+ const auto fs_options = fsrec->fs_options;
+ if (!fs_options) continue;
+ const auto options = android::base::Split(fs_options, ",");
+ for (const auto opt : options) {
+ if (opt == lowerdir) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+bool fs_mgr_overlayfs_mount_all() {
+ auto ret = false;
+
+ if (!fs_mgr_wants_overlayfs()) return ret;
+
+ std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ if (!fstab) return ret;
+
+ for (auto i = 0; i < fstab->num_entries; i++) {
+ const auto fsrec = &fstab->recs[i];
+ auto fsrec_mount_point = fsrec->mount_point;
+ if (!fsrec_mount_point) continue;
+ if (fs_mgr_overlayfs_already_mounted(fsrec_mount_point)) continue;
+
+ if (fs_mgr_overlayfs_mount(fstab.get(), fsrec)) ret = true;
+ }
+ return ret;
+}
+
+// Returns false if setup not permitted, errno set to last error.
+// If something is altered, set *change.
+bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) {
+ if (change) *change = false;
+ auto ret = false;
+ if (backing && (kOverlayMountPoint != backing)) {
+ errno = EINVAL;
+ return ret;
+ }
+ if (!fs_mgr_wants_overlayfs()) return ret;
+ if (!fs_mgr_boot_completed()) {
+ errno = EBUSY;
+ PERROR << "overlayfs setup";
+ return ret;
+ }
+
+ std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ std::vector<std::string> mounts;
+ if (fstab) {
+ if (!fs_mgr_get_entry_for_mount_point(fstab.get(), kOverlayMountPoint)) return ret;
+ for (auto i = 0; i < fstab->num_entries; i++) {
+ const auto fsrec = &fstab->recs[i];
+ auto fsrec_mount_point = fsrec->mount_point;
+ if (!fsrec_mount_point) continue;
+ if (mount_point && strcmp(fsrec_mount_point, mount_point)) continue;
+ if (!fs_mgr_wants_overlayfs(fsrec)) continue;
+ mounts.emplace_back(fsrec_mount_point);
+ }
+ if (mounts.empty()) return ret;
+ }
+
+ if (mount_point && ("/"s == mount_point) && fs_mgr_system_root_image(fstab.get())) {
+ mount_point = "/system";
+ }
+ auto overlay = kOverlayMountPoint + "/overlay/";
+ auto save_errno = errno;
+ if (!mkdir(overlay.c_str(), 0755)) {
+ if (change) *change = true;
+ } else if (errno != EEXIST) {
+ PERROR << "overlayfs mkdir " << overlay;
+ } else {
+ errno = save_errno;
+ }
+ if (!fstab && mount_point && fs_mgr_overlayfs_setup_one(overlay, mount_point, change)) {
+ ret = true;
+ }
+ for (const auto& fsrec_mount_point : mounts) {
+ ret |= fs_mgr_overlayfs_setup_one(overlay, fsrec_mount_point, change);
+ }
+ return ret;
+}
+
+// Returns false if teardown not permitted, errno set to last error.
+// If something is altered, set *change.
+bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) {
+ if (change) *change = false;
+ if (mount_point && ("/"s == mount_point)) {
+ std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(
+ fs_mgr_read_fstab_default(), fs_mgr_free_fstab);
+ if (fs_mgr_system_root_image(fstab.get())) mount_point = "/system";
+ }
+ auto ret = true;
+ const auto overlay = kOverlayMountPoint + "/overlay";
+ const auto oldpath = overlay + (mount_point ?: "");
+ const auto newpath = oldpath + ".teardown";
+ ret &= fs_mgr_rm_all(newpath);
+ auto save_errno = errno;
+ if (rename(oldpath.c_str(), newpath.c_str())) {
+ if (change) *change = true;
+ } else if (errno != ENOENT) {
+ ret = false;
+ PERROR << "overlayfs mv " << oldpath << " " << newpath;
+ } else {
+ errno = save_errno;
+ }
+ ret &= fs_mgr_rm_all(newpath, change);
+ save_errno = errno;
+ if (!rmdir(newpath.c_str())) {
+ if (change) *change = true;
+ } else if (errno != ENOENT) {
+ ret = false;
+ PERROR << "overlayfs rmdir " << newpath;
+ } else {
+ errno = save_errno;
+ }
+ if (mount_point) {
+ save_errno = errno;
+ if (!rmdir(overlay.c_str())) {
+ if (change) *change = true;
+ } else if ((errno != ENOENT) && (errno != ENOTEMPTY)) {
+ ret = false;
+ PERROR << "overlayfs rmdir " << overlay;
+ } else {
+ errno = save_errno;
+ }
+ }
+ if (!fs_mgr_wants_overlayfs()) {
+ // After obligatory teardown to make sure everything is clean, but if
+ // we didn't want overlayfs in the the first place, we do not want to
+ // waste time on a reboot (or reboot request message).
+ if (change) *change = false;
+ }
+ // And now that we did what we could, lets inform
+ // caller that there may still be more to do.
+ if (!fs_mgr_boot_completed()) {
+ errno = EBUSY;
+ PERROR << "overlayfs teardown";
+ ret = false;
+ }
+ return ret;
+}
+
+#endif // ALLOW_ADBD_DISABLE_VERITY != 0
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index afd7227..a347faf 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -45,7 +45,7 @@
#define PWARNING PLOG(WARNING) << FS_MGR_TAG
#define PERROR PLOG(ERROR) << FS_MGR_TAG
-#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
+#define CRYPTO_TMPFS_OPTIONS "size=512m,mode=0771,uid=1000,gid=1000"
/* fstab has the following format:
*
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index cac475c..f15c450 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -41,9 +41,11 @@
// Create a block device for a single logical partition, given metadata and
// the partition name. On success, a path to the partition's block device is
-// returned.
+// returned. If |force_writable| is true, the "readonly" flag will be ignored
+// so the partition can be flashed.
bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
- const std::string& partition_name, std::string* path);
+ const std::string& partition_name, bool force_writable,
+ std::string* path);
// Destroy the block device for a logical partition, by name.
bool DestroyLogicalPartition(const std::string& name);
diff --git a/init/watchdogd.h b/fs_mgr/include/fs_mgr_overlayfs.h
similarity index 60%
copy from init/watchdogd.h
copy to fs_mgr/include/fs_mgr_overlayfs.h
index 73f77d5..1d2ff03 100644
--- a/init/watchdogd.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -14,15 +14,11 @@
* limitations under the License.
*/
-#ifndef _INIT_WATCHDOGD_H_
-#define _INIT_WATCHDOGD_H_
+#pragma once
-namespace android {
-namespace init {
+#include <fstab/fstab.h>
-int watchdogd_main(int argc, char **argv);
-
-} // namespace init
-} // namespace android
-
-#endif
+bool fs_mgr_overlayfs_mount_all();
+bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
+ bool* change = nullptr);
+bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 9d710f9..2015e4d 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -48,10 +48,20 @@
PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
return false;
}
- if (ioctl(fd, BLKALIGNOFF, &device_info->alignment_offset) < 0) {
+
+ int alignment_offset;
+ if (ioctl(fd, BLKALIGNOFF, &alignment_offset) < 0) {
PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
return false;
}
+ int logical_block_size;
+ if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed";
+ return false;
+ }
+
+ device_info->alignment_offset = static_cast<uint32_t>(alignment_offset);
+ device_info->logical_block_size = static_cast<uint32_t>(logical_block_size);
return true;
#else
(void)block_device;
@@ -74,6 +84,19 @@
void Partition::AddExtent(std::unique_ptr<Extent>&& extent) {
size_ += extent->num_sectors() * LP_SECTOR_SIZE;
+
+ if (LinearExtent* new_extent = extent->AsLinearExtent()) {
+ if (!extents_.empty() && extents_.back()->AsLinearExtent() &&
+ extents_.back()->AsLinearExtent()->end_sector() == new_extent->physical_sector()) {
+ // If the previous extent can be merged into this new one, do so
+ // to avoid creating unnecessary extents.
+ LinearExtent* prev_extent = extents_.back()->AsLinearExtent();
+ extent = std::make_unique<LinearExtent>(
+ prev_extent->num_sectors() + new_extent->num_sectors(),
+ prev_extent->physical_sector());
+ extents_.pop_back();
+ }
+ }
extents_.push_back(std::move(extent));
}
@@ -82,11 +105,7 @@
extents_.clear();
}
-void Partition::ShrinkTo(uint64_t requested_size) {
- uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE);
- if (size_ <= aligned_size) {
- return;
- }
+void Partition::ShrinkTo(uint64_t aligned_size) {
if (aligned_size == 0) {
RemoveExtents();
return;
@@ -106,7 +125,7 @@
sectors_to_remove -= extent->num_sectors();
extents_.pop_back();
}
- DCHECK(size_ == requested_size);
+ DCHECK(size_ == aligned_size);
}
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device,
@@ -182,6 +201,7 @@
device_info_.alignment = geometry_.alignment;
device_info_.alignment_offset = geometry_.alignment_offset;
+ device_info_.logical_block_size = geometry_.logical_block_size;
return true;
}
@@ -205,6 +225,10 @@
LERROR << "Block device size must be a multiple of 512.";
return false;
}
+ if (device_info_.logical_block_size % LP_SECTOR_SIZE != 0) {
+ LERROR << "Logical block size must be a multiple of 512.";
+ return false;
+ }
if (device_info_.alignment_offset % LP_SECTOR_SIZE != 0) {
LERROR << "Alignment offset is not sector-aligned.";
return false;
@@ -248,6 +272,18 @@
return false;
}
+ // Finally, the size of the allocatable space must be a multiple of the
+ // logical block size. If we have no more free space after this
+ // computation, then we abort. Note that the last sector is inclusive,
+ // so we have to account for that.
+ uint64_t num_free_sectors = last_sector - first_sector + 1;
+ uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
+ if (num_free_sectors < sectors_per_block) {
+ LERROR << "Not enough space to allocate any partition tables.";
+ return false;
+ }
+ last_sector = first_sector + (num_free_sectors / sectors_per_block) * sectors_per_block - 1;
+
geometry_.first_logical_sector = first_sector;
geometry_.last_logical_sector = last_sector;
geometry_.metadata_max_size = metadata_max_size;
@@ -255,6 +291,7 @@
geometry_.alignment = device_info_.alignment;
geometry_.alignment_offset = device_info_.alignment_offset;
geometry_.block_device_size = device_info_.size;
+ geometry_.logical_block_size = device_info.logical_block_size;
return true;
}
@@ -290,13 +327,7 @@
}
}
-bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t requested_size) {
- // Align the space needed up to the nearest sector.
- uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE);
- if (partition->size() >= aligned_size) {
- return true;
- }
-
+bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size) {
// Figure out how much we need to allocate.
uint64_t space_needed = aligned_size - partition->size();
uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
@@ -307,95 +338,101 @@
uint64_t end;
Interval(uint64_t start, uint64_t end) : start(start), end(end) {}
+ uint64_t length() const { return end - start; }
bool operator<(const Interval& other) const { return start < other.start; }
};
- std::vector<Interval> intervals;
- // Collect all extents in the partition table.
+ // Collect all extents in the partition table, then sort them by starting
+ // sector.
+ std::vector<Interval> extents;
for (const auto& partition : partitions_) {
for (const auto& extent : partition->extents()) {
LinearExtent* linear = extent->AsLinearExtent();
if (!linear) {
continue;
}
- intervals.emplace_back(linear->physical_sector(),
- linear->physical_sector() + extent->num_sectors());
+ extents.emplace_back(linear->physical_sector(),
+ linear->physical_sector() + extent->num_sectors());
}
}
+ std::sort(extents.begin(), extents.end());
- // Sort extents by starting sector.
- std::sort(intervals.begin(), intervals.end());
+ // Convert the extent list into a list of gaps between the extents; i.e.,
+ // the list of ranges that are free on the disk.
+ std::vector<Interval> free_regions;
+ for (size_t i = 1; i < extents.size(); i++) {
+ const Interval& previous = extents[i - 1];
+ const Interval& current = extents[i];
+
+ uint64_t aligned = AlignSector(previous.end);
+ if (aligned >= current.start) {
+ // There is no gap between these two extents, try the next one.
+ // Note that we check with >= instead of >, since alignment may
+ // bump the ending sector past the beginning of the next extent.
+ continue;
+ }
+
+ // The new interval represents the free space starting at the end of
+ // the previous interval, and ending at the start of the next interval.
+ free_regions.emplace_back(aligned, current.start);
+ }
+
+ // Add a final interval representing the remainder of the free space.
+ uint64_t last_free_extent_start =
+ extents.empty() ? geometry_.first_logical_sector : extents.back().end;
+ last_free_extent_start = AlignSector(last_free_extent_start);
+ if (last_free_extent_start <= geometry_.last_logical_sector) {
+ free_regions.emplace_back(last_free_extent_start, geometry_.last_logical_sector + 1);
+ }
+
+ const uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
+ CHECK(sectors_needed % sectors_per_block == 0);
// Find gaps that we can use for new extents. Note we store new extents in a
// temporary vector, and only commit them if we are guaranteed enough free
// space.
std::vector<std::unique_ptr<LinearExtent>> new_extents;
- for (size_t i = 1; i < intervals.size(); i++) {
- const Interval& previous = intervals[i - 1];
- const Interval& current = intervals[i];
+ for (auto& region : free_regions) {
+ if (region.length() % sectors_per_block != 0) {
+ // This should never happen, because it would imply that we
+ // once allocated an extent that was not a multiple of the
+ // block size. That extent would be rejected by DM_TABLE_LOAD.
+ LERROR << "Region " << region.start << ".." << region.end
+ << " is not a multiple of the block size, " << sectors_per_block;
- if (previous.end >= current.start) {
- // There is no gap between these two extents, try the next one. Note that
- // extents may never overlap, but just for safety, we ignore them if they
- // do.
- DCHECK(previous.end == current.start);
- continue;
+ // If for some reason the final region is mis-sized we still want
+ // to be able to grow partitions. So just to be safe, round the
+ // region down to the nearest block.
+ region.end = region.start + (region.length() / sectors_per_block) * sectors_per_block;
+ if (!region.length()) {
+ continue;
+ }
}
- uint64_t aligned = AlignSector(previous.end);
- if (aligned >= current.start) {
- // After alignment, this extent is not usable.
- continue;
- }
+ uint64_t sectors = std::min(sectors_needed, region.length());
+ CHECK(sectors % sectors_per_block == 0);
- // This gap is enough to hold the remainder of the space requested, so we
- // can allocate what we need and return.
- if (current.start - aligned >= sectors_needed) {
- auto extent = std::make_unique<LinearExtent>(sectors_needed, aligned);
- sectors_needed -= extent->num_sectors();
- new_extents.push_back(std::move(extent));
+ auto extent = std::make_unique<LinearExtent>(sectors, region.start);
+ new_extents.push_back(std::move(extent));
+ sectors_needed -= sectors;
+ if (!sectors_needed) {
break;
}
-
- // This gap is not big enough to fit the remainder of the space requested,
- // so consume the whole thing and keep looking for more.
- auto extent = std::make_unique<LinearExtent>(current.start - aligned, aligned);
- sectors_needed -= extent->num_sectors();
- new_extents.push_back(std::move(extent));
}
-
- // If we still have more to allocate, take it from the remaining free space
- // in the allocatable region.
if (sectors_needed) {
- uint64_t first_sector;
- if (intervals.empty()) {
- first_sector = geometry_.first_logical_sector;
- } else {
- first_sector = intervals.back().end;
- }
- DCHECK(first_sector <= geometry_.last_logical_sector);
-
- // Note: After alignment, |first_sector| may be > the last usable sector.
- first_sector = AlignSector(first_sector);
-
- // Note: the last usable sector is inclusive.
- if (first_sector > geometry_.last_logical_sector ||
- geometry_.last_logical_sector + 1 - first_sector < sectors_needed) {
- LERROR << "Not enough free space to expand partition: " << partition->name();
- return false;
- }
- auto extent = std::make_unique<LinearExtent>(sectors_needed, first_sector);
- new_extents.push_back(std::move(extent));
+ LERROR << "Not enough free space to expand partition: " << partition->name();
+ return false;
}
+ // Everything succeeded, so commit the new extents.
for (auto& extent : new_extents) {
partition->AddExtent(std::move(extent));
}
return true;
}
-void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t requested_size) {
- partition->ShrinkTo(requested_size);
+void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t aligned_size) {
+ partition->ShrinkTo(aligned_size);
}
std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
@@ -455,6 +492,12 @@
void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info) {
device_info_.size = device_info.size;
+ // Note that if the logical block size changes, we're probably in trouble:
+ // we could have already built extents that will only work on the previous
+ // size.
+ DCHECK(partitions_.empty() ||
+ device_info_.logical_block_size == device_info.logical_block_size);
+
// The kernel does not guarantee these values are present, so we only
// replace existing values if the new values are non-zero.
if (device_info.alignment) {
@@ -465,5 +508,23 @@
}
}
+bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) {
+ // Align the space needed up to the nearest sector.
+ uint64_t aligned_size = AlignTo(requested_size, device_info_.logical_block_size);
+ uint64_t old_size = partition->size();
+
+ if (aligned_size > old_size) {
+ if (!GrowPartition(partition, aligned_size)) {
+ return false;
+ }
+ } else if (aligned_size < partition->size()) {
+ ShrinkPartition(partition, aligned_size);
+ }
+
+ LINFO << "Partition " << partition->name() << " will resize from " << old_size << " bytes to "
+ << aligned_size << " bytes";
+ return true;
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index b610fd4..da9c8f3 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -45,7 +45,7 @@
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
- EXPECT_EQ(builder->GrowPartition(system, 65536), true);
+ EXPECT_EQ(builder->ResizePartition(system, 65536), true);
EXPECT_EQ(system->size(), 65536);
ASSERT_EQ(system->extents().size(), 1);
@@ -55,24 +55,28 @@
// The first logical sector will be (4096+1024*2)/512 = 12.
EXPECT_EQ(extent->physical_sector(), 12);
- // Test growing to the same size.
- EXPECT_EQ(builder->GrowPartition(system, 65536), true);
+ // Test resizing to the same size.
+ EXPECT_EQ(builder->ResizePartition(system, 65536), true);
EXPECT_EQ(system->size(), 65536);
EXPECT_EQ(system->extents().size(), 1);
EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE);
- // Test growing to a smaller size.
- EXPECT_EQ(builder->GrowPartition(system, 0), true);
- EXPECT_EQ(system->size(), 65536);
+ // Test resizing to a smaller size.
+ EXPECT_EQ(builder->ResizePartition(system, 0), true);
+ EXPECT_EQ(system->size(), 0);
+ EXPECT_EQ(system->extents().size(), 0);
+ // Test resizing to a greater size.
+ builder->ResizePartition(system, 131072);
+ EXPECT_EQ(system->size(), 131072);
EXPECT_EQ(system->extents().size(), 1);
- EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE);
- // Test shrinking to a greater size.
- builder->ShrinkPartition(system, 131072);
- EXPECT_EQ(system->size(), 65536);
+ EXPECT_EQ(system->extents()[0]->num_sectors(), 131072 / LP_SECTOR_SIZE);
+ // Test resizing again, that the extents are merged together.
+ builder->ResizePartition(system, 1024 * 256);
+ EXPECT_EQ(system->size(), 1024 * 256);
EXPECT_EQ(system->extents().size(), 1);
- EXPECT_EQ(system->extents()[0]->num_sectors(), 65536 / LP_SECTOR_SIZE);
+ EXPECT_EQ(system->extents()[0]->num_sectors(), (1024 * 256) / LP_SECTOR_SIZE);
// Test shrinking within the same extent.
- builder->ShrinkPartition(system, 32768);
+ builder->ResizePartition(system, 32768);
EXPECT_EQ(system->size(), 32768);
EXPECT_EQ(system->extents().size(), 1);
extent = system->extents()[0]->AsLinearExtent();
@@ -81,7 +85,7 @@
EXPECT_EQ(extent->physical_sector(), 12);
// Test shrinking to 0.
- builder->ShrinkPartition(system, 0);
+ builder->ResizePartition(system, 0);
EXPECT_EQ(system->size(), 0);
EXPECT_EQ(system->extents().size(), 0);
}
@@ -92,12 +96,12 @@
// Test that we align up to one sector.
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
- EXPECT_EQ(builder->GrowPartition(system, 10000), true);
- EXPECT_EQ(system->size(), 10240);
+ EXPECT_EQ(builder->ResizePartition(system, 10000), true);
+ EXPECT_EQ(system->size(), 12288);
EXPECT_EQ(system->extents().size(), 1);
- builder->ShrinkPartition(system, 9000);
- EXPECT_EQ(system->size(), 9216);
+ builder->ResizePartition(system, 7000);
+ EXPECT_EQ(system->size(), 8192);
EXPECT_EQ(system->extents().size(), 1);
}
@@ -121,13 +125,13 @@
TEST(liblp, InternalAlignment) {
// Test the metadata fitting within alignment.
- BlockDeviceInfo device_info(1024 * 1024, 768 * 1024, 0);
+ BlockDeviceInfo device_info(1024 * 1024, 768 * 1024, 0, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 2);
ASSERT_NE(builder, nullptr);
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 1536);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2035);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 2031);
// Test a large alignment offset thrown in.
device_info.alignment_offset = 753664;
@@ -136,7 +140,7 @@
exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2035);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 2031);
// Alignment offset without alignment doesn't mean anything.
device_info.alignment = 0;
@@ -151,7 +155,7 @@
exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 78);
- EXPECT_EQ(exported->geometry.last_logical_sector, 1975);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 1973);
// Test a small alignment with no alignment offset.
device_info.alignment = 11 * 1024;
@@ -164,7 +168,7 @@
}
TEST(liblp, InternalPartitionAlignment) {
- BlockDeviceInfo device_info(512 * 1024 * 1024, 768 * 1024, 753664);
+ BlockDeviceInfo device_info(512 * 1024 * 1024, 768 * 1024, 753664, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 32 * 1024, 2);
Partition* a = builder->AddPartition("a", TEST_GUID, 0);
@@ -174,8 +178,8 @@
// Add a bunch of small extents to each, interleaving.
for (size_t i = 0; i < 10; i++) {
- ASSERT_TRUE(builder->GrowPartition(a, a->size() + 4096));
- ASSERT_TRUE(builder->GrowPartition(b, b->size() + 4096));
+ ASSERT_TRUE(builder->ResizePartition(a, a->size() + 4096));
+ ASSERT_TRUE(builder->ResizePartition(b, b->size() + 4096));
}
EXPECT_EQ(a->size(), 40960);
EXPECT_EQ(b->size(), 40960);
@@ -203,9 +207,9 @@
Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
- EXPECT_EQ(builder->GrowPartition(system, 1036288), true);
+ EXPECT_EQ(builder->ResizePartition(system, 1036288), true);
EXPECT_EQ(system->size(), 1036288);
- EXPECT_EQ(builder->GrowPartition(system, 1036289), false);
+ EXPECT_EQ(builder->ResizePartition(system, 1036289), false);
}
TEST(liblp, BuildComplex) {
@@ -215,9 +219,9 @@
Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
ASSERT_NE(vendor, nullptr);
- EXPECT_EQ(builder->GrowPartition(system, 65536), true);
- EXPECT_EQ(builder->GrowPartition(vendor, 32768), true);
- EXPECT_EQ(builder->GrowPartition(system, 98304), true);
+ EXPECT_EQ(builder->ResizePartition(system, 65536), true);
+ EXPECT_EQ(builder->ResizePartition(vendor, 32768), true);
+ EXPECT_EQ(builder->ResizePartition(system, 98304), true);
EXPECT_EQ(system->size(), 98304);
EXPECT_EQ(vendor->size(), 32768);
@@ -268,9 +272,9 @@
Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
ASSERT_NE(vendor, nullptr);
- EXPECT_EQ(builder->GrowPartition(system, 65536), true);
- EXPECT_EQ(builder->GrowPartition(vendor, 32768), true);
- EXPECT_EQ(builder->GrowPartition(system, 98304), true);
+ EXPECT_EQ(builder->ResizePartition(system, 65536), true);
+ EXPECT_EQ(builder->ResizePartition(vendor, 32768), true);
+ EXPECT_EQ(builder->ResizePartition(system, 98304), true);
unique_ptr<LpMetadata> exported = builder->Export();
EXPECT_NE(exported, nullptr);
@@ -323,9 +327,9 @@
Partition* vendor = builder->AddPartition("vendor", TEST_GUID2, LP_PARTITION_ATTR_READONLY);
ASSERT_NE(system, nullptr);
ASSERT_NE(vendor, nullptr);
- EXPECT_EQ(builder->GrowPartition(system, 65536), true);
- EXPECT_EQ(builder->GrowPartition(vendor, 32768), true);
- EXPECT_EQ(builder->GrowPartition(system, 98304), true);
+ EXPECT_EQ(builder->ResizePartition(system, 65536), true);
+ EXPECT_EQ(builder->ResizePartition(vendor, 32768), true);
+ EXPECT_EQ(builder->ResizePartition(system, 98304), true);
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
@@ -382,7 +386,7 @@
static const size_t kMetadataSize = 64 * 1024;
// No space to store metadata + geometry.
- BlockDeviceInfo device_info(kDiskSize, 0, 0);
+ BlockDeviceInfo device_info(kDiskSize, 0, 0, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
EXPECT_EQ(builder, nullptr);
@@ -391,8 +395,8 @@
builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
EXPECT_EQ(builder, nullptr);
- // Space for metadata + geometry + one free sector.
- device_info.size += LP_SECTOR_SIZE;
+ // Space for metadata + geometry + one free block.
+ device_info.size += device_info.logical_block_size;
builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
EXPECT_NE(builder, nullptr);
@@ -425,19 +429,21 @@
ASSERT_EQ(device_info.alignment % LP_SECTOR_SIZE, 0);
ASSERT_EQ(device_info.alignment_offset % LP_SECTOR_SIZE, 0);
ASSERT_LE(device_info.alignment_offset, INT_MAX);
+ ASSERT_EQ(device_info.logical_block_size % LP_SECTOR_SIZE, 0);
// Having an alignment offset > alignment doesn't really make sense.
ASSERT_LT(device_info.alignment_offset, device_info.alignment);
}
TEST(liblp, UpdateBlockDeviceInfo) {
- BlockDeviceInfo device_info(1024 * 1024, 4096, 1024);
+ BlockDeviceInfo device_info(1024 * 1024, 4096, 1024, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
EXPECT_EQ(builder->block_device_info().size, device_info.size);
EXPECT_EQ(builder->block_device_info().alignment, device_info.alignment);
EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
+ EXPECT_EQ(builder->block_device_info().logical_block_size, device_info.logical_block_size);
device_info.alignment = 0;
device_info.alignment_offset = 2048;
@@ -451,3 +457,27 @@
EXPECT_EQ(builder->block_device_info().alignment, 8192);
EXPECT_EQ(builder->block_device_info().alignment_offset, 2048);
}
+
+TEST(liblp, InvalidBlockSize) {
+ BlockDeviceInfo device_info(1024 * 1024, 0, 0, 513);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+ EXPECT_EQ(builder, nullptr);
+}
+
+TEST(liblp, AlignedExtentSize) {
+ BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+ ASSERT_NE(builder, nullptr);
+
+ Partition* partition = builder->AddPartition("system", TEST_GUID, 0);
+ ASSERT_NE(partition, nullptr);
+ ASSERT_TRUE(builder->ResizePartition(partition, 512));
+ EXPECT_EQ(partition->size(), 4096);
+}
+
+TEST(liblp, AlignedFreeSpace) {
+ // Only one sector free - at least one block is required.
+ BlockDeviceInfo device_info(10240, 0, 0, 4096);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 512, 1);
+ ASSERT_EQ(builder, nullptr);
+}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 8bde313..a35cf8e 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -32,11 +32,16 @@
// By default, partitions are aligned on a 1MiB boundary.
static const uint32_t kDefaultPartitionAlignment = 1024 * 1024;
+static const uint32_t kDefaultBlockSize = 4096;
struct BlockDeviceInfo {
- BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0) {}
- BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset)
- : size(size), alignment(alignment), alignment_offset(alignment_offset) {}
+ BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0), logical_block_size(0) {}
+ BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset,
+ uint32_t logical_block_size)
+ : size(size),
+ alignment(alignment),
+ alignment_offset(alignment_offset),
+ logical_block_size(logical_block_size) {}
// Size of the block device, in bytes.
uint64_t size;
// Optimal target alignment, in bytes. Partition extents will be aligned to
@@ -46,6 +51,8 @@
// |alignment_offset| on the target device is correctly aligned on its
// parent device. This value must be 0 or a multiple of 512.
uint32_t alignment_offset;
+ // Block size, for aligning extent sizes and partition sizes.
+ uint32_t logical_block_size;
};
// Abstraction around dm-targets that can be encoded into logical partition tables.
@@ -74,6 +81,7 @@
LinearExtent* AsLinearExtent() override { return this; }
uint64_t physical_sector() const { return physical_sector_; }
+ uint64_t end_sector() const { return physical_sector_ + num_sectors_; }
private:
uint64_t physical_sector_;
@@ -88,6 +96,8 @@
};
class Partition final {
+ friend class MetadataBuilder;
+
public:
Partition(const std::string& name, const std::string& guid, uint32_t attributes);
@@ -97,10 +107,6 @@
// Remove all extents from this partition.
void RemoveExtents();
- // Remove and/or shrink extents until the partition is the requested size.
- // See MetadataBuilder::ShrinkPartition for more information.
- void ShrinkTo(uint64_t requested_size);
-
const std::string& name() const { return name_; }
uint32_t attributes() const { return attributes_; }
const std::string& guid() const { return guid_; }
@@ -108,6 +114,8 @@
uint64_t size() const { return size_; }
private:
+ void ShrinkTo(uint64_t aligned_size);
+
std::string name_;
std::string guid_;
std::vector<std::unique_ptr<Extent>> extents_;
@@ -144,7 +152,7 @@
// size. This is a convenience method for tests.
static std::unique_ptr<MetadataBuilder> New(uint64_t blockdev_size, uint32_t metadata_max_size,
uint32_t metadata_slot_count) {
- BlockDeviceInfo device_info(blockdev_size, 0, 0);
+ BlockDeviceInfo device_info(blockdev_size, 0, 0, kDefaultBlockSize);
return New(device_info, metadata_max_size, metadata_slot_count);
}
@@ -162,29 +170,17 @@
// Find a partition by name. If no partition is found, nullptr is returned.
Partition* FindPartition(const std::string& name);
- // Grow a partition to the requested size. If the partition's size is already
- // greater or equal to the requested size, this will return true and the
- // partition table will not be changed. Otherwise, a greedy algorithm is
- // used to find free gaps in the partition table and allocate them for this
- // partition. If not enough space can be allocated, false is returned, and
- // the parition table will not be modified.
+ // Grow or shrink a partition to the requested size. This size will be
+ // rounded UP to the nearest block (512 bytes).
//
- // The size will be rounded UP to the nearest sector.
+ // When growing a partition, a greedy algorithm is used to find free gaps
+ // in the partition table and allocate them. If not enough space can be
+ // allocated, false is returned, and the parition table will not be
+ // modified.
//
// Note, this is an in-memory operation, and it does not alter the
// underlying filesystem or contents of the partition on disk.
- bool GrowPartition(Partition* partition, uint64_t requested_size);
-
- // Shrink a partition to the requested size. If the partition is already
- // smaller than the given size, this will return and the partition table
- // will not be changed. Otherwise, extents will be removed and/or shrunk
- // from the end of the partition until it is the requested size.
- //
- // The size will be rounded UP to the nearest sector.
- //
- // Note, this is an in-memory operation, and it does not alter the
- // underlying filesystem or contents of the partition on disk.
- void ShrinkPartition(Partition* partition, uint64_t requested_size);
+ bool ResizePartition(Partition* partition, uint64_t requested_size);
// Amount of space that can be allocated to logical partitions.
uint64_t AllocatableSpace() const;
@@ -198,7 +194,8 @@
MetadataBuilder();
bool Init(const BlockDeviceInfo& info, uint32_t metadata_max_size, uint32_t metadata_slot_count);
bool Init(const LpMetadata& metadata);
-
+ bool GrowPartition(Partition* partition, uint64_t aligned_size);
+ void ShrinkPartition(Partition* partition, uint64_t aligned_size);
uint64_t AlignSector(uint64_t sector);
LpMetadataGeometry geometry_;
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index e1323e1..52c80f7 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -136,6 +136,12 @@
* can be used to verify the geometry against a target device.
*/
uint64_t block_device_size;
+
+ /* 76: Logical block size of the super partition block device. This is the
+ * minimal alignment for partition and extent sizes, and it must be a
+ * multiple of LP_SECTOR_SIZE.
+ */
+ uint32_t logical_block_size;
} __attribute__((packed)) LpMetadataGeometry;
/* The logical partition metadata has a number of tables; they are described
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index bbbedc7..638f4b3 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -85,7 +85,7 @@
if (!system) {
return false;
}
- return builder->GrowPartition(system, 24 * 1024);
+ return builder->ResizePartition(system, 24 * 1024);
}
// Create a temporary disk and flash it with the default partition setup.
@@ -345,7 +345,7 @@
ASSERT_NE(partition, nullptr);
// Add one extent to any partition to fill up more space - we're at 508
// bytes after this, out of 512.
- ASSERT_TRUE(builder->GrowPartition(partition, 1024));
+ ASSERT_TRUE(builder->ResizePartition(partition, 1024));
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 4522275..6ef5124 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -26,6 +26,8 @@
#include "liblp/metadata_format.h"
#define LP_TAG "[liblp]"
+#define LWARN LOG(WARNING) << LP_TAG
+#define LINFO LOG(INFO) << LP_TAG
#define LERROR LOG(ERROR) << LP_TAG
#define PERROR PLOG(ERROR) << LP_TAG
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 092dbf1..7bf42ae 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -40,7 +40,8 @@
80000,
0,
0,
- 1024 * 1024};
+ 1024 * 1024,
+ 4096};
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 4096);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 4096 + 16384);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 4096 + 16384 * 2);
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 156319b..fc9d83f 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -304,7 +304,11 @@
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
return false;
}
- return FlashPartitionTable(fd, metadata, slot_number);
+ if (!FlashPartitionTable(fd, metadata, slot_number)) {
+ return false;
+ }
+ LWARN << "Flashed new logical partition geometry to " << block_device;
+ return true;
}
bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata,
@@ -314,7 +318,12 @@
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
return false;
}
- return UpdatePartitionTable(fd, metadata, slot_number);
+ if (!UpdatePartitionTable(fd, metadata, slot_number)) {
+ return false;
+ }
+ LINFO << "Updated logical partition table at slot " << slot_number << " on device "
+ << block_device;
+ return true;
}
bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) {
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
index 28f0b07..6d5d1ea 100644
--- a/gatekeeperd/Android.mk
+++ b/gatekeeperd/Android.mk
@@ -32,6 +32,7 @@
libbase \
libutils \
libcrypto \
+ libkeystore_aidl \
libkeystore_binder \
libhidlbase \
libhidltransport \
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index abb387c..5f3ce36 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -25,14 +25,15 @@
#include <unistd.h>
#include <memory>
+#include <android/security/IKeystoreService.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
#include <gatekeeper/password_handle.h> // for password_handle_t
#include <hardware/gatekeeper.h>
#include <hardware/hw_auth_token.h>
-#include <keystore/IKeystoreService.h>
#include <keystore/keystore.h> // For error code
+#include <keystore/keystore_return_types.h>
#include <log/log.h>
#include <utils/Log.h>
#include <utils/String16.h>
@@ -317,11 +318,15 @@
// TODO: cache service?
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
- sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+ sp<security::IKeystoreService> service =
+ interface_cast<security::IKeystoreService>(binder);
if (service != NULL) {
- auto ret = service->addAuthToken(*auth_token, *auth_token_length);
- if (!ret.isOk()) {
- ALOGE("Failure sending auth token to KeyStore: %" PRId32, int32_t(ret));
+ std::vector<uint8_t> auth_token_vector(*auth_token,
+ (*auth_token) + *auth_token_length);
+ int result = 0;
+ auto binder_result = service->addAuthToken(auth_token_vector, &result);
+ if (!binder_result.isOk() || !keystore::KeyStoreServiceReturnCode(result).isOk()) {
+ ALOGE("Failure sending auth token to KeyStore: %" PRId32, result);
}
} else {
ALOGE("Unable to communicate with KeyStore");
diff --git a/healthd/Android.bp b/healthd/Android.bp
index 7269b62..6b00f81 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -1,6 +1,7 @@
cc_library_headers {
name: "libhealthd_headers",
vendor_available: true,
+ recovery_available: true,
export_include_dirs: ["include"],
header_libs: ["libbatteryservice_headers"],
export_header_lib_headers: ["libbatteryservice_headers"],
@@ -9,7 +10,9 @@
cc_library_static {
name: "libbatterymonitor",
srcs: ["BatteryMonitor.cpp"],
+ cflags: ["-Wall", "-Werror"],
vendor_available: true,
+ recovery_available: true,
export_include_dirs: ["include"],
shared_libs: [
"libutils",
@@ -18,3 +21,66 @@
header_libs: ["libhealthd_headers"],
export_header_lib_headers: ["libhealthd_headers"],
}
+
+cc_defaults {
+ name: "android.hardware.health@2.0-service_defaults",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ static_libs: [
+ "android.hardware.health@2.0-impl",
+ "android.hardware.health@1.0-convert",
+ "libhealthservice",
+ "libhealthstoragedefault",
+ "libbatterymonitor",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "android.hardware.health@2.0",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.health@2.0-service",
+ defaults: ["android.hardware.health@2.0-service_defaults"],
+
+ vendor: true,
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.health@2.0-service.rc"],
+ srcs: [
+ "HealthServiceDefault.cpp",
+ ],
+
+ overrides: [
+ "healthd",
+ ]
+}
+
+cc_binary {
+ name: "healthd",
+ defaults: ["android.hardware.health@2.0-service_defaults"],
+
+ init_rc: ["healthd.rc"],
+ srcs: [
+ "HealthServiceHealthd.cpp",
+ ],
+ local_include_dirs: ["include"],
+
+ shared_libs: [
+ "android.hardware.health@1.0",
+ ],
+
+ vintf_fragments: [
+ "manifest_healthd.xml"
+ ],
+}
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 1244903..f7214c6 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -3,27 +3,6 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
- healthd_mode_android.cpp \
- BatteryPropertiesRegistrar.cpp
-
-LOCAL_MODULE := libhealthd_android
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
- $(LOCAL_PATH) \
- $(LOCAL_PATH)/include
-
-LOCAL_STATIC_LIBRARIES := \
- libbatterymonitor \
- libbatteryservice \
- libutils \
- libbase \
- libcutils \
- liblog \
- libc \
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
LOCAL_MODULE := libhealthd_draw
@@ -45,6 +24,8 @@
LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_OFFSET=0
endif
+LOCAL_HEADER_LIBRARIES := libbatteryservice_headers
+
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -68,6 +49,11 @@
$(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := \
+ android.hardware.health@2.0 \
+ android.hardware.health@2.0-impl \
+ android.hardware.health@1.0 \
+ android.hardware.health@1.0-convert \
+ libhealthstoragedefault \
libminui \
libpng \
libz \
@@ -92,7 +78,6 @@
endif
LOCAL_SRC_FILES := \
- healthd_common.cpp \
charger.cpp \
LOCAL_MODULE := charger
@@ -106,14 +91,17 @@
ifeq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
LOCAL_CFLAGS += -DCHARGER_NO_UI
endif
-ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
-LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
-endif
-ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
-LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
-endif
-LOCAL_STATIC_LIBRARIES := \
+CHARGER_STATIC_LIBRARIES := \
+ android.hardware.health@2.0-impl \
+ android.hardware.health@2.0 \
+ android.hardware.health@1.0 \
+ android.hardware.health@1.0-convert \
+ libhidltransport \
+ libhidlbase \
+ libhwbinder_noltopgo \
+ libhealthstoragedefault \
+ libvndksupport \
libhealthd_charger \
libhealthd_draw \
libbatterymonitor \
@@ -124,6 +112,8 @@
libm \
libc \
+LOCAL_STATIC_LIBRARIES := $(CHARGER_STATIC_LIBRARIES)
+
ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
LOCAL_STATIC_LIBRARIES += \
libminui \
@@ -144,6 +134,21 @@
include $(BUILD_EXECUTABLE)
+include $(CLEAR_VARS)
+LOCAL_MODULE := charger_test
+LOCAL_MODULE_TAGS := optional
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror -DCHARGER_TEST -DCHARGER_NO_UI
+LOCAL_STATIC_LIBRARIES := $(CHARGER_STATIC_LIBRARIES)
+LOCAL_SRC_FILES := \
+ charger.cpp \
+ charger_test.cpp \
+
+include $(BUILD_EXECUTABLE)
+
+CHARGER_STATIC_LIBRARIES :=
+
ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
define _add-charger-image
include $$(CLEAR_VARS)
@@ -171,41 +176,3 @@
_add-charger-image :=
_img_modules :=
endif # LOCAL_CHARGER_NO_UI
-
-### healthd ###
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- healthd_common.cpp \
- healthd.cpp \
-
-LOCAL_MODULE := healthd
-LOCAL_MODULE_TAGS := optional
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-
-ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
-LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
-endif
-ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
-LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
-endif
-
-LOCAL_STATIC_LIBRARIES := \
- libhealthd_android \
- libbatterymonitor \
- libbatteryservice \
- android.hardware.health@1.0-convert \
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libbase \
- libutils \
- libcutils \
- liblog \
- libm \
- libc \
- libhidlbase \
- libhidltransport \
- android.hardware.health@1.0 \
-
-include $(BUILD_EXECUTABLE)
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index fa79d0b..80c5afe 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -88,6 +88,10 @@
initBatteryProperties(&props);
}
+struct BatteryProperties getBatteryProperties(BatteryMonitor* batteryMonitor) {
+ return batteryMonitor->props;
+}
+
int BatteryMonitor::getBatteryStatus(const char* status) {
int ret;
struct sysfsStringEnumMap batteryStatusMap[] = {
@@ -531,12 +535,6 @@
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0) {
mHealthdConfig->batteryVoltagePath = path;
- } else {
- path.clear();
- path.appendFormat("%s/%s/batt_vol",
- POWER_SUPPLY_SYSFS_PATH, name);
- if (access(path, R_OK) == 0)
- mHealthdConfig->batteryVoltagePath = path;
}
}
@@ -586,12 +584,6 @@
name);
if (access(path, R_OK) == 0) {
mHealthdConfig->batteryTemperaturePath = path;
- } else {
- path.clear();
- path.appendFormat("%s/%s/batt_temp",
- POWER_SUPPLY_SYSFS_PATH, name);
- if (access(path, R_OK) == 0)
- mHealthdConfig->batteryTemperaturePath = path;
}
}
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
deleted file mode 100644
index e51a06d..0000000
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BatteryPropertiesRegistrar.h"
-#include <batteryservice/BatteryService.h>
-#include <batteryservice/IBatteryPropertiesListener.h>
-#include <batteryservice/IBatteryPropertiesRegistrar.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/PermissionCache.h>
-#include <private/android_filesystem_config.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-
-#include <healthd/healthd.h>
-
-namespace android {
-
-void BatteryPropertiesRegistrar::publish(
- const sp<BatteryPropertiesRegistrar>& service) {
- defaultServiceManager()->addService(String16("batteryproperties"), service);
-}
-
-void BatteryPropertiesRegistrar::notifyListeners(const struct BatteryProperties& props) {
- Vector<sp<IBatteryPropertiesListener> > listenersCopy;
-
- // Binder currently may service an incoming oneway transaction whenever an
- // outbound oneway call is made (if there is already a pending incoming
- // oneway call waiting). This is considered a bug and may change in the
- // future. For now, avoid recursive mutex lock while making outbound
- // calls by making a local copy of the current list of listeners.
- {
- Mutex::Autolock _l(mRegistrationLock);
- listenersCopy = mListeners;
- }
- for (size_t i = 0; i < listenersCopy.size(); i++) {
- listenersCopy[i]->batteryPropertiesChanged(props);
- }
-}
-
-void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {
- {
- if (listener == NULL)
- return;
- Mutex::Autolock _l(mRegistrationLock);
- // check whether this is a duplicate
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) {
- return;
- }
- }
-
- mListeners.add(listener);
- IInterface::asBinder(listener)->linkToDeath(this);
- }
- healthd_battery_update();
-}
-
-void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
- if (listener == NULL)
- return;
- Mutex::Autolock _l(mRegistrationLock);
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) {
- IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
- mListeners.removeAt(i);
- break;
- }
- }
-}
-
-status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty *val) {
- return healthd_get_property(id, val);
-}
-
-void BatteryPropertiesRegistrar::scheduleUpdate() {
- healthd_battery_update();
-}
-
-status_t BatteryPropertiesRegistrar::dump(int fd, const Vector<String16>& /*args*/) {
- IPCThreadState* self = IPCThreadState::self();
- const int pid = self->getCallingPid();
- const int uid = self->getCallingUid();
- if ((uid != AID_SHELL) &&
- !PermissionCache::checkPermission(
- String16("android.permission.DUMP"), pid, uid))
- return PERMISSION_DENIED;
-
- healthd_dump_battery_state(fd);
- return OK;
-}
-
-void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) {
- Mutex::Autolock _l(mRegistrationLock);
-
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) == who) {
- mListeners.removeAt(i);
- break;
- }
- }
-}
-
-} // namespace android
diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h
deleted file mode 100644
index 14e9145..0000000
--- a/healthd/BatteryPropertiesRegistrar.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
-#define HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
-
-#include <binder/IBinder.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-#include <batteryservice/BatteryService.h>
-#include <batteryservice/IBatteryPropertiesListener.h>
-#include <batteryservice/IBatteryPropertiesRegistrar.h>
-
-namespace android {
-
-class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar,
- public IBinder::DeathRecipient {
-public:
- void publish(const sp<BatteryPropertiesRegistrar>& service);
- void notifyListeners(const struct BatteryProperties& props);
- void scheduleUpdate();
-
-private:
- Mutex mRegistrationLock;
- Vector<sp<IBatteryPropertiesListener> > mListeners;
-
- void registerListener(const sp<IBatteryPropertiesListener>& listener);
- void unregisterListener(const sp<IBatteryPropertiesListener>& listener);
- status_t getProperty(int id, struct BatteryProperty *val);
- status_t dump(int fd, const Vector<String16>& args);
- void binderDied(const wp<IBinder>& who);
-};
-
-}; // namespace android
-
-#endif // HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
diff --git a/healthd/HealthServiceDefault.cpp b/healthd/HealthServiceDefault.cpp
new file mode 100644
index 0000000..89ecc2f
--- /dev/null
+++ b/healthd/HealthServiceDefault.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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 <health2/service.h>
+#include <healthd/healthd.h>
+
+void healthd_board_init(struct healthd_config*) {
+ // Implementation-defined init logic goes here.
+ // 1. config->periodic_chores_interval_* variables
+ // 2. config->battery*Path variables
+ // 3. config->energyCounter. In this implementation, energyCounter is not defined.
+
+ // use defaults
+}
+
+int healthd_board_battery_update(struct android::BatteryProperties*) {
+ // Implementation-defined update logic goes here. An implementation
+ // can make modifications to prop before broadcasting it to all callbacks.
+
+ // return 0 to log periodic polled battery status to kernel log
+ return 0;
+}
+
+int main() {
+ return health_service_main();
+}
diff --git a/healthd/HealthServiceHealthd.cpp b/healthd/HealthServiceHealthd.cpp
new file mode 100644
index 0000000..5fd2597
--- /dev/null
+++ b/healthd/HealthServiceHealthd.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "healthd"
+#include <android-base/logging.h>
+
+#include <android/hardware/health/1.0/IHealth.h>
+#include <android/hardware/health/1.0/types.h>
+#include <hal_conversion.h>
+#include <health2/service.h>
+#include <healthd/healthd.h>
+#include <hidl/HidlTransportSupport.h>
+
+using android::OK;
+using android::NAME_NOT_FOUND;
+using android::hardware::health::V1_0::HealthConfig;
+using android::hardware::health::V1_0::HealthInfo;
+using android::hardware::health::V1_0::Result;
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
+using android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
+using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+
+using IHealthLegacy = android::hardware::health::V1_0::IHealth;
+
+static android::sp<IHealthLegacy> gHealth_1_0;
+
+static int healthd_board_get_energy_counter(int64_t* energy) {
+ if (gHealth_1_0 == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+
+ Result result = Result::NOT_SUPPORTED;
+ gHealth_1_0->energyCounter([energy, &result](Result ret, int64_t energyOut) {
+ result = ret;
+ *energy = energyOut;
+ });
+
+ return result == Result::SUCCESS ? OK : NAME_NOT_FOUND;
+}
+
+void healthd_board_init(struct healthd_config* config) {
+ gHealth_1_0 = IHealthLegacy::getService();
+
+ if (gHealth_1_0 == nullptr) {
+ return;
+ }
+
+ HealthConfig halConfig{};
+ convertToHealthConfig(config, halConfig);
+ gHealth_1_0->init(halConfig, [config](const auto& halConfigOut) {
+ convertFromHealthConfig(halConfigOut, config);
+ // always redirect energy counter queries
+ config->energyCounter = healthd_board_get_energy_counter;
+ });
+ LOG(INFO) << LOG_TAG << ": redirecting calls to 1.0 health HAL";
+}
+
+// TODO(b/68724651): Move this function into healthd_mode_service_2_0_battery_update
+// with logthis returned.
+int healthd_board_battery_update(struct android::BatteryProperties* props) {
+ int logthis = 0;
+
+ if (gHealth_1_0 == nullptr) {
+ return logthis;
+ }
+
+ HealthInfo info;
+ convertToHealthInfo(props, info);
+ gHealth_1_0->update(info, [props, &logthis](int32_t ret, const auto& infoOut) {
+ logthis = ret;
+ convertFromHealthInfo(infoOut, props);
+ });
+
+ return logthis;
+}
+
+int main() {
+ return health_service_main("backup");
+}
diff --git a/healthd/android.hardware.health@2.0-service.rc b/healthd/android.hardware.health@2.0-service.rc
new file mode 100644
index 0000000..dca0ccc
--- /dev/null
+++ b/healthd/android.hardware.health@2.0-service.rc
@@ -0,0 +1,5 @@
+service health-hal-2-0 /vendor/bin/hw/android.hardware.health@2.0-service
+ class hal
+ user system
+ group system
+ file /dev/kmsg w
diff --git a/healthd/charger.cpp b/healthd/charger.cpp
index 5a8fe1a..43e7fd5 100644
--- a/healthd/charger.cpp
+++ b/healthd/charger.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "charger"
#define KLOG_LEVEL 6
+#include <health2/Health.h>
#include <healthd/healthd.h>
#include <stdlib.h>
@@ -62,7 +63,9 @@
};
#endif
-static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
+static void healthd_mode_nop_init(struct healthd_config* config) {
+ using android::hardware::health::V2_0::implementation::Health;
+ Health::initInstance(config);
}
static int healthd_mode_nop_preparetowait(void) {
@@ -76,7 +79,7 @@
struct android::BatteryProperties* /*props*/) {
}
-int main(int argc, char **argv) {
+int healthd_charger_main(int argc, char** argv) {
int ch;
healthd_mode_ops = &charger_ops;
@@ -100,3 +103,9 @@
return healthd_main();
}
+
+#ifndef CHARGER_TEST
+int main(int argc, char** argv) {
+ return healthd_charger_main(argc, argv);
+}
+#endif
diff --git a/healthd/charger_test.cpp b/healthd/charger_test.cpp
new file mode 100644
index 0000000..a7e2161
--- /dev/null
+++ b/healthd/charger_test.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "charger_test"
+#include <android/log.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <fstream>
+#include <iostream>
+#include <mutex>
+#include <streambuf>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <health2/Health.h>
+
+#define LOG_THIS(fmt, ...) \
+ ALOGE(fmt, ##__VA_ARGS__); \
+ printf(fmt "\n", ##__VA_ARGS__);
+
+template <typename T>
+class Atomic {
+ public:
+ Atomic(T&& init) : mValue(std::move(init)) {}
+ void set(T&& newVal) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mValue = std::move(newVal);
+ }
+ mChanged.notify_all();
+ }
+ bool waitFor(long ms, const T& expectVal) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ return mChanged.wait_for(lock, std::chrono::milliseconds(ms),
+ [this, &expectVal] { return mValue == expectVal; });
+ }
+ private:
+ std::mutex mMutex;
+ std::condition_variable mChanged;
+ T mValue;
+};
+
+Atomic<bool>& getUpdateNotifier() {
+ static Atomic<bool> val(false);
+ return val;
+}
+
+int energyCounter(int64_t* counter) {
+ *counter = 0xEC12345;
+ return 0;
+}
+
+const char* createFile(const char* path, const char* content) {
+ std::ofstream stream(path);
+ if (!stream.is_open()) {
+ LOG_THIS("Cannot create file %s", path);
+ return NULL;
+ }
+ stream << content << std::endl;
+ stream.close();
+ return path;
+}
+
+std::string openToString(const char* path) {
+ std::ifstream stream(path);
+ if (!stream.is_open()) {
+ LOG_THIS("Cannot open file %s", path);
+ return "";
+ }
+ return std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
+}
+
+int expectContains(const std::string& content, const std::vector<std::string>& fields) {
+ int status = 0;
+ for (const auto& field : fields) {
+ auto pos = content.find(field);
+ if (pos == std::string::npos) {
+ LOG_THIS("Cannot find substr '%s'", field.c_str());
+ status = 1;
+ }
+ }
+ return status;
+}
+
+::android::hardware::hidl_handle createHidlHandle(const char* filepath) {
+ int fd = creat(filepath, S_IRUSR | S_IWUSR);
+ if (fd < 0) return {};
+ native_handle_t* nativeHandle = native_handle_create(1, 0);
+ nativeHandle->data[0] = fd;
+ ::android::hardware::hidl_handle handle;
+ handle.setTo(nativeHandle, true /* shouldOwn */);
+ return handle;
+}
+
+void healthd_board_init(struct healthd_config* config) {
+ config->periodic_chores_interval_fast = 60;
+ config->periodic_chores_interval_slow = 600;
+
+ config->batteryStatusPath = createFile("/data/local/tmp/batteryStatus", "Not charging");
+ config->batteryHealthPath = createFile("/data/local/tmp/batteryHealth", "Unspecified failure");
+ config->batteryPresentPath = createFile("/data/local/tmp/batteryPresent", "1");
+ config->batteryCapacityPath = createFile("/data/local/tmp/batteryCapacity", "47");
+ config->batteryVoltagePath = createFile("/data/local/tmp/batteryVoltage", "45000");
+ config->batteryTemperaturePath = createFile("/data/local/tmp/batteryTemperature", "987");
+ config->batteryTechnologyPath = createFile("/data/local/tmp/batteryTechnology", "NiCd");
+ config->batteryCurrentNowPath = createFile("/data/local/tmp/batteryCurrentNow", "99000");
+ config->batteryCurrentAvgPath = createFile("/data/local/tmp/batteryCurrentAvg", "98000");
+ config->batteryChargeCounterPath = createFile("/data/local/tmp/batteryChargeCounter", "600");
+ config->batteryFullChargePath = createFile("/data/local/tmp/batteryFullCharge", "3515547");
+ config->batteryCycleCountPath = createFile("/data/local/tmp/batteryCycleCount", "77");
+
+ config->energyCounter = energyCounter;
+ config->boot_min_cap = 50;
+ config->screen_on = NULL;
+}
+
+int healthd_board_battery_update(struct android::BatteryProperties*) {
+ getUpdateNotifier().set(true /* updated */);
+
+ // return 0 to log periodic polled battery status to kernel log
+ return 0;
+}
+
+extern int healthd_charger_main(int argc, char** argv);
+
+int main(int argc, char** argv) {
+ using android::hardware::health::V2_0::implementation::Health;
+
+ const char* dumpFile = "/data/local/tmp/dump.txt";
+
+ std::thread bgThread([=] {
+ healthd_charger_main(argc, argv);
+ });
+
+ // wait for healthd_init to finish
+ if (!getUpdateNotifier().waitFor(1000 /* wait ms */, true /* updated */)) {
+ LOG_THIS("Time out.");
+ exit(1);
+ }
+
+ Health::getImplementation()->debug(createHidlHandle(dumpFile), {} /* options */);
+
+ std::string content = openToString(dumpFile);
+ int status = expectContains(content, {
+ "status: 4",
+ "health: 6",
+ "present: 1",
+ "level: 47",
+ "voltage: 45",
+ "temp: 987",
+ "current now: 99000",
+ "current avg: 98000",
+ "charge counter: 600",
+ "current now: 99",
+ "cycle count: 77",
+ "Full charge: 3515547"
+ });
+
+ if (status == 0) {
+ LOG_THIS("Test success.");
+ } else {
+ LOG_THIS("Actual dump:\n%s", content.c_str());
+ }
+
+ exit(status); // force bgThread to exit
+}
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
deleted file mode 100644
index ed1971a..0000000
--- a/healthd/healthd.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "healthd"
-#define KLOG_LEVEL 6
-
-#include <healthd/healthd.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <cutils/klog.h>
-
-#include <android/hardware/health/1.0/IHealth.h>
-#include <android/hardware/health/1.0/types.h>
-#include <hal_conversion.h>
-
-using namespace android;
-
-using IHealth = ::android::hardware::health::V1_0::IHealth;
-using Result = ::android::hardware::health::V1_0::Result;
-using HealthConfig = ::android::hardware::health::V1_0::HealthConfig;
-using HealthInfo = ::android::hardware::health::V1_0::HealthInfo;
-
-using ::android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
-using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
-using ::android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
-using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
-
-// device specific hal interface;
-static sp<IHealth> gHealth;
-
-// main healthd loop
-extern int healthd_main(void);
-
-// Android mode
-extern void healthd_mode_android_init(struct healthd_config *config);
-extern int healthd_mode_android_preparetowait(void);
-extern void healthd_mode_android_heartbeat(void);
-extern void healthd_mode_android_battery_update(
- struct android::BatteryProperties *props);
-
-static struct healthd_mode_ops android_ops = {
- .init = healthd_mode_android_init,
- .preparetowait = healthd_mode_android_preparetowait,
- .heartbeat = healthd_mode_android_heartbeat,
- .battery_update = healthd_mode_android_battery_update,
-};
-
-// default energy counter property redirect to talk to device
-// HAL
-static int healthd_board_get_energy_counter(int64_t *energy) {
-
- if (gHealth == nullptr) {
- return NAME_NOT_FOUND;
- }
-
- Result result = Result::NOT_SUPPORTED;
- gHealth->energyCounter([=, &result] (Result ret, int64_t energyOut) {
- result = ret;
- *energy = energyOut;
- });
-
- return result == Result::SUCCESS ? OK : NAME_NOT_FOUND;
-}
-
-void healthd_board_init(struct healthd_config *config) {
-
- // Initialize the board HAL - Equivalent of healthd_board_init(config)
- // in charger/recovery mode.
-
- gHealth = IHealth::getService();
- if (gHealth == nullptr) {
- KLOG_WARNING(LOG_TAG, "unable to get HAL interface, using defaults\n");
- return;
- }
-
- HealthConfig halConfig;
- convertToHealthConfig(config, halConfig);
- gHealth->init(halConfig, [=] (const auto &halConfigOut) {
- convertFromHealthConfig(halConfigOut, config);
- // always redirect energy counter queries
- config->energyCounter = healthd_board_get_energy_counter;
- });
-}
-
-int healthd_board_battery_update(struct android::BatteryProperties *props) {
- int logthis = 0;
-
- if (gHealth == nullptr) {
- return logthis;
- }
-
- HealthInfo info;
- convertToHealthInfo(props, info);
- gHealth->update(info,
- [=, &logthis] (int32_t ret, const auto &infoOut) {
- logthis = ret;
- convertFromHealthInfo(infoOut, props);
- });
-
- return logthis;
-}
-
-int main(int /*argc*/, char ** /*argv*/) {
-
- healthd_mode_ops = &android_ops;
-
- return healthd_main();
-}
diff --git a/healthd/healthd.rc b/healthd/healthd.rc
new file mode 100644
index 0000000..8e2ebb6
--- /dev/null
+++ b/healthd/healthd.rc
@@ -0,0 +1,4 @@
+service healthd /system/bin/healthd
+ class hal
+ critical
+ group root system wakelock
diff --git a/healthd/healthd_common.cpp b/healthd/healthd_common.cpp
deleted file mode 100644
index 6599919..0000000
--- a/healthd/healthd_common.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "healthd-common"
-#define KLOG_LEVEL 6
-
-#include <healthd/healthd.h>
-#include <healthd/BatteryMonitor.h>
-
-#include <errno.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <batteryservice/BatteryService.h>
-#include <cutils/klog.h>
-#include <cutils/uevent.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <utils/Errors.h>
-
-using namespace android;
-
-#ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST
- // Periodic chores fast interval in seconds
- #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
-#else
- #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST)
-#endif
-
-#ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW
- // Periodic chores fast interval in seconds
- #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
-#else
- #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
-#endif
-
-static struct healthd_config healthd_config = {
- .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
- .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
- .batteryStatusPath = String8(String8::kEmptyString),
- .batteryHealthPath = String8(String8::kEmptyString),
- .batteryPresentPath = String8(String8::kEmptyString),
- .batteryCapacityPath = String8(String8::kEmptyString),
- .batteryVoltagePath = String8(String8::kEmptyString),
- .batteryTemperaturePath = String8(String8::kEmptyString),
- .batteryTechnologyPath = String8(String8::kEmptyString),
- .batteryCurrentNowPath = String8(String8::kEmptyString),
- .batteryCurrentAvgPath = String8(String8::kEmptyString),
- .batteryChargeCounterPath = String8(String8::kEmptyString),
- .batteryFullChargePath = String8(String8::kEmptyString),
- .batteryCycleCountPath = String8(String8::kEmptyString),
- .energyCounter = NULL,
- .boot_min_cap = 0,
- .screen_on = NULL,
-};
-
-static int eventct;
-static int epollfd;
-
-#define POWER_SUPPLY_SUBSYSTEM "power_supply"
-
-// epoll_create() parameter is actually unused
-#define MAX_EPOLL_EVENTS 40
-static int uevent_fd;
-static int wakealarm_fd;
-
-// -1 for no epoll timeout
-static int awake_poll_interval = -1;
-
-static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
-
-static BatteryMonitor* gBatteryMonitor;
-
-struct healthd_mode_ops *healthd_mode_ops;
-
-int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
- struct epoll_event ev;
-
- ev.events = EPOLLIN;
-
- if (wakeup == EVENT_WAKEUP_FD)
- ev.events |= EPOLLWAKEUP;
-
- ev.data.ptr = (void *)handler;
- if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
- KLOG_ERROR(LOG_TAG,
- "epoll_ctl failed; errno=%d\n", errno);
- return -1;
- }
-
- eventct++;
- return 0;
-}
-
-static void wakealarm_set_interval(int interval) {
- struct itimerspec itval;
-
- if (wakealarm_fd == -1)
- return;
-
- wakealarm_wake_interval = interval;
-
- if (interval == -1)
- interval = 0;
-
- itval.it_interval.tv_sec = interval;
- itval.it_interval.tv_nsec = 0;
- itval.it_value.tv_sec = interval;
- itval.it_value.tv_nsec = 0;
-
- if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
- KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
-}
-
-status_t healthd_get_property(int id, struct BatteryProperty *val) {
- return gBatteryMonitor->getProperty(id, val);
-}
-
-void healthd_battery_update(void) {
- // Fast wake interval when on charger (watch for overheat);
- // slow wake interval when on battery (watch for drained battery).
-
- int new_wake_interval = gBatteryMonitor->update() ?
- healthd_config.periodic_chores_interval_fast :
- healthd_config.periodic_chores_interval_slow;
-
- if (new_wake_interval != wakealarm_wake_interval)
- wakealarm_set_interval(new_wake_interval);
-
- // During awake periods poll at fast rate. If wake alarm is set at fast
- // rate then just use the alarm; if wake alarm is set at slow rate then
- // poll at fast rate while awake and let alarm wake up at slow rate when
- // asleep.
-
- if (healthd_config.periodic_chores_interval_fast == -1)
- awake_poll_interval = -1;
- else
- awake_poll_interval =
- new_wake_interval == healthd_config.periodic_chores_interval_fast ?
- -1 : healthd_config.periodic_chores_interval_fast * 1000;
-}
-
-void healthd_dump_battery_state(int fd) {
- gBatteryMonitor->dumpState(fd);
- fsync(fd);
-}
-
-static void periodic_chores() {
- healthd_battery_update();
-}
-
-#define UEVENT_MSG_LEN 2048
-static void uevent_event(uint32_t /*epevents*/) {
- char msg[UEVENT_MSG_LEN+2];
- char *cp;
- int n;
-
- n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
- if (n <= 0)
- return;
- if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
- return;
-
- msg[n] = '\0';
- msg[n+1] = '\0';
- cp = msg;
-
- while (*cp) {
- if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
- healthd_battery_update();
- break;
- }
-
- /* advance to after the next \0 */
- while (*cp++)
- ;
- }
-}
-
-static void uevent_init(void) {
- uevent_fd = uevent_open_socket(64*1024, true);
-
- if (uevent_fd < 0) {
- KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
- return;
- }
-
- fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
- if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
- KLOG_ERROR(LOG_TAG,
- "register for uevent events failed\n");
-}
-
-static void wakealarm_event(uint32_t /*epevents*/) {
- unsigned long long wakeups;
-
- if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
- KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
- return;
- }
-
- periodic_chores();
-}
-
-static void wakealarm_init(void) {
- wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
- if (wakealarm_fd == -1) {
- KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
- return;
- }
-
- if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
- KLOG_ERROR(LOG_TAG,
- "Registration of wakealarm event failed\n");
-
- wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
-}
-
-static void healthd_mainloop(void) {
- int nevents = 0;
- while (1) {
- struct epoll_event events[eventct];
- int timeout = awake_poll_interval;
- int mode_timeout;
-
- /* Don't wait for first timer timeout to run periodic chores */
- if (!nevents)
- periodic_chores();
-
- healthd_mode_ops->heartbeat();
-
- mode_timeout = healthd_mode_ops->preparetowait();
- if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
- timeout = mode_timeout;
- nevents = epoll_wait(epollfd, events, eventct, timeout);
- if (nevents == -1) {
- if (errno == EINTR)
- continue;
- KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
- break;
- }
-
- for (int n = 0; n < nevents; ++n) {
- if (events[n].data.ptr)
- (*(void (*)(int))events[n].data.ptr)(events[n].events);
- }
- }
-
- return;
-}
-
-static int healthd_init() {
- epollfd = epoll_create(MAX_EPOLL_EVENTS);
- if (epollfd == -1) {
- KLOG_ERROR(LOG_TAG,
- "epoll_create failed; errno=%d\n",
- errno);
- return -1;
- }
-
- healthd_board_init(&healthd_config);
- healthd_mode_ops->init(&healthd_config);
- wakealarm_init();
- uevent_init();
- gBatteryMonitor = new BatteryMonitor();
- gBatteryMonitor->init(&healthd_config);
- return 0;
-}
-
-int healthd_main() {
- int ret;
-
- klog_set_level(KLOG_LEVEL);
-
- if (!healthd_mode_ops) {
- KLOG_ERROR("healthd ops not set, exiting\n");
- exit(1);
- }
-
- ret = healthd_init();
- if (ret) {
- KLOG_ERROR("Initialization failed, exiting\n");
- exit(2);
- }
-
- healthd_mainloop();
- KLOG_ERROR("Main loop terminated, exiting\n");
- return 3;
-}
diff --git a/healthd/healthd_mode_android.cpp b/healthd/healthd_mode_android.cpp
deleted file mode 100644
index c612313..0000000
--- a/healthd/healthd_mode_android.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "healthd-android"
-
-#include <healthd/healthd.h>
-#include "BatteryPropertiesRegistrar.h"
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <cutils/klog.h>
-#include <sys/epoll.h>
-
-using namespace android;
-
-static int gBinderFd;
-static sp<BatteryPropertiesRegistrar> gBatteryPropertiesRegistrar;
-
-void healthd_mode_android_battery_update(
- struct android::BatteryProperties *props) {
- if (gBatteryPropertiesRegistrar != NULL)
- gBatteryPropertiesRegistrar->notifyListeners(*props);
-
- return;
-}
-
-int healthd_mode_android_preparetowait(void) {
- IPCThreadState::self()->flushCommands();
- return -1;
-}
-
-void healthd_mode_android_heartbeat(void) {
-}
-
-static void binder_event(uint32_t /*epevents*/) {
- IPCThreadState::self()->handlePolledCommands();
-}
-
-void healthd_mode_android_init(struct healthd_config* /*config*/) {
- ProcessState::self()->setThreadPoolMaxThreadCount(0);
- IPCThreadState::self()->disableBackgroundScheduling(true);
- IPCThreadState::self()->setupPolling(&gBinderFd);
-
- if (gBinderFd >= 0) {
- if (healthd_register_event(gBinderFd, binder_event))
- KLOG_ERROR(LOG_TAG,
- "Register for binder events failed\n");
- }
-
- gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
- gBatteryPropertiesRegistrar->publish(gBatteryPropertiesRegistrar);
-}
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index f1fe5cd..56a9f86 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -49,6 +49,7 @@
#include "AnimationParser.h"
#include "healthd_draw.h"
+#include <health2/Health.h>
#include <healthd/healthd.h>
using namespace android;
@@ -612,6 +613,8 @@
}
void healthd_mode_charger_init(struct healthd_config* config) {
+ using android::hardware::health::V2_0::implementation::Health;
+
int ret;
charger* charger = &charger_state;
int i;
@@ -666,6 +669,10 @@
charger->next_screen_transition = -1;
charger->next_key_check = -1;
charger->next_pwr_check = -1;
+
+ // Initialize Health implementation (which initializes the internal BatteryMonitor).
+ Health::initInstance(config);
+
healthd_config = config;
charger->boot_min_cap = config->boot_min_cap;
}
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 97435c7..4d1d53f 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -42,6 +42,7 @@
int getChargeStatus();
status_t getProperty(int id, struct BatteryProperty *val);
void dumpState(int fd);
+ friend struct BatteryProperties getBatteryProperties(BatteryMonitor* batteryMonitor);
private:
struct healthd_config *mHealthdConfig;
diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h
index 17efbd6..c01e8d7 100644
--- a/healthd/include/healthd/healthd.h
+++ b/healthd/include/healthd/healthd.h
@@ -81,10 +81,6 @@
// Global helper functions
int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup = EVENT_NO_WAKEUP_FD);
-void healthd_battery_update();
-android::status_t healthd_get_property(int id,
- struct android::BatteryProperty *val);
-void healthd_dump_battery_state(int fd);
struct healthd_mode_ops {
void (*init)(struct healthd_config *config);
diff --git a/healthd/manifest_healthd.xml b/healthd/manifest_healthd.xml
new file mode 100644
index 0000000..097a7d8
--- /dev/null
+++ b/healthd/manifest_healthd.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.hardware.health</name>
+ <transport>hwbinder</transport>
+ <version>2.0</version>
+ <interface>
+ <name>IHealth</name>
+ <instance>backup</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/init/Android.bp b/init/Android.bp
index 660d586..84a78e2 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -92,6 +92,7 @@
cc_library_static {
name: "libinit",
+ recovery_available: true,
defaults: ["init_defaults"],
srcs: [
"action.cpp",
@@ -115,6 +116,7 @@
"property_service.cpp",
"property_type.cpp",
"reboot.cpp",
+ "reboot_utils.cpp",
"security.cpp",
"selinux.cpp",
"service.cpp",
@@ -127,7 +129,6 @@
"ueventd.cpp",
"ueventd_parser.cpp",
"util.cpp",
- "watchdogd.cpp",
],
whole_static_libs: ["libcap"],
header_libs: ["bootimg_headers"],
@@ -137,30 +138,21 @@
},
}
-/*
-This is not yet ready, see the below TODOs for what is missing
-
cc_binary {
- // TODO: Missing,
- //LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
- //LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
-
- name: "init",
+ name: "init_second_stage",
+ recovery_available: true,
+ stem: "init",
defaults: ["init_defaults"],
+ static_libs: ["libinit"],
required: [
"e2fsdroid",
"mke2fs",
"sload_f2fs",
"make_f2fs",
],
- static_executable: true,
srcs: ["main.cpp"],
- symlinks: [
- "sbin/ueventd",
- "sbin/watchdogd",
- ],
+ symlinks: ["ueventd"],
}
-*/
// Tests
// ------------------------------------------------------------------------------
diff --git a/init/Android.mk b/init/Android.mk
index d0cb820..d20509b 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -41,35 +41,35 @@
include $(CLEAR_VARS)
LOCAL_CPPFLAGS := $(init_cflags)
-LOCAL_SRC_FILES := main.cpp
+LOCAL_SRC_FILES := \
+ devices.cpp \
+ first_stage_mount.cpp \
+ init_first_stage.cpp \
+ reboot_utils.cpp \
+ selinux.cpp \
+ uevent_listener.cpp \
+ util.cpp \
-LOCAL_MODULE:= init
+LOCAL_MODULE := init
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
LOCAL_STATIC_LIBRARIES := \
- libinit \
- libbootloader_message \
libfs_mgr \
libfec \
libfec_rs \
- libhidl-gen-utils \
libsquashfs_utils \
liblogwrap \
libext4_utils \
libseccomp_policy \
libcrypto_utils \
libsparse \
- libprocessgroup \
libavb \
libkeyutils \
- libprotobuf-cpp-lite \
- libpropertyinfoserializer \
- libpropertyinfoparser \
liblp \
-
-shared_libs := \
libcutils \
libbase \
liblog \
@@ -77,28 +77,11 @@
libdl \
libz \
libselinux \
-
-ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
-# init is static executable for non-system-as-root devices, because the dynamic linker
-# and shared libs are not available before /system is mounted, but init has to run
-# before the partition is mounted.
-LOCAL_STATIC_LIBRARIES += $(shared_libs) libc++_static
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-else
-LOCAL_SHARED_LIBRARIES := $(shared_libs) libc++
-endif
-shared_libs :=
+ libcap \
LOCAL_REQUIRED_MODULES := \
- e2fsdroid \
- mke2fs \
- sload_f2fs \
- make_f2fs \
-
-# Create symlinks.
-LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
- ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
- ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
+ init_second_stage \
+ init_second_stage.recovery \
LOCAL_SANITIZE := signed-integer-overflow
include $(BUILD_EXECUTABLE)
diff --git a/init/devices.cpp b/init/devices.cpp
index ed4a739..58c8b2e 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -34,7 +34,7 @@
#include "util.h"
#ifdef _INIT_INIT_H
-#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
+#error "Do not include init.h in files used by ueventd; it will expose init's globals"
#endif
using android::base::Basename;
@@ -372,7 +372,7 @@
}
}
-void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
+void DeviceHandler::HandleUevent(const Uevent& uevent) {
if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
FixupSysPermissions(uevent.path, uevent.subsystem);
}
@@ -418,6 +418,10 @@
HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
}
+void DeviceHandler::ColdbootDone() {
+ skip_restorecon_ = true;
+}
+
DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
std::vector<SysfsPermissions> sysfs_permissions,
std::vector<Subsystem> subsystems, std::set<std::string> boot_devices,
diff --git a/init/devices.h b/init/devices.h
index 0be660f..9d39eaa 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -29,6 +29,7 @@
#include <selinux/label.h>
#include "uevent.h"
+#include "uevent_handler.h"
namespace android {
namespace init {
@@ -105,7 +106,7 @@
std::string dir_name_ = "/dev";
};
-class DeviceHandler {
+class DeviceHandler : public UeventHandler {
public:
friend class DeviceHandlerTester;
@@ -113,11 +114,12 @@
DeviceHandler(std::vector<Permissions> dev_permissions,
std::vector<SysfsPermissions> sysfs_permissions, std::vector<Subsystem> subsystems,
std::set<std::string> boot_devices, bool skip_restorecon);
+ virtual ~DeviceHandler() = default;
- void HandleDeviceEvent(const Uevent& uevent);
+ void HandleUevent(const Uevent& uevent) override;
+ void ColdbootDone() override;
std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
- void set_skip_restorecon(bool value) { skip_restorecon_ = value; }
private:
bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index 28bda34..740e82c 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -35,8 +35,6 @@
namespace android {
namespace init {
-std::vector<std::string> firmware_directories;
-
static void LoadFirmware(const Uevent& uevent, const std::string& root, int fw_fd, size_t fw_size,
int loading_fd, int data_fd) {
// Start transfer.
@@ -58,7 +56,10 @@
return access("/dev/.booting", F_OK) == 0;
}
-static void ProcessFirmwareEvent(const Uevent& uevent) {
+FirmwareHandler::FirmwareHandler(std::vector<std::string> firmware_directories)
+ : firmware_directories_(std::move(firmware_directories)) {}
+
+void FirmwareHandler::ProcessFirmwareEvent(const Uevent& uevent) {
int booting = IsBooting();
LOG(INFO) << "firmware: loading '" << uevent.firmware << "' for '" << uevent.path << "'";
@@ -80,7 +81,7 @@
}
try_loading_again:
- for (const auto& firmware_directory : firmware_directories) {
+ for (const auto& firmware_directory : firmware_directories_) {
std::string file = firmware_directory + uevent.firmware;
unique_fd fw_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
struct stat sb;
@@ -104,7 +105,7 @@
write(loading_fd, "-1", 2);
}
-void HandleFirmwareEvent(const Uevent& uevent) {
+void FirmwareHandler::HandleUevent(const Uevent& uevent) {
if (uevent.subsystem != "firmware" || uevent.action != "add") return;
// Loading the firmware in a child means we can do that in parallel...
diff --git a/init/firmware_handler.h b/init/firmware_handler.h
index 6081511..3996096 100644
--- a/init/firmware_handler.h
+++ b/init/firmware_handler.h
@@ -21,13 +21,23 @@
#include <vector>
#include "uevent.h"
+#include "uevent_handler.h"
namespace android {
namespace init {
-extern std::vector<std::string> firmware_directories;
+class FirmwareHandler : public UeventHandler {
+ public:
+ explicit FirmwareHandler(std::vector<std::string> firmware_directories);
+ virtual ~FirmwareHandler() = default;
-void HandleFirmwareEvent(const Uevent& uevent);
+ void HandleUevent(const Uevent& uevent) override;
+
+ private:
+ void ProcessFirmwareEvent(const Uevent& uevent);
+
+ std::vector<std::string> firmware_directories_;
+};
} // namespace init
} // namespace android
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 43075b2..0c5cf76 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -35,6 +35,7 @@
#include "fs_mgr.h"
#include "fs_mgr_avb.h"
#include "fs_mgr_dm_linear.h"
+#include "fs_mgr_overlayfs.h"
#include "uevent.h"
#include "uevent_listener.h"
#include "util.h"
@@ -206,7 +207,7 @@
bool found = false;
auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
if (uevent.path == dm_path) {
- device_handler_->HandleDeviceEvent(uevent);
+ device_handler_->HandleUevent(uevent);
found = true;
return ListenerAction::kStop;
}
@@ -273,7 +274,7 @@
lp_metadata_partition_ = links[0];
}
required_devices_partition_names_.erase(iter);
- device_handler_->HandleDeviceEvent(uevent);
+ device_handler_->HandleUevent(uevent);
if (required_devices_partition_names_.empty()) {
return ListenerAction::kStop;
} else {
@@ -310,7 +311,7 @@
auto verity_callback = [&device_name, &dm_device, this, &found](const Uevent& uevent) {
if (uevent.device_name == device_name) {
LOG(VERBOSE) << "Creating device-mapper device : " << dm_device;
- device_handler_->HandleDeviceEvent(uevent);
+ device_handler_->HandleUevent(uevent);
found = true;
return ListenerAction::kStop;
}
@@ -351,6 +352,7 @@
return false;
}
}
+ fs_mgr_overlayfs_mount_all();
return true;
}
diff --git a/init/host_init_stubs.cpp b/init/host_init_stubs.cpp
index 2352fc7..8866bdc 100644
--- a/init/host_init_stubs.cpp
+++ b/init/host_init_stubs.cpp
@@ -41,10 +41,9 @@
}
// selinux.h
-bool SelinuxHasVendorInit() {
- return true;
+int SelinuxGetVendorAndroidVersion() {
+ return 10000;
}
-
void SelabelInitialize() {}
bool SelabelLookupFileContext(const std::string& key, int type, std::string* result) {
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index f0e1f07..0af11f6 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -23,6 +23,9 @@
#include <string>
+// android/api-level.h
+#define __ANDROID_API_P__ 28
+
// sys/system_properties.h
#define PROP_VALUE_MAX 92
@@ -41,7 +44,7 @@
const std::string& source_context, const ucred& cr, std::string* error);
// selinux.h
-bool SelinuxHasVendorInit();
+int SelinuxGetVendorAndroidVersion();
void SelabelInitialize();
bool SelabelLookupFileContext(const std::string& key, int type, std::string* result);
diff --git a/init/init.cpp b/init/init.cpp
index 73194bd..b550f1b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,15 +18,12 @@
#include <dirent.h>
#include <fcntl.h>
-#include <paths.h>
#include <pthread.h>
-#include <seccomp_policy.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/signalfd.h>
-#include <sys/sysmacros.h>
#include <sys/types.h>
#include <unistd.h>
@@ -43,8 +40,6 @@
#include <cutils/android_reboot.h>
#include <keyutils.h>
#include <libavb/libavb.h>
-#include <private/android_filesystem_config.h>
-#include <selinux/android.h>
#include "action_parser.h"
#include "epoll.h"
@@ -53,12 +48,12 @@
#include "keychords.h"
#include "property_service.h"
#include "reboot.h"
+#include "reboot_utils.h"
#include "security.h"
#include "selinux.h"
#include "sigchld_handler.h"
#include "ueventd.h"
#include "util.h"
-#include "watchdogd.h"
using namespace std::chrono_literals;
using namespace std::string_literals;
@@ -418,14 +413,6 @@
return Success();
}
-static void global_seccomp() {
- import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
- if (key == "androidboot.seccomp" && value == "global" && !set_global_seccomp_filter()) {
- LOG(FATAL) << "Failed to globally enable seccomp!";
- }
- });
-}
-
// Set the UDC controller for the ConfigFS USB Gadgets.
// Read the UDC controller in use from "/sys/class/udc".
// In case of multiple UDC controllers select the first one.
@@ -442,40 +429,6 @@
}
}
-static void InstallRebootSignalHandlers() {
- // Instead of panic'ing the kernel as is the default behavior when init crashes,
- // we prefer to reboot to bootloader on development builds, as this will prevent
- // boot looping bad configurations and allow both developers and test farms to easily
- // recover.
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- sigfillset(&action.sa_mask);
- action.sa_handler = [](int signal) {
- // These signal handlers are also caught for processes forked from init, however we do not
- // want them to trigger reboot, so we directly call _exit() for children processes here.
- if (getpid() != 1) {
- _exit(signal);
- }
-
- // Calling DoReboot() or LOG(FATAL) is not a good option as this is a signal handler.
- // RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option
- // and probably good enough given this is already an error case and only enabled for
- // development builds.
- RebootSystem(ANDROID_RB_RESTART2, "bootloader");
- };
- action.sa_flags = SA_RESTART;
- sigaction(SIGABRT, &action, nullptr);
- sigaction(SIGBUS, &action, nullptr);
- sigaction(SIGFPE, &action, nullptr);
- sigaction(SIGILL, &action, nullptr);
- sigaction(SIGSEGV, &action, nullptr);
-#if defined(SIGSTKFLT)
- sigaction(SIGSTKFLT, &action, nullptr);
-#endif
- sigaction(SIGSYS, &action, nullptr);
- sigaction(SIGTRAP, &action, nullptr);
-}
-
static void HandleSigtermSignal(const signalfd_siginfo& siginfo) {
if (siginfo.ssi_pid != 0) {
// Drop any userspace SIGTERM requests.
@@ -617,10 +570,6 @@
return ueventd_main(argc, argv);
}
- if (!strcmp(basename(argv[0]), "watchdogd")) {
- return watchdogd_main(argc, argv);
- }
-
if (argc > 1 && !strcmp(argv[1], "subcontext")) {
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap function_map;
@@ -631,106 +580,6 @@
InstallRebootSignalHandlers();
}
- bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
-
- if (is_first_stage) {
- boot_clock::time_point start_time = boot_clock::now();
-
- std::vector<std::pair<std::string, int>> errors;
-#define CHECKCALL(x) \
- if (x != 0) errors.emplace_back(#x " failed", errno);
-
- // Clear the umask.
- umask(0);
-
- CHECKCALL(clearenv());
- CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
- // Get the basic filesystem setup we need put together in the initramdisk
- // on / and then we'll let the rc file figure out the rest.
- CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
- CHECKCALL(mkdir("/dev/pts", 0755));
- CHECKCALL(mkdir("/dev/socket", 0755));
- CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
-#define MAKE_STR(x) __STRING(x)
- CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
-#undef MAKE_STR
- // Don't expose the raw commandline to unprivileged processes.
- CHECKCALL(chmod("/proc/cmdline", 0440));
- gid_t groups[] = { AID_READPROC };
- CHECKCALL(setgroups(arraysize(groups), groups));
- CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
- CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
-
- CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
-
- if constexpr (WORLD_WRITABLE_KMSG) {
- CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
- }
-
- CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
- CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
-
- // Mount staging areas for devices managed by vold
- // See storage config details at http://source.android.com/devices/storage/
- CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
- "mode=0755,uid=0,gid=1000"));
- // /mnt/vendor is used to mount vendor-specific partitions that can not be
- // part of the vendor partition, e.g. because they are mounted read-write.
- CHECKCALL(mkdir("/mnt/vendor", 0755));
- // /mnt/product is used to mount product-specific partitions that can not be
- // part of the product partition, e.g. because they are mounted read-write.
- CHECKCALL(mkdir("/mnt/product", 0755));
-
-#undef CHECKCALL
-
- // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
- // talk to the outside world...
- InitKernelLogging(argv);
-
- if (!errors.empty()) {
- for (const auto& [error_string, error_errno] : errors) {
- LOG(ERROR) << error_string << " " << strerror(error_errno);
- }
- LOG(FATAL) << "Init encountered errors starting first stage, aborting";
- }
-
- LOG(INFO) << "init first stage started!";
-
- if (!DoFirstStageMount()) {
- LOG(FATAL) << "Failed to mount required partitions early ...";
- }
-
- SetInitAvbVersionInRecovery();
-
- // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
- global_seccomp();
-
- // Set up SELinux, loading the SELinux policy.
- SelinuxSetupKernelLogging();
- SelinuxInitialize();
-
- // We're in the kernel domain, so re-exec init to transition to the init domain now
- // that the SELinux policy has been loaded.
- if (selinux_android_restorecon("/init", 0) == -1) {
- PLOG(FATAL) << "restorecon failed of /init failed";
- }
-
- setenv("INIT_SECOND_STAGE", "true", 1);
-
- static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
- uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
- setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
-
- char* path = argv[0];
- char* args[] = { path, nullptr };
- execv(path, args);
-
- // execv() only returns if an error happened, in which case we
- // panic and never fall through this conditional.
- PLOG(FATAL) << "execv(\"" << path << "\") failed";
- }
-
- // At this point we're in the second stage of init.
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
@@ -762,7 +611,6 @@
if (avb_version) property_set("ro.boot.avb_version", avb_version);
// Clean up our environment.
- unsetenv("INIT_SECOND_STAGE");
unsetenv("INIT_STARTED_AT");
unsetenv("INIT_SELINUX_TOOK");
unsetenv("INIT_AVB_VERSION");
diff --git a/init/init.h b/init/init.h
index 6c82fa1..f244ad7 100644
--- a/init/init.h
+++ b/init/init.h
@@ -31,8 +31,8 @@
namespace android {
namespace init {
-// Note: These globals are *only* valid in init, so they should not be used in ueventd,
-// watchdogd, or any files that may be included in those, such as devices.cpp and util.cpp.
+// Note: These globals are *only* valid in init, so they should not be used in ueventd
+// or any files that may be included in ueventd, such as devices.cpp and util.cpp.
// TODO: Have an Init class and remove all globals.
extern std::string default_console;
extern std::vector<std::string> late_import_paths;
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
new file mode 100644
index 0000000..466cde3
--- /dev/null
+++ b/init/init_first_stage.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+#include <paths.h>
+#include <seccomp_policy.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <cutils/android_reboot.h>
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+
+#include "first_stage_mount.h"
+#include "reboot_utils.h"
+#include "selinux.h"
+#include "util.h"
+
+using android::base::boot_clock;
+
+namespace android {
+namespace init {
+
+static void GlobalSeccomp() {
+ import_kernel_cmdline(false, [](const std::string& key, const std::string& value,
+ bool in_qemu) {
+ if (key == "androidboot.seccomp" && value == "global" && !set_global_seccomp_filter()) {
+ LOG(FATAL) << "Failed to globally enable seccomp!";
+ }
+ });
+}
+
+int main(int argc, char** argv) {
+ if (REBOOT_BOOTLOADER_ON_PANIC) {
+ InstallRebootSignalHandlers();
+ }
+
+ boot_clock::time_point start_time = boot_clock::now();
+
+ std::vector<std::pair<std::string, int>> errors;
+#define CHECKCALL(x) \
+ if (x != 0) errors.emplace_back(#x " failed", errno);
+
+ // Clear the umask.
+ umask(0);
+
+ CHECKCALL(clearenv());
+ CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
+ // Get the basic filesystem setup we need put together in the initramdisk
+ // on / and then we'll let the rc file figure out the rest.
+ CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
+ CHECKCALL(mkdir("/dev/pts", 0755));
+ CHECKCALL(mkdir("/dev/socket", 0755));
+ CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
+#define MAKE_STR(x) __STRING(x)
+ CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
+#undef MAKE_STR
+ // Don't expose the raw commandline to unprivileged processes.
+ CHECKCALL(chmod("/proc/cmdline", 0440));
+ gid_t groups[] = {AID_READPROC};
+ CHECKCALL(setgroups(arraysize(groups), groups));
+ CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
+ CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
+
+ CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
+
+ if constexpr (WORLD_WRITABLE_KMSG) {
+ CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
+ }
+
+ CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
+ CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
+
+ // This is needed for log wrapper, which gets called before ueventd runs.
+ CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
+ CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
+
+ // Mount staging areas for devices managed by vold
+ // See storage config details at http://source.android.com/devices/storage/
+ CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+ "mode=0755,uid=0,gid=1000"));
+ // /mnt/vendor is used to mount vendor-specific partitions that can not be
+ // part of the vendor partition, e.g. because they are mounted read-write.
+ CHECKCALL(mkdir("/mnt/vendor", 0755));
+ // /mnt/product is used to mount product-specific partitions that can not be
+ // part of the product partition, e.g. because they are mounted read-write.
+ CHECKCALL(mkdir("/mnt/product", 0755));
+
+#undef CHECKCALL
+
+ // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
+ // talk to the outside world...
+ android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
+ RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+ });
+
+ if (!errors.empty()) {
+ for (const auto& [error_string, error_errno] : errors) {
+ LOG(ERROR) << error_string << " " << strerror(error_errno);
+ }
+ LOG(FATAL) << "Init encountered errors starting first stage, aborting";
+ }
+
+ LOG(INFO) << "init first stage started!";
+
+ if (!DoFirstStageMount()) {
+ LOG(FATAL) << "Failed to mount required partitions early ...";
+ }
+
+ SetInitAvbVersionInRecovery();
+
+ // Does this need to be done in first stage init or can it be done later?
+ // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
+ GlobalSeccomp();
+
+ // Set up SELinux, loading the SELinux policy.
+ SelinuxSetupKernelLogging();
+ SelinuxInitialize();
+
+ // We're in the kernel domain and want to transition to the init domain when we exec second
+ // stage init. File systems that store SELabels in their xattrs, such as ext4 do not need an
+ // explicit restorecon here, but other file systems do. In particular, this is needed for
+ // ramdisks such as the recovery image for A/B devices.
+ if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
+ PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
+ }
+
+ static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
+ uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
+ setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
+
+ const char* path = "/system/bin/init";
+ const char* args[] = {path, nullptr};
+ execv(path, const_cast<char**>(args));
+
+ // execv() only returns if an error happened, in which case we
+ // panic and never fall through this conditional.
+ PLOG(FATAL) << "execv(\"" << path << "\") failed";
+
+ return 1;
+}
+
+} // namespace init
+} // namespace android
+
+int main(int argc, char** argv) {
+ return android::init::main(argc, argv);
+}
diff --git a/init/modalias_handler.cpp b/init/modalias_handler.cpp
index 1734a7e..1e0db57 100644
--- a/init/modalias_handler.cpp
+++ b/init/modalias_handler.cpp
@@ -139,7 +139,7 @@
return Insmod(dependencies[0], args);
}
-void ModaliasHandler::HandleModaliasEvent(const Uevent& uevent) {
+void ModaliasHandler::HandleUevent(const Uevent& uevent) {
if (uevent.modalias.empty()) return;
for (const auto& [alias, module] : module_aliases_) {
diff --git a/init/modalias_handler.h b/init/modalias_handler.h
index e79da32..3247c86 100644
--- a/init/modalias_handler.h
+++ b/init/modalias_handler.h
@@ -16,22 +16,23 @@
#pragma once
-#include "result.h"
-#include "uevent.h"
-
#include <string>
#include <unordered_map>
#include <vector>
+#include "result.h"
+#include "uevent.h"
+#include "uevent_handler.h"
+
namespace android {
namespace init {
-class ModaliasHandler {
+class ModaliasHandler : public UeventHandler {
public:
ModaliasHandler();
- ~ModaliasHandler(){};
+ virtual ~ModaliasHandler() = default;
- void HandleModaliasEvent(const Uevent& uevent);
+ void HandleUevent(const Uevent& uevent) override;
private:
Result<Success> InsmodWithDeps(const std::string& module_name, const std::string& args);
diff --git a/init/property_service.cpp b/init/property_service.cpp
index c0d811f..cd2f630 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -16,6 +16,7 @@
#include "property_service.h"
+#include <android/api-level.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -576,7 +577,7 @@
size_t flen = 0;
const char* context = kInitContext.c_str();
- if (SelinuxHasVendorInit()) {
+ if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
if (StartsWith(filename, path_prefix)) {
context = secontext;
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 11507f4..7401857 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -20,11 +20,9 @@
#include <fcntl.h>
#include <linux/fs.h>
#include <mntent.h>
-#include <sys/capability.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
-#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
@@ -51,9 +49,9 @@
#include <selinux/selinux.h>
#include "action_manager.h"
-#include "capabilities.h"
#include "init.h"
#include "property_service.h"
+#include "reboot_utils.h"
#include "service.h"
#include "sigchld_handler.h"
@@ -159,54 +157,6 @@
<< stat;
}
-bool IsRebootCapable() {
- if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
- PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
- return true;
- }
-
- ScopedCaps caps(cap_get_proc());
- if (!caps) {
- PLOG(WARNING) << "cap_get_proc() failed";
- return true;
- }
-
- cap_flag_value_t value = CAP_SET;
- if (cap_get_flag(caps.get(), CAP_SYS_BOOT, CAP_EFFECTIVE, &value) != 0) {
- PLOG(WARNING) << "cap_get_flag(CAP_SYS_BOOT, EFFECTIVE) failed";
- return true;
- }
- return value == CAP_SET;
-}
-
-void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
- LOG(INFO) << "Reboot ending, jumping to kernel";
-
- if (!IsRebootCapable()) {
- // On systems where init does not have the capability of rebooting the
- // device, just exit cleanly.
- exit(0);
- }
-
- switch (cmd) {
- case ANDROID_RB_POWEROFF:
- reboot(RB_POWER_OFF);
- break;
-
- case ANDROID_RB_RESTART2:
- syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
- break;
-
- case ANDROID_RB_THERMOFF:
- reboot(RB_POWER_OFF);
- break;
- }
- // In normal case, reboot should not return.
- PLOG(ERROR) << "reboot call returned";
- abort();
-}
-
/* Find all read+write block devices and emulated devices in /proc/mounts
* and add them to correpsponding list.
*/
@@ -329,8 +279,15 @@
return stat;
}
-void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
- bool runFsck) {
+//* Reboot / shutdown the system.
+// cmd ANDROID_RB_* as defined in android_reboot.h
+// reason Reason string like "reboot", "shutdown,userrequested"
+// rebootTarget Reboot target string like "bootloader". Otherwise, it should be an
+// empty string.
+// runFsck Whether to run fsck after umount is done.
+//
+static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
+ bool runFsck) {
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
diff --git a/init/reboot.h b/init/reboot.h
index 1c58bd1..07dcb6e 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -22,26 +22,9 @@
namespace android {
namespace init {
-// This is a wrapper around the actual reboot calls. DoReboot() should be preferred in most cases.
-void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget);
-
-/* Reboot / shutdown the system.
- * cmd ANDROID_RB_* as defined in android_reboot.h
- * reason Reason string like "reboot", "shutdown,userrequested"
- * rebootTarget Reboot target string like "bootloader". Otherwise, it should be an
- * empty string.
- * runFsck Whether to run fsck after umount is done.
- */
-void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
- bool runFsck) __attribute__((__noreturn__));
-
// Parses and handles a setprop sys.powerctl message.
bool HandlePowerctlMessage(const std::string& command);
-// Determines whether the system is capable of rebooting. This is conservative,
-// so if any of the attempts to determine this fail, it will still return true.
-bool IsRebootCapable();
-
} // namespace init
} // namespace android
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
new file mode 100644
index 0000000..9610304
--- /dev/null
+++ b/init/reboot_utils.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#include <sys/capability.h>
+#include <sys/reboot.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <cutils/android_reboot.h>
+
+#include "capabilities.h"
+
+namespace android {
+namespace init {
+
+bool IsRebootCapable() {
+ if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
+ PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
+ return true;
+ }
+
+ ScopedCaps caps(cap_get_proc());
+ if (!caps) {
+ PLOG(WARNING) << "cap_get_proc() failed";
+ return true;
+ }
+
+ cap_flag_value_t value = CAP_SET;
+ if (cap_get_flag(caps.get(), CAP_SYS_BOOT, CAP_EFFECTIVE, &value) != 0) {
+ PLOG(WARNING) << "cap_get_flag(CAP_SYS_BOOT, EFFECTIVE) failed";
+ return true;
+ }
+ return value == CAP_SET;
+}
+
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
+ LOG(INFO) << "Reboot ending, jumping to kernel";
+
+ if (!IsRebootCapable()) {
+ // On systems where init does not have the capability of rebooting the
+ // device, just exit cleanly.
+ exit(0);
+ }
+
+ switch (cmd) {
+ case ANDROID_RB_POWEROFF:
+ reboot(RB_POWER_OFF);
+ break;
+
+ case ANDROID_RB_RESTART2:
+ syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+ LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
+ break;
+
+ case ANDROID_RB_THERMOFF:
+ reboot(RB_POWER_OFF);
+ break;
+ }
+ // In normal case, reboot should not return.
+ PLOG(ERROR) << "reboot call returned";
+ abort();
+}
+
+void InstallRebootSignalHandlers() {
+ // Instead of panic'ing the kernel as is the default behavior when init crashes,
+ // we prefer to reboot to bootloader on development builds, as this will prevent
+ // boot looping bad configurations and allow both developers and test farms to easily
+ // recover.
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ sigfillset(&action.sa_mask);
+ action.sa_handler = [](int signal) {
+ // These signal handlers are also caught for processes forked from init, however we do not
+ // want them to trigger reboot, so we directly call _exit() for children processes here.
+ if (getpid() != 1) {
+ _exit(signal);
+ }
+
+ // Calling DoReboot() or LOG(FATAL) is not a good option as this is a signal handler.
+ // RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option
+ // and probably good enough given this is already an error case and only enabled for
+ // development builds.
+ RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+ };
+ action.sa_flags = SA_RESTART;
+ sigaction(SIGABRT, &action, nullptr);
+ sigaction(SIGBUS, &action, nullptr);
+ sigaction(SIGFPE, &action, nullptr);
+ sigaction(SIGILL, &action, nullptr);
+ sigaction(SIGSEGV, &action, nullptr);
+#if defined(SIGSTKFLT)
+ sigaction(SIGSTKFLT, &action, nullptr);
+#endif
+ sigaction(SIGSYS, &action, nullptr);
+ sigaction(SIGTRAP, &action, nullptr);
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
new file mode 100644
index 0000000..073a16a
--- /dev/null
+++ b/init/reboot_utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010 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>
+
+namespace android {
+namespace init {
+
+// Determines whether the system is capable of rebooting. This is conservative,
+// so if any of the attempts to determine this fail, it will still return true.
+bool IsRebootCapable();
+// This is a wrapper around the actual reboot calls.
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target);
+void InstallRebootSignalHandlers();
+
+} // namespace init
+} // namespace android
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 94f206e..fd7e86f 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -47,6 +47,7 @@
#include "selinux.h"
+#include <android/api-level.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
@@ -414,6 +415,8 @@
if constexpr (WORLD_WRITABLE_KMSG) {
selinux_android_restorecon("/dev/kmsg_debug", 0);
}
+ selinux_android_restorecon("/dev/null", 0);
+ selinux_android_restorecon("/dev/ptmx", 0);
selinux_android_restorecon("/dev/socket", 0);
selinux_android_restorecon("/dev/random", 0);
selinux_android_restorecon("/dev/urandom", 0);
@@ -470,29 +473,27 @@
selinux_set_callback(SELINUX_CB_LOG, cb);
}
-// This function checks whether the sepolicy supports vendor init.
-bool SelinuxHasVendorInit() {
+// This function returns the Android version with which the vendor SEPolicy was compiled.
+// It is used for version checks such as whether or not vendor_init should be used
+int SelinuxGetVendorAndroidVersion() {
if (!IsSplitPolicyDevice()) {
- // If this device does not split sepolicy files, vendor_init will be available in the latest
- // monolithic sepolicy file.
- return true;
+ // If this device does not split sepolicy files, it's not a Treble device and therefore,
+ // we assume it's always on the latest platform.
+ return __ANDROID_API_FUTURE__;
}
std::string version;
if (!GetVendorMappingVersion(&version)) {
- // Return true as the default if we failed to load the vendor sepolicy version.
- return true;
+ LOG(FATAL) << "Could not read vendor SELinux version";
}
int major_version;
std::string major_version_str(version, 0, version.find('.'));
if (!ParseInt(major_version_str, &major_version)) {
- PLOG(ERROR) << "Failed to parse the vendor sepolicy major version " << major_version_str;
- // Return true as the default if we failed to parse the major version.
- return true;
+ PLOG(FATAL) << "Failed to parse the vendor sepolicy major version " << major_version_str;
}
- return major_version >= 28;
+ return major_version;
}
// selinux_android_file_context_handle() takes on the order of 10+ms to run, so we want to cache
diff --git a/init/selinux.h b/init/selinux.h
index 30069b5..c41d7f0 100644
--- a/init/selinux.h
+++ b/init/selinux.h
@@ -27,7 +27,7 @@
void SelinuxRestoreContext();
void SelinuxSetupKernelLogging();
-bool SelinuxHasVendorInit();
+int SelinuxGetVendorAndroidVersion();
void SelabelInitialize();
bool SelabelLookupFileContext(const std::string& key, int type, std::string* result);
diff --git a/init/service.cpp b/init/service.cpp
index 4c2747e..d20e90a 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -46,10 +46,12 @@
#include "util.h"
#if defined(__ANDROID__)
+#include <android/api-level.h>
#include <sys/system_properties.h>
#include "init.h"
#include "property_service.h"
+#include "selinux.h"
#else
#include "host_init_stubs.h"
#endif
@@ -1211,6 +1213,13 @@
}
std::vector<std::string> str_args(args.begin() + 2, args.end());
+
+ if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_P__) {
+ if (str_args[0] == "/sbin/watchdogd") {
+ str_args[0] = "/system/bin/watchdogd";
+ }
+ }
+
service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);
return Success();
}
diff --git a/init/stable_properties.h b/init/stable_properties.h
index 05b2acb..4972d10 100644
--- a/init/stable_properties.h
+++ b/init/stable_properties.h
@@ -36,6 +36,7 @@
"init.svc.zygote",
"persist.bluetooth.btsnoopenable",
"persist.sys.crash_rcu",
+ "persist.sys.usb.usbradio.config",
"persist.sys.zram_enabled",
"ro.board.platform",
"ro.bootmode",
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index ee72513..c2a21d4 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -30,6 +30,7 @@
#include "util.h"
#if defined(__ANDROID__)
+#include <android/api-level.h>
#include "property_service.h"
#include "selinux.h"
#else
@@ -355,7 +356,7 @@
static bool shutting_down;
std::vector<Subcontext>* InitializeSubcontexts() {
- if (SelinuxHasVendorInit()) {
+ if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
subcontexts.emplace_back(path_prefix, secontext);
}
diff --git a/init/watchdogd.h b/init/uevent_handler.h
similarity index 71%
rename from init/watchdogd.h
rename to init/uevent_handler.h
index 73f77d5..75d1990 100644
--- a/init/watchdogd.h
+++ b/init/uevent_handler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -14,15 +14,21 @@
* limitations under the License.
*/
-#ifndef _INIT_WATCHDOGD_H_
-#define _INIT_WATCHDOGD_H_
+#pragma once
+
+#include "uevent.h"
namespace android {
namespace init {
-int watchdogd_main(int argc, char **argv);
+class UeventHandler {
+ public:
+ virtual ~UeventHandler() = default;
+
+ virtual void HandleUevent(const Uevent& uevent) = 0;
+
+ virtual void ColdbootDone() {}
+};
} // namespace init
} // namespace android
-
-#endif
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index e9d829b..95be6af 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -38,6 +38,7 @@
#include "firmware_handler.h"
#include "modalias_handler.h"
#include "selinux.h"
+#include "uevent_handler.h"
#include "uevent_listener.h"
#include "ueventd_parser.h"
#include "util.h"
@@ -107,11 +108,10 @@
class ColdBoot {
public:
- ColdBoot(UeventListener& uevent_listener, DeviceHandler& device_handler,
- ModaliasHandler& modalias_handler)
+ ColdBoot(UeventListener& uevent_listener,
+ std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers)
: uevent_listener_(uevent_listener),
- device_handler_(device_handler),
- modalias_handler_(modalias_handler),
+ uevent_handlers_(uevent_handlers),
num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4) {}
void Run();
@@ -124,8 +124,7 @@
void WaitForSubProcesses();
UeventListener& uevent_listener_;
- DeviceHandler& device_handler_;
- ModaliasHandler& modalias_handler_;
+ std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers_;
unsigned int num_handler_subprocesses_;
std::vector<Uevent> uevent_queue_;
@@ -136,16 +135,16 @@
void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) {
for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) {
auto& uevent = uevent_queue_[i];
- device_handler_.HandleDeviceEvent(uevent);
- modalias_handler_.HandleModaliasEvent(uevent);
+
+ for (auto& uevent_handler : uevent_handlers_) {
+ uevent_handler->HandleUevent(uevent);
+ }
}
_exit(EXIT_SUCCESS);
}
void ColdBoot::RegenerateUevents() {
uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
- HandleFirmwareEvent(uevent);
-
uevent_queue_.emplace_back(std::move(uevent));
return ListenerAction::kContinue;
});
@@ -168,7 +167,6 @@
void ColdBoot::DoRestoreCon() {
selinux_android_restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
- device_handler_.set_skip_restorecon(false);
}
void ColdBoot::WaitForSubProcesses() {
@@ -234,8 +232,7 @@
SelinuxSetupKernelLogging();
SelabelInitialize();
- DeviceHandler device_handler;
- ModaliasHandler modalias_handler;
+ std::vector<std::unique_ptr<UeventHandler>> uevent_handlers;
UeventListener uevent_listener;
{
@@ -248,19 +245,27 @@
ParseConfig({"/ueventd.rc", "/vendor/ueventd.rc", "/odm/ueventd.rc",
"/ueventd." + hardware + ".rc"});
- device_handler = DeviceHandler{std::move(ueventd_configuration.dev_permissions),
- std::move(ueventd_configuration.sysfs_permissions),
- std::move(ueventd_configuration.subsystems),
- fs_mgr_get_boot_devices(), true};
+ uevent_handlers.emplace_back(std::make_unique<DeviceHandler>(
+ std::move(ueventd_configuration.dev_permissions),
+ std::move(ueventd_configuration.sysfs_permissions),
+ std::move(ueventd_configuration.subsystems), fs_mgr_get_boot_devices(), true));
+ uevent_handlers.emplace_back(std::make_unique<FirmwareHandler>(
+ std::move(ueventd_configuration.firmware_directories)));
- firmware_directories = ueventd_configuration.firmware_directories;
+ if (ueventd_configuration.enable_modalias_handling) {
+ uevent_handlers.emplace_back(std::make_unique<ModaliasHandler>());
+ }
}
if (access(COLDBOOT_DONE, F_OK) != 0) {
- ColdBoot cold_boot(uevent_listener, device_handler, modalias_handler);
+ ColdBoot cold_boot(uevent_listener, uevent_handlers);
cold_boot.Run();
}
+ for (auto& uevent_handler : uevent_handlers) {
+ uevent_handler->ColdbootDone();
+ }
+
// We use waitpid() in ColdBoot, so we can't ignore SIGCHLD until now.
signal(SIGCHLD, SIG_IGN);
// Reap and pending children that exited between the last call to waitpid() and setting SIG_IGN
@@ -268,10 +273,10 @@
while (waitpid(-1, nullptr, WNOHANG) > 0) {
}
- uevent_listener.Poll([&device_handler, &modalias_handler](const Uevent& uevent) {
- HandleFirmwareEvent(uevent);
- modalias_handler.HandleModaliasEvent(uevent);
- device_handler.HandleDeviceEvent(uevent);
+ uevent_listener.Poll([&uevent_handlers](const Uevent& uevent) {
+ for (auto& uevent_handler : uevent_handlers) {
+ uevent_handler->HandleUevent(uevent);
+ }
return ListenerAction::kContinue;
});
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 54b0d16..677938e 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -84,6 +84,23 @@
return Success();
}
+Result<Success> ParseModaliasHandlingLine(std::vector<std::string>&& args,
+ bool* enable_modalias_handling) {
+ if (args.size() != 2) {
+ return Error() << "modalias_handling lines take exactly one parameter";
+ }
+
+ if (args[1] == "enabled") {
+ *enable_modalias_handling = true;
+ } else if (args[1] == "disabled") {
+ *enable_modalias_handling = false;
+ } else {
+ return Error() << "modalias_handling takes either 'enabled' or 'disabled' as a parameter";
+ }
+
+ return Success();
+}
+
class SubsystemParser : public SectionParser {
public:
SubsystemParser(std::vector<Subsystem>* subsystems) : subsystems_(subsystems) {}
@@ -182,6 +199,9 @@
parser.AddSingleLineParser("firmware_directories",
std::bind(ParseFirmwareDirectoriesLine, _1,
&ueventd_configuration.firmware_directories));
+ parser.AddSingleLineParser("modalias_handling",
+ std::bind(ParseModaliasHandlingLine, _1,
+ &ueventd_configuration.enable_modalias_handling));
for (const auto& config : configs) {
parser.ParseConfig(config);
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 343d58b..7d30edf 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -30,6 +30,7 @@
std::vector<SysfsPermissions> sysfs_permissions;
std::vector<Permissions> dev_permissions;
std::vector<std::string> firmware_directories;
+ bool enable_modalias_handling = false;
};
UeventdConfiguration ParseConfig(const std::vector<std::string>& configs);
diff --git a/init/util.cpp b/init/util.cpp
index 7735717..105ac87 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -47,7 +47,7 @@
#endif
#ifdef _INIT_INIT_H
-#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
+#error "Do not include init.h in files used by ueventd; it will expose init's globals"
#endif
using android::base::boot_clock;
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
index 1eab46c..1915f22 100644
--- a/libappfuse/FuseBuffer.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -149,8 +149,8 @@
}
constexpr int kMaxMessageSize = sizeof(FuseBuffer);
- if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUFFORCE, &kMaxMessageSize, sizeof(int)) != 0 ||
- setsockopt(fds[1], SOL_SOCKET, SO_SNDBUFFORCE, &kMaxMessageSize, sizeof(int)) != 0) {
+ if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &kMaxMessageSize, sizeof(int)) != 0 ||
+ setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, &kMaxMessageSize, sizeof(int)) != 0) {
PLOG(ERROR) << "Failed to update buffer size for socket";
return false;
}
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
index 7a70bf3..3063815 100644
--- a/libappfuse/include/libappfuse/FuseBuffer.h
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -25,7 +25,7 @@
// The numbers came from sdcard.c.
// Maximum number of bytes to write/read in one request/one reply.
-constexpr size_t kFuseMaxWrite = 256 * 1024;
+constexpr size_t kFuseMaxWrite = 128 * 1024;
constexpr size_t kFuseMaxRead = 128 * 1024;
constexpr int32_t kFuseSuccess = 0;
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index a9cfce4..c564271 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -31,6 +31,7 @@
#include <deque>
#include <iterator>
+#include <memory>
#include <string>
#include <vector>
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 48def6f..af8f0a2 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -62,7 +62,7 @@
static const struct fs_path_config android_dirs[] = {
// clang-format off
{ 00770, AID_SYSTEM, AID_CACHE, 0, "cache" },
- { 00500, AID_ROOT, AID_ROOT, 0, "config" },
+ { 00555, AID_ROOT, AID_ROOT, 0, "config" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" },
diff --git a/liblog/include/log/log_event_list.h b/liblog/include/log/log_event_list.h
index bb1ce34..1b7c377 100644
--- a/liblog/include/log/log_event_list.h
+++ b/liblog/include/log/log_event_list.h
@@ -108,6 +108,13 @@
android_log_list_element android_log_read_next(android_log_context ctx);
android_log_list_element android_log_peek_next(android_log_context ctx);
+/* Reset writer context */
+int android_log_reset(android_log_context ctx);
+
+/* Reset reader context */
+int android_log_parser_reset(android_log_context ctx,
+ const char* msg, size_t len);
+
/* Finished with reader or writer context */
int android_log_destroy(android_log_context* ctx);
diff --git a/liblog/include_vndk/log/log_event_list.h b/liblog/include_vndk/log/log_event_list.h
index cbd3091..9f74534 100644
--- a/liblog/include_vndk/log/log_event_list.h
+++ b/liblog/include_vndk/log/log_event_list.h
@@ -63,6 +63,13 @@
/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
int android_log_write_list(android_log_context ctx, log_id_t id);
+/* Reset writer context */
+int android_log_reset(android_log_context ctx);
+
+/* Reset reader context */
+int android_log_parser_reset(android_log_context ctx,
+ const char* msg, size_t len);
+
/* Finished with reader or writer context */
int android_log_destroy(android_log_context* ctx);
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 66670fe..015c9cb 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -53,3 +53,9 @@
__android_log_is_loggable_len;
__android_log_is_debuggable; # vndk
};
+
+LIBLOG_Q {
+ global:
+ android_log_reset; #vndk
+ android_log_parser_reset; #vndk
+};
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index a59cb87..14002ce 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -45,14 +45,9 @@
uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
} android_log_context_internal;
-LIBLOG_ABI_PUBLIC android_log_context create_android_logger(uint32_t tag) {
- size_t needed, i;
- android_log_context_internal* context;
+static void init_context(android_log_context_internal* context, uint32_t tag) {
+ size_t needed;
- context = calloc(1, sizeof(android_log_context_internal));
- if (!context) {
- return NULL;
- }
context->tag = tag;
context->read_write_flag = kAndroidLoggerWrite;
needed = sizeof(uint8_t) + sizeof(uint8_t);
@@ -63,6 +58,24 @@
context->storage[context->pos + 0] = EVENT_TYPE_LIST;
context->list[0] = context->pos + 1;
context->pos += needed;
+}
+
+static void init_parser_context(android_log_context_internal* context,
+ const char* msg, size_t len) {
+ len = (len <= MAX_EVENT_PAYLOAD) ? len : MAX_EVENT_PAYLOAD;
+ context->len = len;
+ memcpy(context->storage, msg, len);
+ context->read_write_flag = kAndroidLoggerRead;
+}
+
+LIBLOG_ABI_PUBLIC android_log_context create_android_logger(uint32_t tag) {
+ android_log_context_internal* context;
+
+ context = calloc(1, sizeof(android_log_context_internal));
+ if (!context) {
+ return NULL;
+ }
+ init_context(context, tag);
return (android_log_context)context;
}
@@ -76,10 +89,7 @@
if (!context) {
return NULL;
}
- len = (len <= MAX_EVENT_PAYLOAD) ? len : MAX_EVENT_PAYLOAD;
- context->len = len;
- memcpy(context->storage, msg, len);
- context->read_write_flag = kAndroidLoggerRead;
+ init_parser_context(context, msg, len);
return (android_log_context)context;
}
@@ -97,6 +107,38 @@
return 0;
}
+LIBLOG_ABI_PUBLIC int android_log_reset(android_log_context ctx) {
+ android_log_context_internal* context;
+ uint32_t tag;
+
+ context = (android_log_context_internal*)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+
+ tag = context->tag;
+ memset(context, 0, sizeof(*context));
+ init_context(context, tag);
+
+ return 0;
+}
+
+LIBLOG_ABI_PUBLIC int android_log_parser_reset(android_log_context ctx,
+ const char* msg, size_t len) {
+ android_log_context_internal* context;
+
+ context = (android_log_context_internal*)ctx;
+ if (!context || (kAndroidLoggerRead != context->read_write_flag)) {
+ return -EBADF;
+ }
+
+ memset(context, 0, sizeof(*context));
+ init_parser_context(context, msg, len);
+
+ return 0;
+}
+
+
LIBLOG_ABI_PUBLIC int android_log_write_list_begin(android_log_context ctx) {
size_t needed;
android_log_context_internal* context;
diff --git a/libmetricslogger/OWNERS b/libmetricslogger/OWNERS
index 7fe0443..6a6fba2 100644
--- a/libmetricslogger/OWNERS
+++ b/libmetricslogger/OWNERS
@@ -1 +1,2 @@
+cwren@google.com
jhawkins@google.com
diff --git a/libmetricslogger/include/metricslogger/metrics_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h
index 2c76869..c305db2 100644
--- a/libmetricslogger/include/metricslogger/metrics_logger.h
+++ b/libmetricslogger/include/metricslogger/metrics_logger.h
@@ -47,6 +47,8 @@
public:
// Create a complex event with category|category|.
explicit ComplexEventLogger(int category);
+ // Set the package name that this event originates from.
+ void SetPackageName(const std::string& package_name);
// Add tagged data to the event, with the given tag and integer value.
void AddTaggedData(int tag, int32_t value);
// Add tagged data to the event, with the given tag and string value.
@@ -70,14 +72,49 @@
LOGBUILDER_VALUE = 802,
LOGBUILDER_COUNTER = 803,
LOGBUILDER_HISTOGRAM = 804,
+ LOGBUILDER_PACKAGENAME = 806,
ACTION_BOOT = 1098,
FIELD_PLATFORM_REASON = 1099,
+ FIELD_DURATION_MILLIS = 1304,
+
+ FIELD_END_BATTERY_PERCENT = 1308,
+
ACTION_HIDDEN_API_ACCESSED = 1391,
FIELD_HIDDEN_API_ACCESS_METHOD = 1392,
FIELD_HIDDEN_API_ACCESS_DENIED = 1393,
FIELD_HIDDEN_API_SIGNATURE = 1394,
+
+ ACTION_USB_CONNECTOR_CONNECTED = 1422,
+ ACTION_USB_CONNECTOR_DISCONNECTED = 1423,
+ ACTION_USB_AUDIO_CONNECTED = 1424,
+ FIELD_USB_AUDIO_VIDPID = 1425,
+ ACTION_USB_AUDIO_DISCONNECTED = 1426,
+ ACTION_HARDWARE_FAILED = 1427,
+ FIELD_HARDWARE_TYPE = 1428,
+ FIELD_HARDWARE_FAILURE_CODE = 1429,
+ ACTION_PHYSICAL_DROP = 1430,
+ FIELD_CONFIDENCE_PERCENT = 1431,
+ FIELD_ACCEL_MILLI_G = 1432,
+ ACTION_BATTERY_HEALTH = 1433,
+ FIELD_BATTERY_HEALTH_SNAPSHOT_TYPE = 1434,
+ FIELD_BATTERY_TEMPERATURE_DECI_C = 1435,
+ FIELD_BATTERY_VOLTAGE_UV = 1436,
+ FIELD_BATTERY_OPEN_CIRCUIT_VOLTAGE_UV = 1437,
+ ACTION_BATTERY_CHARGE_CYCLES = 1438,
+ FIELD_BATTERY_CHARGE_CYCLES = 1439,
+
+ ACTION_SLOW_IO = 1442,
+ FIELD_IO_OPERATION_TYPE = 1443,
+ FIELD_IO_OPERATION_COUNT = 1444,
+ ACTION_SPEAKER_IMPEDANCE = 1445,
+ FIELD_SPEAKER_IMPEDANCE_MILLIOHMS = 1446,
+ FIELD_SPEAKER_LOCATION = 1447,
+ FIELD_BATTERY_RESISTANCE_UOHMS = 1448,
+ FIELD_BATTERY_CURRENT_UA = 1449,
+ FIELD_HARDWARE_LOCATION = 1450,
+ ACTION_BATTERY_CAUSED_SHUTDOWN = 1441,
};
enum {
@@ -91,5 +128,30 @@
ACCESS_METHOD_LINKING = 3,
};
+enum HardwareType {
+ HARDWARE_UNKNOWN = 0,
+ HARDWARE_MICROPHONE = 1,
+ HARDWARE_CODEC = 2,
+ HARDWARE_SPEAKER = 3,
+ HARDWARE_FINGERPRINT = 4,
+};
+
+enum HardwareFailureCode {
+ HARDWARE_FAILURE_UNKNOWN = 0,
+ HARDWARE_FAILURE_COMPLETE = 1,
+ HARDWARE_FAILURE_SPEAKER_HIGH_Z = 2,
+ HARDWARE_FAILURE_SPEAKER_SHORT = 3,
+ HARDWARE_FAILURE_FINGERPRINT_SENSOR_BROKEN = 4,
+ HARDWARE_FAILURE_FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5,
+};
+
+enum IoOperation {
+ IOOP_UNKNOWN = 0,
+ IOOP_READ = 1,
+ IOOP_WRITE = 2,
+ IOOP_UNMAP = 3,
+ IOOP_SYNC = 4,
+};
+
} // namespace metricslogger
} // namespace android
diff --git a/libmetricslogger/metrics_logger.cpp b/libmetricslogger/metrics_logger.cpp
index 912fa12..6a32153 100644
--- a/libmetricslogger/metrics_logger.cpp
+++ b/libmetricslogger/metrics_logger.cpp
@@ -62,6 +62,10 @@
logger << LOGBUILDER_CATEGORY << category;
}
+void ComplexEventLogger::SetPackageName(const std::string& package_name) {
+ logger << LOGBUILDER_PACKAGENAME << package_name;
+}
+
void ComplexEventLogger::AddTaggedData(int tag, int32_t value) {
logger << tag << value;
}
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
index e53a4c8..9ecdd4f 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -218,6 +218,20 @@
* to construct the pseudo header used in the checksum calculation.
*/
dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp);
+ /*
+ * check validity of dhcp_size.
+ * 1) cannot be negative or zero.
+ * 2) src buffer contains enough bytes to copy
+ * 3) cannot exceed destination buffer
+ */
+ if ((dhcp_size <= 0) ||
+ ((int)(nread - sizeof(struct iphdr) - sizeof(struct udphdr)) < dhcp_size) ||
+ ((int)sizeof(struct dhcp_msg) < dhcp_size)) {
+#if VERBOSE
+ ALOGD("Malformed Packet");
+#endif
+ return -1;
+ }
saddr = packet.ip.saddr;
daddr = packet.ip.daddr;
nread = ntohs(packet.ip.tot_len);
diff --git a/libpixelflinger/fixed.cpp b/libpixelflinger/fixed.cpp
index 5094537..de6b479 100644
--- a/libpixelflinger/fixed.cpp
+++ b/libpixelflinger/fixed.cpp
@@ -70,17 +70,6 @@
// ------------------------------------------------------------------------
-GGLfixed gglFastDivx(GGLfixed n, GGLfixed d)
-{
- if ((d>>24) && ((d>>24)+1)) {
- n >>= 8;
- d >>= 8;
- }
- return gglMulx(n, gglRecip(d));
-}
-
-// ------------------------------------------------------------------------
-
static const GGLfixed ggl_sqrt_reciproc_approx_tab[8] = {
// 1/sqrt(x) with x = 1-N/16, N=[8...1]
0x16A09, 0x15555, 0x143D1, 0x134BF, 0x1279A, 0x11C01, 0x111AC, 0x10865
diff --git a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
index 51e9e26..7f39e9b 100644
--- a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
+++ b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
@@ -86,7 +86,6 @@
GGLfixed gglPowx(GGLfixed x, GGLfixed y) CONST;
GGLfixed gglSqrtx(GGLfixed a) CONST;
GGLfixed gglSqrtRecipx(GGLfixed x) CONST;
-GGLfixed gglFastDivx(GGLfixed n, GGLfixed d) CONST;
int32_t gglMulDivi(int32_t a, int32_t b, int32_t c);
int32_t gglRecipQNormalized(int32_t x, int* exponent);
diff --git a/libsync/Android.bp b/libsync/Android.bp
index c95563d..e56f8ba 100644
--- a/libsync/Android.bp
+++ b/libsync/Android.bp
@@ -20,8 +20,9 @@
cflags: ["-Werror"],
}
-cc_library_shared {
+cc_library {
name: "libsync",
+ recovery_available: true,
defaults: ["libsync_defaults"],
}
@@ -31,14 +32,6 @@
export_include_dirs: ["include"],
}
-// libsync_recovery is only intended for the recovery binary.
-// Future versions of the kernel WILL require an updated libsync, and will break
-// anything statically linked against the current libsync.
-cc_library_static {
- name: "libsync_recovery",
- defaults: ["libsync_defaults"],
-}
-
cc_test {
name: "sync-unit-tests",
shared_libs: ["libsync"],
diff --git a/libsystem/include/system/camera.h b/libsystem/include/system/camera.h
index 5d0873a..7d79673 100644
--- a/libsystem/include/system/camera.h
+++ b/libsystem/include/system/camera.h
@@ -203,6 +203,15 @@
* (except disconnect and sending CAMERA_CMD_PING) after getting this.
*/
CAMERA_ERROR_RELEASED = 2,
+
+ /**
+ * Camera was released because device policy change or the client application
+ * is going to background. The client should call Camera::disconnect
+ * immediately after getting this notification. Otherwise, the camera will be
+ * released by camera service in a short time. The client should not call any
+ * method (except disconnect and sending CAMERA_CMD_PING) after getting this.
+ */
+ CAMERA_ERROR_DISABLED = 3,
CAMERA_ERROR_SERVER_DIED = 100
};
diff --git a/libsystem/include/system/graphics-base-v1.0.h b/libsystem/include/system/graphics-base-v1.0.h
new file mode 100644
index 0000000..44913cc
--- /dev/null
+++ b/libsystem/include/system/graphics-base-v1.0.h
@@ -0,0 +1,140 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+// Source: android.hardware.graphics.common@1.0
+// Location: hardware/interfaces/graphics/common/1.0/
+
+#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ HAL_PIXEL_FORMAT_RGBA_8888 = 1,
+ HAL_PIXEL_FORMAT_RGBX_8888 = 2,
+ HAL_PIXEL_FORMAT_RGB_888 = 3,
+ HAL_PIXEL_FORMAT_RGB_565 = 4,
+ HAL_PIXEL_FORMAT_BGRA_8888 = 5,
+ HAL_PIXEL_FORMAT_YCBCR_422_SP = 16,
+ HAL_PIXEL_FORMAT_YCRCB_420_SP = 17,
+ HAL_PIXEL_FORMAT_YCBCR_422_I = 20,
+ HAL_PIXEL_FORMAT_RGBA_FP16 = 22,
+ HAL_PIXEL_FORMAT_RAW16 = 32,
+ HAL_PIXEL_FORMAT_BLOB = 33,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 34,
+ HAL_PIXEL_FORMAT_YCBCR_420_888 = 35,
+ HAL_PIXEL_FORMAT_RAW_OPAQUE = 36,
+ HAL_PIXEL_FORMAT_RAW10 = 37,
+ HAL_PIXEL_FORMAT_RAW12 = 38,
+ HAL_PIXEL_FORMAT_RGBA_1010102 = 43,
+ HAL_PIXEL_FORMAT_Y8 = 538982489,
+ HAL_PIXEL_FORMAT_Y16 = 540422489,
+ HAL_PIXEL_FORMAT_YV12 = 842094169,
+} android_pixel_format_t;
+
+typedef enum {
+ HAL_TRANSFORM_FLIP_H = 1, // (1 << 0)
+ HAL_TRANSFORM_FLIP_V = 2, // (1 << 1)
+ HAL_TRANSFORM_ROT_90 = 4, // (1 << 2)
+ HAL_TRANSFORM_ROT_180 = 3, // (FLIP_H | FLIP_V)
+ HAL_TRANSFORM_ROT_270 = 7, // ((FLIP_H | FLIP_V) | ROT_90)
+} android_transform_t;
+
+typedef enum {
+ HAL_DATASPACE_UNKNOWN = 0,
+ HAL_DATASPACE_ARBITRARY = 1,
+ HAL_DATASPACE_STANDARD_SHIFT = 16,
+ HAL_DATASPACE_STANDARD_MASK = 4128768, // (63 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_UNSPECIFIED = 0, // (0 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT709 = 65536, // (1 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_625 = 131072, // (2 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 196608, // (3 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_525 = 262144, // (4 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 327680, // (5 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT2020 = 393216, // (6 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 458752, // (7 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_BT470M = 524288, // (8 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_FILM = 589824, // (9 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_DCI_P3 = 655360, // (10 << STANDARD_SHIFT)
+ HAL_DATASPACE_STANDARD_ADOBE_RGB = 720896, // (11 << STANDARD_SHIFT)
+ HAL_DATASPACE_TRANSFER_SHIFT = 22,
+ HAL_DATASPACE_TRANSFER_MASK = 130023424, // (31 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0, // (0 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_LINEAR = 4194304, // (1 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_SRGB = 8388608, // (2 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_SMPTE_170M = 12582912, // (3 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_GAMMA2_2 = 16777216, // (4 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_GAMMA2_6 = 20971520, // (5 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_GAMMA2_8 = 25165824, // (6 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_ST2084 = 29360128, // (7 << TRANSFER_SHIFT)
+ HAL_DATASPACE_TRANSFER_HLG = 33554432, // (8 << TRANSFER_SHIFT)
+ HAL_DATASPACE_RANGE_SHIFT = 27,
+ HAL_DATASPACE_RANGE_MASK = 939524096, // (7 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_UNSPECIFIED = 0, // (0 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_FULL = 134217728, // (1 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_LIMITED = 268435456, // (2 << RANGE_SHIFT)
+ HAL_DATASPACE_RANGE_EXTENDED = 402653184, // (3 << RANGE_SHIFT)
+ HAL_DATASPACE_SRGB_LINEAR = 512,
+ HAL_DATASPACE_V0_SRGB_LINEAR = 138477568, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_FULL)
+ HAL_DATASPACE_V0_SCRGB_LINEAR =
+ 406913024, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_EXTENDED)
+ HAL_DATASPACE_SRGB = 513,
+ HAL_DATASPACE_V0_SRGB = 142671872, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_FULL)
+ HAL_DATASPACE_V0_SCRGB = 411107328, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_EXTENDED)
+ HAL_DATASPACE_JFIF = 257,
+ HAL_DATASPACE_V0_JFIF = 146931712, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_FULL)
+ HAL_DATASPACE_BT601_625 = 258,
+ HAL_DATASPACE_V0_BT601_625 =
+ 281149440, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_BT601_525 = 259,
+ HAL_DATASPACE_V0_BT601_525 =
+ 281280512, // ((STANDARD_BT601_525 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_BT709 = 260,
+ HAL_DATASPACE_V0_BT709 = 281083904, // ((STANDARD_BT709 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_DCI_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL)
+ HAL_DATASPACE_DCI_P3 = 155844608, // ((STANDARD_DCI_P3 | TRANSFER_GAMMA2_6) | RANGE_FULL)
+ HAL_DATASPACE_DISPLAY_P3_LINEAR =
+ 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL)
+ HAL_DATASPACE_DISPLAY_P3 = 143261696, // ((STANDARD_DCI_P3 | TRANSFER_SRGB) | RANGE_FULL)
+ HAL_DATASPACE_ADOBE_RGB = 151715840, // ((STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2) | RANGE_FULL)
+ HAL_DATASPACE_BT2020_LINEAR = 138805248, // ((STANDARD_BT2020 | TRANSFER_LINEAR) | RANGE_FULL)
+ HAL_DATASPACE_BT2020 = 147193856, // ((STANDARD_BT2020 | TRANSFER_SMPTE_170M) | RANGE_FULL)
+ HAL_DATASPACE_BT2020_PQ = 163971072, // ((STANDARD_BT2020 | TRANSFER_ST2084) | RANGE_FULL)
+ HAL_DATASPACE_DEPTH = 4096,
+ HAL_DATASPACE_SENSOR = 4097,
+} android_dataspace_t;
+
+typedef enum {
+ HAL_COLOR_MODE_NATIVE = 0,
+ HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
+ HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
+ HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
+ HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
+ HAL_COLOR_MODE_STANDARD_BT709 = 5,
+ HAL_COLOR_MODE_DCI_P3 = 6,
+ HAL_COLOR_MODE_SRGB = 7,
+ HAL_COLOR_MODE_ADOBE_RGB = 8,
+ HAL_COLOR_MODE_DISPLAY_P3 = 9,
+} android_color_mode_t;
+
+typedef enum {
+ HAL_COLOR_TRANSFORM_IDENTITY = 0,
+ HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
+ HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
+ HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
+ HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
+ HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
+ HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6,
+} android_color_transform_t;
+
+typedef enum {
+ HAL_HDR_DOLBY_VISION = 1,
+ HAL_HDR_HDR10 = 2,
+ HAL_HDR_HLG = 3,
+} android_hdr_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
diff --git a/libsystem/include/system/graphics-base-v1.1.h b/libsystem/include/system/graphics-base-v1.1.h
new file mode 100644
index 0000000..f95b9ba
--- /dev/null
+++ b/libsystem/include/system/graphics-base-v1.1.h
@@ -0,0 +1,48 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+// Source: android.hardware.graphics.common@1.1
+// Location: hardware/interfaces/graphics/common/1.1/
+
+#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_1_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_1_EXPORTED_CONSTANTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ HAL_PIXEL_FORMAT_DEPTH_16 = 48,
+ HAL_PIXEL_FORMAT_DEPTH_24 = 49,
+ HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 = 50,
+ HAL_PIXEL_FORMAT_DEPTH_32F = 51,
+ HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 = 52,
+ HAL_PIXEL_FORMAT_STENCIL_8 = 53,
+ HAL_PIXEL_FORMAT_YCBCR_P010 = 54,
+} android_pixel_format_v1_1_t;
+
+typedef enum {
+ HAL_DATASPACE_BT2020_ITU =
+ 281411584, // ((STANDARD_BT2020 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_BT2020_ITU_PQ =
+ 298188800, // ((STANDARD_BT2020 | TRANSFER_ST2084) | RANGE_LIMITED)
+ HAL_DATASPACE_BT2020_ITU_HLG = 302383104, // ((STANDARD_BT2020 | TRANSFER_HLG) | RANGE_LIMITED)
+ HAL_DATASPACE_BT2020_HLG = 168165376, // ((STANDARD_BT2020 | TRANSFER_HLG) | RANGE_FULL)
+} android_dataspace_v1_1_t;
+
+typedef enum {
+ HAL_COLOR_MODE_BT2020 = 10,
+ HAL_COLOR_MODE_BT2100_PQ = 11,
+ HAL_COLOR_MODE_BT2100_HLG = 12,
+} android_color_mode_v1_1_t;
+
+typedef enum {
+ HAL_RENDER_INTENT_COLORIMETRIC = 0,
+ HAL_RENDER_INTENT_ENHANCE = 1,
+ HAL_RENDER_INTENT_TONE_MAP_COLORIMETRIC = 2,
+ HAL_RENDER_INTENT_TONE_MAP_ENHANCE = 3,
+} android_render_intent_v1_1_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_1_EXPORTED_CONSTANTS_H_
diff --git a/libsystem/include/system/graphics-base.h b/libsystem/include/system/graphics-base.h
index 2a44faf..ea92007 100644
--- a/libsystem/include/system/graphics-base.h
+++ b/libsystem/include/system/graphics-base.h
@@ -1,141 +1,7 @@
-// This file is autogenerated by hidl-gen. Do not edit manually.
-// Source: android.hardware.graphics.common@1.0
-// Root: android.hardware:hardware/interfaces
+#ifndef SYSTEM_CORE_GRAPHICS_BASE_H_
+#define SYSTEM_CORE_GRAPHICS_BASE_H_
-#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
-#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
+#include "graphics-base-v1.0.h"
+#include "graphics-base-v1.1.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
- HAL_PIXEL_FORMAT_RGBA_8888 = 1,
- HAL_PIXEL_FORMAT_RGBX_8888 = 2,
- HAL_PIXEL_FORMAT_RGB_888 = 3,
- HAL_PIXEL_FORMAT_RGB_565 = 4,
- HAL_PIXEL_FORMAT_BGRA_8888 = 5,
- HAL_PIXEL_FORMAT_RGBA_1010102 = 43, // 0x2B
- HAL_PIXEL_FORMAT_RGBA_FP16 = 22, // 0x16
- HAL_PIXEL_FORMAT_YV12 = 842094169, // 0x32315659
- HAL_PIXEL_FORMAT_Y8 = 538982489, // 0x20203859
- HAL_PIXEL_FORMAT_Y16 = 540422489, // 0x20363159
- HAL_PIXEL_FORMAT_RAW16 = 32, // 0x20
- HAL_PIXEL_FORMAT_RAW10 = 37, // 0x25
- HAL_PIXEL_FORMAT_RAW12 = 38, // 0x26
- HAL_PIXEL_FORMAT_RAW_OPAQUE = 36, // 0x24
- HAL_PIXEL_FORMAT_BLOB = 33, // 0x21
- HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 34, // 0x22
- HAL_PIXEL_FORMAT_YCBCR_420_888 = 35, // 0x23
- HAL_PIXEL_FORMAT_YCBCR_422_888 = 39, // 0x27
- HAL_PIXEL_FORMAT_YCBCR_444_888 = 40, // 0x28
- HAL_PIXEL_FORMAT_FLEX_RGB_888 = 41, // 0x29
- HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 42, // 0x2A
- HAL_PIXEL_FORMAT_YCBCR_422_SP = 16, // 0x10
- HAL_PIXEL_FORMAT_YCRCB_420_SP = 17, // 0x11
- HAL_PIXEL_FORMAT_YCBCR_422_I = 20, // 0x14
- HAL_PIXEL_FORMAT_JPEG = 256, // 0x100
-} android_pixel_format_t;
-
-typedef enum {
- HAL_TRANSFORM_FLIP_H = 1, // 0x01
- HAL_TRANSFORM_FLIP_V = 2, // 0x02
- HAL_TRANSFORM_ROT_90 = 4, // 0x04
- HAL_TRANSFORM_ROT_180 = 3, // 0x03
- HAL_TRANSFORM_ROT_270 = 7, // 0x07
-} android_transform_t;
-
-typedef enum {
- HAL_DATASPACE_UNKNOWN = 0, // 0x0
- HAL_DATASPACE_ARBITRARY = 1, // 0x1
- HAL_DATASPACE_STANDARD_SHIFT = 16,
- HAL_DATASPACE_STANDARD_MASK = 4128768, // (63 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_UNSPECIFIED = 0, // (0 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_BT709 = 65536, // (1 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_BT601_625 = 131072, // (2 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 196608, // (3 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_BT601_525 = 262144, // (4 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 327680, // (5 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_BT2020 = 393216, // (6 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 458752, // (7 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_BT470M = 524288, // (8 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_FILM = 589824, // (9 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_DCI_P3 = 655360, // (10 << STANDARD_SHIFT)
- HAL_DATASPACE_STANDARD_ADOBE_RGB = 720896, // (11 << STANDARD_SHIFT)
- HAL_DATASPACE_TRANSFER_SHIFT = 22,
- HAL_DATASPACE_TRANSFER_MASK = 130023424, // (31 << TRANSFER_SHIFT)
- HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0, // (0 << TRANSFER_SHIFT)
- HAL_DATASPACE_TRANSFER_LINEAR = 4194304, // (1 << TRANSFER_SHIFT)
- HAL_DATASPACE_TRANSFER_SRGB = 8388608, // (2 << TRANSFER_SHIFT)
- HAL_DATASPACE_TRANSFER_SMPTE_170M = 12582912, // (3 << TRANSFER_SHIFT)
- HAL_DATASPACE_TRANSFER_GAMMA2_2 = 16777216, // (4 << TRANSFER_SHIFT)
- HAL_DATASPACE_TRANSFER_GAMMA2_6 = 20971520, // (5 << TRANSFER_SHIFT)
- HAL_DATASPACE_TRANSFER_GAMMA2_8 = 25165824, // (6 << TRANSFER_SHIFT)
- HAL_DATASPACE_TRANSFER_ST2084 = 29360128, // (7 << TRANSFER_SHIFT)
- HAL_DATASPACE_TRANSFER_HLG = 33554432, // (8 << TRANSFER_SHIFT)
- HAL_DATASPACE_RANGE_SHIFT = 27,
- HAL_DATASPACE_RANGE_MASK = 939524096, // (7 << RANGE_SHIFT)
- HAL_DATASPACE_RANGE_UNSPECIFIED = 0, // (0 << RANGE_SHIFT)
- HAL_DATASPACE_RANGE_FULL = 134217728, // (1 << RANGE_SHIFT)
- HAL_DATASPACE_RANGE_LIMITED = 268435456, // (2 << RANGE_SHIFT)
- HAL_DATASPACE_RANGE_EXTENDED = 402653184, // (3 << RANGE_SHIFT)
- HAL_DATASPACE_SRGB_LINEAR = 512, // 0x200
- HAL_DATASPACE_V0_SRGB_LINEAR = 138477568, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_FULL)
- HAL_DATASPACE_V0_SCRGB_LINEAR = 406913024, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_EXTENDED)
- HAL_DATASPACE_SRGB = 513, // 0x201
- HAL_DATASPACE_V0_SRGB = 142671872, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_FULL)
- HAL_DATASPACE_V0_SCRGB = 411107328, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_EXTENDED)
- HAL_DATASPACE_JFIF = 257, // 0x101
- HAL_DATASPACE_V0_JFIF = 146931712, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_FULL)
- HAL_DATASPACE_BT601_625 = 258, // 0x102
- HAL_DATASPACE_V0_BT601_625 = 281149440, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
- HAL_DATASPACE_BT601_525 = 259, // 0x103
- HAL_DATASPACE_V0_BT601_525 = 281280512, // ((STANDARD_BT601_525 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
- HAL_DATASPACE_BT709 = 260, // 0x104
- HAL_DATASPACE_V0_BT709 = 281083904, // ((STANDARD_BT709 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
- HAL_DATASPACE_DCI_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL)
- HAL_DATASPACE_DCI_P3 = 155844608, // ((STANDARD_DCI_P3 | TRANSFER_GAMMA2_6) | RANGE_FULL)
- HAL_DATASPACE_DISPLAY_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL)
- HAL_DATASPACE_DISPLAY_P3 = 143261696, // ((STANDARD_DCI_P3 | TRANSFER_SRGB) | RANGE_FULL)
- HAL_DATASPACE_ADOBE_RGB = 151715840, // ((STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2) | RANGE_FULL)
- HAL_DATASPACE_BT2020_LINEAR = 138805248, // ((STANDARD_BT2020 | TRANSFER_LINEAR) | RANGE_FULL)
- HAL_DATASPACE_BT2020 = 147193856, // ((STANDARD_BT2020 | TRANSFER_SMPTE_170M) | RANGE_FULL)
- HAL_DATASPACE_BT2020_PQ = 163971072, // ((STANDARD_BT2020 | TRANSFER_ST2084) | RANGE_FULL)
- HAL_DATASPACE_DEPTH = 4096, // 0x1000
- HAL_DATASPACE_SENSOR = 4097, // 0x1001
-} android_dataspace_t;
-
-typedef enum {
- HAL_COLOR_MODE_NATIVE = 0,
- HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
- HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
- HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
- HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
- HAL_COLOR_MODE_STANDARD_BT709 = 5,
- HAL_COLOR_MODE_DCI_P3 = 6,
- HAL_COLOR_MODE_SRGB = 7,
- HAL_COLOR_MODE_ADOBE_RGB = 8,
- HAL_COLOR_MODE_DISPLAY_P3 = 9,
-} android_color_mode_t;
-
-typedef enum {
- HAL_COLOR_TRANSFORM_IDENTITY = 0,
- HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
- HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
- HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
- HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
- HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
- HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6,
-} android_color_transform_t;
-
-typedef enum {
- HAL_HDR_DOLBY_VISION = 1,
- HAL_HDR_HDR10 = 2,
- HAL_HDR_HLG = 3,
-} android_hdr_t;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
+#endif // SYSTEM_CORE_GRAPHICS_BASE_H_
diff --git a/libsystem/include/system/graphics-sw.h b/libsystem/include/system/graphics-sw.h
new file mode 100644
index 0000000..9e1a88e
--- /dev/null
+++ b/libsystem/include/system/graphics-sw.h
@@ -0,0 +1,16 @@
+#ifndef SYSTEM_CORE_GRAPHICS_SW_H_
+#define SYSTEM_CORE_GRAPHICS_SW_H_
+
+/* Software formats not in the HAL definitions. */
+typedef enum {
+ HAL_PIXEL_FORMAT_YCBCR_422_888 = 39, // 0x27
+ HAL_PIXEL_FORMAT_YCBCR_444_888 = 40, // 0x28
+ HAL_PIXEL_FORMAT_FLEX_RGB_888 = 41, // 0x29
+ HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 42, // 0x2A
+} android_pixel_format_sw_t;
+
+/* for compatibility */
+#define HAL_PIXEL_FORMAT_YCbCr_422_888 HAL_PIXEL_FORMAT_YCBCR_422_888
+#define HAL_PIXEL_FORMAT_YCbCr_444_888 HAL_PIXEL_FORMAT_YCBCR_444_888
+
+#endif // SYSTEM_CORE_GRAPHICS_SW_H_
diff --git a/libsystem/include/system/graphics.h b/libsystem/include/system/graphics.h
index 1a99187..1b6060a 100644
--- a/libsystem/include/system/graphics.h
+++ b/libsystem/include/system/graphics.h
@@ -25,6 +25,7 @@
* generated.
*/
#include "graphics-base.h"
+#include "graphics-sw.h"
#ifdef __cplusplus
extern "C" {
@@ -32,8 +33,6 @@
/* for compatibility */
#define HAL_PIXEL_FORMAT_YCbCr_420_888 HAL_PIXEL_FORMAT_YCBCR_420_888
-#define HAL_PIXEL_FORMAT_YCbCr_422_888 HAL_PIXEL_FORMAT_YCBCR_422_888
-#define HAL_PIXEL_FORMAT_YCbCr_444_888 HAL_PIXEL_FORMAT_YCBCR_444_888
#define HAL_PIXEL_FORMAT_YCbCr_422_SP HAL_PIXEL_FORMAT_YCBCR_422_SP
#define HAL_PIXEL_FORMAT_YCrCb_420_SP HAL_PIXEL_FORMAT_YCRCB_420_SP
#define HAL_PIXEL_FORMAT_YCbCr_422_I HAL_PIXEL_FORMAT_YCBCR_422_I
@@ -257,6 +256,11 @@
float minLuminance;
};
+struct android_cta861_3_metadata {
+ float maxContentLightLevel;
+ float maxFrameAverageLightLevel;
+};
+
#ifdef __cplusplus
}
#endif
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index df5da65..be2145d 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -190,6 +190,7 @@
"tests/MemoryRangeTest.cpp",
"tests/MemoryRemoteTest.cpp",
"tests/MemoryTest.cpp",
+ "tests/RegsInfoTest.cpp",
"tests/RegsIterateTest.cpp",
"tests/RegsStepIfSignalHandlerTest.cpp",
"tests/RegsTest.cpp",
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index 3d982f6..8ec560c 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -24,6 +24,7 @@
#include <android-base/unique_fd.h>
+#include <dex/class_accessor-inl.h>
#include <dex/code_item_accessors-inl.h>
#include <dex/compact_dex_file.h>
#include <dex/dex_file-inl.h>
@@ -98,38 +99,20 @@
// Check the methods we haven't cached.
for (; class_def_index_ < dex_file_->NumClassDefs(); class_def_index_++) {
- const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(class_def_index_);
- const uint8_t* class_data = dex_file_->GetClassData(class_def);
- if (class_data == nullptr) {
- continue;
- }
+ art::ClassAccessor accessor(*dex_file_, dex_file_->GetClassDef(class_def_index_));
- if (class_it_.get() == nullptr || !class_it_->HasNext()) {
- class_it_.reset(new art::ClassDataItemIterator(*dex_file_.get(), class_data));
- }
-
- for (; class_it_->HasNext(); class_it_->Next()) {
- if (!class_it_->IsAtMethod()) {
- continue;
- }
- const art::DexFile::CodeItem* code_item = class_it_->GetMethodCodeItem();
- if (code_item == nullptr) {
- continue;
- }
- art::CodeItemInstructionAccessor code(*dex_file_.get(), code_item);
+ for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
+ art::CodeItemInstructionAccessor code = method.GetInstructions();
if (!code.HasCodeItem()) {
continue;
}
-
uint32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
- uint32_t offset_end = offset + code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
- uint32_t member_index = class_it_->GetMemberIndex();
+ uint32_t offset_end = offset + code.InsnsSizeInBytes();
+ uint32_t member_index = method.GetIndex();
method_cache_[offset_end] = std::make_pair(offset, member_index);
if (offset <= dex_offset && dex_offset < offset_end) {
*method_name = dex_file_->PrettyMethod(member_index, false);
*method_offset = dex_offset - offset;
- // Move past this element.
- class_it_->Next();
return true;
}
}
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index 508692d..c123158 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -45,7 +45,6 @@
std::map<uint32_t, std::pair<uint64_t, uint32_t>> method_cache_; // dex offset to method index.
uint32_t class_def_index_ = 0;
- std::unique_ptr<art::ClassDataItemIterator> class_it_;
};
class DexFileFromFile : public DexFile {
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 2c00456..f59a472 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -167,15 +167,10 @@
return false;
}
- if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias)) {
- return false;
- }
-
- // We could still potentially unwind without the section header
- // information, so ignore any errors.
- if (!ReadSectionHeaders<EhdrType, ShdrType>(ehdr)) {
- log(0, "Malformed section header found, ignoring...");
- }
+ // If we have enough information that this is an elf file, then allow
+ // malformed program and section headers.
+ ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias);
+ ReadSectionHeaders<EhdrType, ShdrType>(ehdr);
return true;
}
@@ -200,14 +195,12 @@
}
template <typename EhdrType, typename PhdrType>
-bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
+void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
uint64_t offset = ehdr.e_phoff;
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
PhdrType phdr;
if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset;
- return false;
+ return;
}
switch (phdr.p_type) {
@@ -242,11 +235,10 @@
break;
}
}
- return true;
}
template <typename EhdrType, typename ShdrType>
-bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
+void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
uint64_t offset = ehdr.e_shoff;
uint64_t sec_offset = 0;
uint64_t sec_size = 0;
@@ -267,9 +259,7 @@
offset += ehdr.e_shentsize;
for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset;
- return false;
+ return;
}
if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
@@ -277,18 +267,14 @@
// the string terminated names.
ShdrType str_shdr;
if (shdr.sh_link >= ehdr.e_shnum) {
- last_error_.code = ERROR_UNWIND_INFO;
- return false;
+ continue;
}
uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
if (!memory_->Read(str_offset, &str_shdr, sizeof(str_shdr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = str_offset;
- return false;
+ continue;
}
if (str_shdr.sh_type != SHT_STRTAB) {
- last_error_.code = ERROR_UNWIND_INFO;
- return false;
+ continue;
}
symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
str_shdr.sh_offset, str_shdr.sh_size));
@@ -324,7 +310,6 @@
static_cast<uint64_t>(shdr.sh_offset)));
}
}
- return true;
}
template <typename DynType>
@@ -499,11 +484,13 @@
template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
-template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, uint64_t*);
-template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, uint64_t*);
+template void ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&,
+ uint64_t*);
+template void ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&,
+ uint64_t*);
-template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
-template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
+template void ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
+template void ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
diff --git a/libunwindstack/RegsInfo.h b/libunwindstack/RegsInfo.h
index 47825f5..e6dd33c 100644
--- a/libunwindstack/RegsInfo.h
+++ b/libunwindstack/RegsInfo.h
@@ -25,11 +25,13 @@
template <typename AddressType>
struct RegsInfo {
+ static constexpr size_t MAX_REGISTERS = 64;
+
RegsInfo(RegsImpl<AddressType>* regs) : regs(regs) {}
RegsImpl<AddressType>* regs = nullptr;
uint64_t saved_reg_map = 0;
- AddressType saved_regs[64];
+ AddressType saved_regs[MAX_REGISTERS];
inline AddressType Get(uint32_t reg) {
if (IsSaved(reg)) {
@@ -39,23 +41,23 @@
}
inline AddressType* Save(uint32_t reg) {
- if (reg > sizeof(saved_regs) / sizeof(AddressType)) {
- // This should never happen as since all currently supported
- // architectures have the total number of registers < 64.
+ if (reg > MAX_REGISTERS) {
+ // This should never happen since all currently supported
+ // architectures have < 64 total registers.
abort();
}
- saved_reg_map |= 1 << reg;
+ saved_reg_map |= 1ULL << reg;
saved_regs[reg] = (*regs)[reg];
return &(*regs)[reg];
}
inline bool IsSaved(uint32_t reg) {
- if (reg > sizeof(saved_regs) / sizeof(AddressType)) {
- // This should never happen as since all currently supported
- // architectures have the total number of registers < 64.
+ if (reg > MAX_REGISTERS) {
+ // This should never happen since all currently supported
+ // architectures have < 64 total registers.
abort();
}
- return saved_reg_map & (1 << reg);
+ return saved_reg_map & (1ULL << reg);
}
inline uint16_t Total() { return regs->total_regs(); }
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 5c1210d..a45eba8 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -104,10 +104,10 @@
bool ReadAllHeaders(uint64_t* load_bias);
template <typename EhdrType, typename PhdrType>
- bool ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
+ void ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
template <typename EhdrType, typename ShdrType>
- bool ReadSectionHeaders(const EhdrType& ehdr);
+ void ReadSectionHeaders(const EhdrType& ehdr);
template <typename DynType>
bool GetSonameWithTemplate(std::string* soname);
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index 81c0af3..f0b5e3a 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -33,8 +33,7 @@
#if defined(__arm__)
-inline __always_inline void RegsGetLocal(Regs* regs) {
- void* reg_data = regs->RawData();
+inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) {
asm volatile(
".align 2\n"
"bx pc\n"
@@ -55,8 +54,7 @@
#elif defined(__aarch64__)
-inline __always_inline void RegsGetLocal(Regs* regs) {
- void* reg_data = regs->RawData();
+inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) {
asm volatile(
"1:\n"
"stp x0, x1, [%[base], #0]\n"
@@ -87,11 +85,12 @@
extern "C" void AsmGetRegs(void* regs);
-inline void RegsGetLocal(Regs* regs) {
+#endif
+
+inline __attribute__((__always_inline__)) void RegsGetLocal(Regs* regs) {
AsmGetRegs(regs->RawData());
}
-#endif
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index aa6df84..9326bff 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -97,9 +97,15 @@
template <typename ElfType>
void InitHeadersDebugFrameFail();
+ template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+ void InitProgramHeadersMalformed();
+
template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void InitSectionHeadersMalformed();
+ template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+ void InitSectionHeadersMalformedSymData();
+
template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType>
void InitSectionHeaders(uint64_t entry_size);
@@ -677,6 +683,29 @@
InitHeadersDebugFrame<ElfInterface64Fake>();
}
+template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+void ElfInterfaceTest::InitProgramHeadersMalformed() {
+ std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+
+ Ehdr ehdr = {};
+ ehdr.e_phoff = 0x100;
+ ehdr.e_phnum = 3;
+ ehdr.e_phentsize = sizeof(Phdr);
+ memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
+}
+
+TEST_F(ElfInterfaceTest, init_program_headers_malformed32) {
+ InitProgramHeadersMalformed<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, init_program_headers_malformed64) {
+ InitProgramHeadersMalformed<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>();
+}
+
template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void ElfInterfaceTest::InitSectionHeadersMalformed() {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -700,6 +729,80 @@
InitSectionHeadersMalformed<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
}
+template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+void ElfInterfaceTest::InitSectionHeadersMalformedSymData() {
+ std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+
+ uint64_t offset = 0x1000;
+
+ Ehdr ehdr = {};
+ ehdr.e_shoff = offset;
+ ehdr.e_shnum = 5;
+ ehdr.e_shentsize = sizeof(Shdr);
+ memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+ offset += ehdr.e_shentsize;
+
+ Shdr shdr = {};
+ shdr.sh_type = SHT_SYMTAB;
+ shdr.sh_link = 4;
+ shdr.sh_addr = 0x5000;
+ shdr.sh_offset = 0x5000;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = shdr.sh_entsize * 10;
+ memory_.SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr.e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_DYNSYM;
+ shdr.sh_link = 10;
+ shdr.sh_addr = 0x6000;
+ shdr.sh_offset = 0x6000;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = shdr.sh_entsize * 10;
+ memory_.SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr.e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_DYNSYM;
+ shdr.sh_link = 2;
+ shdr.sh_addr = 0x6000;
+ shdr.sh_offset = 0x6000;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = shdr.sh_entsize * 10;
+ memory_.SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr.e_shentsize;
+
+ // The string data for the entries.
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_name = 0x20000;
+ shdr.sh_offset = 0xf000;
+ shdr.sh_size = 0x1000;
+ memory_.SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr.e_shentsize;
+
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0U, elf->debug_frame_offset());
+ EXPECT_EQ(0U, elf->debug_frame_size());
+ EXPECT_EQ(0U, elf->gnu_debugdata_offset());
+ EXPECT_EQ(0U, elf->gnu_debugdata_size());
+
+ std::string name;
+ uint64_t name_offset;
+ ASSERT_FALSE(elf->GetFunctionName(0x90010, &name, &name_offset));
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata32) {
+ InitSectionHeadersMalformedSymData<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata64) {
+ InitSectionHeadersMalformedSymData<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
+}
+
template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType>
void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -708,7 +811,7 @@
Ehdr ehdr = {};
ehdr.e_shoff = offset;
- ehdr.e_shnum = 10;
+ ehdr.e_shnum = 5;
ehdr.e_shentsize = entry_size;
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
@@ -795,7 +898,7 @@
Ehdr ehdr = {};
ehdr.e_shoff = offset;
- ehdr.e_shnum = 10;
+ ehdr.e_shnum = 6;
ehdr.e_shentsize = sizeof(Shdr);
ehdr.e_shstrndx = 2;
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index f599503..861b82f 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -319,7 +319,7 @@
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
ehdr.e_shoff = 0x2000;
ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 4;
+ ehdr.e_shnum = 0;
memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
Elf* elf = info.GetElf(process_memory_, false);
@@ -341,7 +341,7 @@
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
ehdr.e_shoff = 0x2000;
ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 4;
+ ehdr.e_shnum = 0;
memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
Elf* elf = info.GetElf(process_memory_, false);
@@ -368,7 +368,7 @@
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
ehdr.e_shoff = 0x2000;
ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 4;
+ ehdr.e_shnum = 0;
memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
Elf* elf_in_threads[kNumConcurrentThreads];
diff --git a/libunwindstack/tests/RegsInfoTest.cpp b/libunwindstack/tests/RegsInfoTest.cpp
new file mode 100644
index 0000000..052b5bf
--- /dev/null
+++ b/libunwindstack/tests/RegsInfoTest.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Regs.h>
+
+#include "RegsFake.h"
+#include "RegsInfo.h"
+
+namespace unwindstack {
+
+TEST(RegsInfoTest, single_uint32_t) {
+ RegsImplFake<uint32_t> regs(10);
+ RegsInfo<uint32_t> info(®s);
+
+ regs[1] = 0x100;
+ ASSERT_FALSE(info.IsSaved(1));
+ ASSERT_EQ(0x100U, info.Get(1));
+ ASSERT_EQ(10, info.Total());
+
+ uint32_t* value = info.Save(1);
+ ASSERT_EQ(value, ®s[1]);
+ regs[1] = 0x200;
+ ASSERT_TRUE(info.IsSaved(1));
+ ASSERT_EQ(0x100U, info.Get(1));
+ ASSERT_EQ(0x200U, regs[1]);
+}
+
+TEST(RegsInfoTest, single_uint64_t) {
+ RegsImplFake<uint64_t> regs(20);
+ RegsInfo<uint64_t> info(®s);
+
+ regs[3] = 0x300;
+ ASSERT_FALSE(info.IsSaved(3));
+ ASSERT_EQ(0x300U, info.Get(3));
+ ASSERT_EQ(20, info.Total());
+
+ uint64_t* value = info.Save(3);
+ ASSERT_EQ(value, ®s[3]);
+ regs[3] = 0x400;
+ ASSERT_TRUE(info.IsSaved(3));
+ ASSERT_EQ(0x300U, info.Get(3));
+ ASSERT_EQ(0x400U, regs[3]);
+}
+
+TEST(RegsInfoTest, all) {
+ RegsImplFake<uint64_t> regs(64);
+ RegsInfo<uint64_t> info(®s);
+
+ for (uint32_t i = 0; i < 64; i++) {
+ regs[i] = i * 0x100;
+ ASSERT_EQ(i * 0x100, info.Get(i)) << "Reg " + std::to_string(i) + " failed.";
+ }
+
+ for (uint32_t i = 0; i < 64; i++) {
+ ASSERT_FALSE(info.IsSaved(i)) << "Reg " + std::to_string(i) + " failed.";
+ uint64_t* reg = info.Save(i);
+ ASSERT_EQ(reg, ®s[i]) << "Reg " + std::to_string(i) + " failed.";
+ *reg = i * 0x1000 + 0x100;
+ ASSERT_EQ(i * 0x1000 + 0x100, regs[i]) << "Reg " + std::to_string(i) + " failed.";
+ }
+
+ for (uint32_t i = 0; i < 64; i++) {
+ ASSERT_TRUE(info.IsSaved(i)) << "Reg " + std::to_string(i) + " failed.";
+ ASSERT_EQ(i * 0x100, info.Get(i)) << "Reg " + std::to_string(i) + " failed.";
+ }
+}
+
+} // namespace unwindstack
diff --git a/libusbhost/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h
index 9758b18..7e62542 100644
--- a/libusbhost/include/usbhost/usbhost.h
+++ b/libusbhost/include/usbhost/usbhost.h
@@ -137,6 +137,7 @@
/* Returns the USB product ID from the device descriptor for the USB device */
uint16_t usb_device_get_product_id(struct usb_device *device);
+/* Returns a pointer to device descriptor */
const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device);
/* Returns a USB descriptor string for the given string ID.
@@ -156,6 +157,12 @@
int usb_device_get_string_ucs2(struct usb_device* device, int id, int timeout, void** ucs2_out,
size_t* response_size);
+/* Returns the length in bytes read into the raw descriptors array */
+size_t usb_device_get_descriptors_length(const struct usb_device* device);
+
+/* Returns a pointer to the raw descriptors array */
+const unsigned char* usb_device_get_raw_descriptors(const struct usb_device* device);
+
/* Returns a USB descriptor string for the given string ID.
* Used to implement usb_device_get_manufacturer_name,
* usb_device_get_product_name and usb_device_get_serial.
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index cb8d430..415488f 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -76,9 +76,11 @@
int wddbus;
};
+#define MAX_DESCRIPTORS_LENGTH 4096
+
struct usb_device {
char dev_name[64];
- unsigned char desc[4096];
+ unsigned char desc[MAX_DESCRIPTORS_LENGTH];
int desc_length;
int fd;
int writeable;
@@ -387,6 +389,8 @@
return device;
failed:
+ // TODO It would be more appropriate to have callers do this
+ // since this function doesn't "own" this file descriptor.
close(fd);
free(device);
return NULL;
@@ -455,11 +459,18 @@
return __le16_to_cpu(desc->idProduct);
}
-const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device)
-{
+const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device* device) {
return (struct usb_device_descriptor*)device->desc;
}
+size_t usb_device_get_descriptors_length(const struct usb_device* device) {
+ return device->desc_length;
+}
+
+const unsigned char* usb_device_get_raw_descriptors(const struct usb_device* device) {
+ return device->desc;
+}
+
/* Returns a USB descriptor string for the given string ID.
* Return value: < 0 on error. 0 on success.
* The string is returned in ucs2_out in USB-native UCS-2 encoding.
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
index bd6015e..fe6f33d 100644
--- a/libutils/CallStack.cpp
+++ b/libutils/CallStack.cpp
@@ -16,16 +16,15 @@
#define LOG_TAG "CallStack"
-#include <utils/CallStack.h>
-
-#include <memory>
-
#include <utils/Printer.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <backtrace/Backtrace.h>
+#define CALLSTACK_WEAK // Don't generate weak definitions.
+#include <utils/CallStack.h>
+
namespace android {
CallStack::CallStack() {
@@ -76,4 +75,30 @@
}
}
+// The following four functions may be used via weak symbol references from libutils.
+// Clients assume that if any of these symbols are available, then deleteStack() is.
+
+#ifdef WEAKS_AVAILABLE
+
+CallStack::CallStackUPtr CallStack::getCurrentInternal(int ignoreDepth) {
+ CallStack::CallStackUPtr stack(new CallStack());
+ stack->update(ignoreDepth + 1);
+ return stack;
+}
+
+void CallStack::logStackInternal(const char* logtag, const CallStack* stack,
+ android_LogPriority priority) {
+ stack->log(logtag, priority);
+}
+
+String8 CallStack::stackToStringInternal(const char* prefix, const CallStack* stack) {
+ return stack->toString(prefix);
+}
+
+void CallStack::deleteStack(CallStack* stack) {
+ delete stack;
+}
+
+#endif // WEAKS_AVAILABLE
+
}; // namespace android
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 9074850..3f1e79a 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -17,30 +17,41 @@
#define LOG_TAG "RefBase"
// #define LOG_NDEBUG 0
+#include <memory>
+
#include <utils/RefBase.h>
#include <utils/CallStack.h>
+#include <utils/Mutex.h>
+
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
-// compile with refcounting debugging enabled
-#define DEBUG_REFS 0
+// Compile with refcounting debugging enabled.
+#define DEBUG_REFS 0
+
+// The following three are ignored unless DEBUG_REFS is set.
// whether ref-tracking is enabled by default, if not, trackMe(true, false)
// needs to be called explicitly
-#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
+#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
// whether callstack are collected (significantly slows things down)
-#define DEBUG_REFS_CALLSTACK_ENABLED 1
+#define DEBUG_REFS_CALLSTACK_ENABLED 1
// folder where stack traces are saved when DEBUG_REFS is enabled
// this folder needs to exist and be writable
-#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
+#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
// log all reference counting operations
-#define PRINT_REFS 0
+#define PRINT_REFS 0
+
+// Continue after logging a stack trace if ~RefBase discovers that reference
+// count has never been incremented. Normally we conspicuously crash in that
+// case.
+#define DEBUG_REFBASE_DESTRUCTION 1
// ---------------------------------------------------------------------------
@@ -184,7 +195,7 @@
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
- refs->stack.log(LOG_TAG);
+ CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
refs = refs->next;
}
@@ -198,14 +209,14 @@
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
- refs->stack.log(LOG_TAG);
+ CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
refs = refs->next;
}
}
if (dumpStack) {
ALOGE("above errors at:");
- CallStack stack(LOG_TAG);
+ CallStack::logStack(LOG_TAG);
}
}
@@ -279,7 +290,7 @@
this);
int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
if (rc >= 0) {
- write(rc, text.string(), text.length());
+ (void)write(rc, text.string(), text.length());
close(rc);
ALOGD("STACK TRACE for %p saved in %s", this, name);
}
@@ -294,7 +305,7 @@
ref_entry* next;
const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
- CallStack stack;
+ CallStack::CallStackUPtr stack;
#endif
int32_t ref;
};
@@ -311,7 +322,7 @@
ref->ref = mRef;
ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED
- ref->stack.update(2);
+ ref->stack = CallStack::getCurrent(2);
#endif
ref->next = *refs;
*refs = ref;
@@ -346,7 +357,7 @@
ref = ref->next;
}
- CallStack stack(LOG_TAG);
+ CallStack::logStack(LOG_TAG);
}
}
@@ -373,7 +384,7 @@
inc, refs->id, refs->ref);
out->append(buf);
#if DEBUG_REFS_CALLSTACK_ENABLED
- out->append(refs->stack.toString("\t\t"));
+ out->append(CallStack::stackToString("\t\t", refs->stack.get()));
#else
out->append("\t\t(call stacks disabled)");
#endif
@@ -700,16 +711,16 @@
if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
delete mRefs;
}
- } else if (mRefs->mStrong.load(std::memory_order_relaxed)
- == INITIAL_STRONG_VALUE) {
+ } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
// We never acquired a strong reference on this object.
- LOG_ALWAYS_FATAL_IF(mRefs->mWeak.load() != 0,
- "RefBase: Explicit destruction with non-zero weak "
- "reference count");
- // TODO: Always report if we get here. Currently MediaMetadataRetriever
- // C++ objects are inconsistently managed and sometimes get here.
- // There may be other cases, but we believe they should all be fixed.
- delete mRefs;
+#if DEBUG_REFBASE_DESTRUCTION
+ // Treating this as fatal is prone to causing boot loops. For debugging, it's
+ // better to treat as non-fatal.
+ ALOGD("RefBase: Explicit destruction, weak count = %d (in %p)", mRefs->mWeak.load(), this);
+ CallStack::logStack(LOG_TAG);
+#else
+ LOG_ALWAYS_FATAL("RefBase: Explicit destruction, weak count = %d", mRefs->mWeak.load());
+#endif
}
// For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
const_cast<weakref_impl*&>(mRefs) = nullptr;
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index f820b8b..5c0b406 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -66,6 +66,23 @@
return getEmptyString();
}
+static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len) {
+ if (u16len >= SIZE_MAX / sizeof(char16_t)) {
+ android_errorWriteLog(0x534e4554, "73826242");
+ abort();
+ }
+
+ SharedBuffer* buf = SharedBuffer::alloc((u16len + 1) * sizeof(char16_t));
+ ALOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (buf) {
+ char16_t* str = (char16_t*)buf->data();
+ memcpy(str, u16str, u16len * sizeof(char16_t));
+ str[u16len] = 0;
+ return str;
+ }
+ return getEmptyString();
+}
+
// ---------------------------------------------------------------------------
String16::String16()
@@ -98,35 +115,9 @@
setTo(o, len, begin);
}
-String16::String16(const char16_t* o)
-{
- size_t len = strlen16(o);
- SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
- ALOG_ASSERT(buf, "Unable to allocate shared buffer");
- if (buf) {
- char16_t* str = (char16_t*)buf->data();
- strcpy16(str, o);
- mString = str;
- return;
- }
+String16::String16(const char16_t* o) : mString(allocFromUTF16(o, strlen16(o))) {}
- mString = getEmptyString();
-}
-
-String16::String16(const char16_t* o, size_t len)
-{
- SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
- ALOG_ASSERT(buf, "Unable to allocate shared buffer");
- if (buf) {
- char16_t* str = (char16_t*)buf->data();
- memcpy(str, o, len*sizeof(char16_t));
- str[len] = 0;
- mString = str;
- return;
- }
-
- mString = getEmptyString();
-}
+String16::String16(const char16_t* o, size_t len) : mString(allocFromUTF16(o, len)) {}
String16::String16(const String8& o)
: mString(allocFromUTF8(o.string(), o.size()))
@@ -188,6 +179,11 @@
status_t String16::setTo(const char16_t* other, size_t len)
{
+ if (len >= SIZE_MAX / sizeof(char16_t)) {
+ android_errorWriteLog(0x534e4554, "73826242");
+ abort();
+ }
+
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
->editResize((len+1)*sizeof(char16_t));
if (buf) {
@@ -211,6 +207,11 @@
return NO_ERROR;
}
+ if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) {
+ android_errorWriteLog(0x534e4554, "73826242");
+ abort();
+ }
+
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
->editResize((myLen+otherLen+1)*sizeof(char16_t));
if (buf) {
@@ -232,6 +233,11 @@
return NO_ERROR;
}
+ if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) {
+ android_errorWriteLog(0x534e4554, "73826242");
+ abort();
+ }
+
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
->editResize((myLen+otherLen+1)*sizeof(char16_t));
if (buf) {
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 0c1b875..56004fe 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_CALLSTACK_H
#define ANDROID_CALLSTACK_H
+#include <memory>
+
#include <android/log.h>
#include <backtrace/backtrace_constants.h>
#include <utils/String8.h>
@@ -25,6 +27,19 @@
#include <stdint.h>
#include <sys/types.h>
+#if !defined(__APPLE__) && !defined(_WIN32)
+# define WEAKS_AVAILABLE 1
+#endif
+#ifndef CALLSTACK_WEAK
+# ifdef WEAKS_AVAILABLE
+# define CALLSTACK_WEAK __attribute__((weak))
+# else // !WEAKS_AVAILABLE
+# define CALLSTACK_WEAK
+# endif // !WEAKS_AVAILABLE
+#endif // CALLSTACK_WEAK predefined
+
+#define ALWAYS_INLINE __attribute__((always_inline))
+
namespace android {
class Printer;
@@ -36,7 +51,7 @@
CallStack();
// Create a callstack with the current thread's stack trace.
// Immediately dump it to logcat using the given logtag.
- CallStack(const char* logtag, int32_t ignoreDepth=1);
+ CallStack(const char* logtag, int32_t ignoreDepth = 1);
~CallStack();
// Reset the stack frames (same as creating an empty call stack).
@@ -44,7 +59,7 @@
// Immediately collect the stack traces for the specified thread.
// The default is to dump the stack of the current call.
- void update(int32_t ignoreDepth=1, pid_t tid=BACKTRACE_CURRENT_THREAD);
+ void update(int32_t ignoreDepth = 1, pid_t tid = BACKTRACE_CURRENT_THREAD);
// Dump a stack trace to the log using the supplied logtag.
void log(const char* logtag,
@@ -63,7 +78,88 @@
// Get the count of stack frames that are in this call stack.
size_t size() const { return mFrameLines.size(); }
-private:
+ // DO NOT USE ANYTHING BELOW HERE. The following public members are expected
+ // to disappear again shortly, once a better replacement facility exists.
+ // The replacement facility will be incompatible!
+
+ // Debugging accesses to some basic functionality. These use weak symbols to
+ // avoid introducing a dependency on libutilscallstack. Such a dependency from
+ // libutils results in a cyclic build dependency. These routines can be called
+ // from within libutils. But if the actual library is unavailable, they do
+ // nothing.
+ //
+ // DO NOT USE THESE. They will disappear.
+ struct StackDeleter {
+#ifdef WEAKS_AVAILABLE
+ void operator()(CallStack* stack) {
+ deleteStack(stack);
+ }
+#else
+ void operator()(CallStack*) {}
+#endif
+ };
+
+ typedef std::unique_ptr<CallStack, StackDeleter> CallStackUPtr;
+
+ // Return current call stack if possible, nullptr otherwise.
+#ifdef WEAKS_AVAILABLE
+ static CallStackUPtr ALWAYS_INLINE getCurrent(int32_t ignoreDepth = 1) {
+ if (reinterpret_cast<uintptr_t>(getCurrentInternal) == 0) {
+ ALOGW("CallStack::getCurrentInternal not linked, returning null");
+ return CallStackUPtr(nullptr);
+ } else {
+ return getCurrentInternal(ignoreDepth);
+ }
+ }
+#else // !WEAKS_AVAILABLE
+ static CallStackUPtr ALWAYS_INLINE getCurrent(int32_t = 1) {
+ return CallStackUPtr(nullptr);
+ }
+#endif // !WEAKS_AVAILABLE
+
+#ifdef WEAKS_AVAILABLE
+ static void ALWAYS_INLINE logStack(const char* logtag, CallStack* stack = getCurrent().get(),
+ android_LogPriority priority = ANDROID_LOG_DEBUG) {
+ if (reinterpret_cast<uintptr_t>(logStackInternal) != 0 && stack != nullptr) {
+ logStackInternal(logtag, stack, priority);
+ } else {
+ ALOGW("CallStack::logStackInternal not linked");
+ }
+ }
+
+#else
+ static void ALWAYS_INLINE logStack(const char*, CallStack* = getCurrent().get(),
+ android_LogPriority = ANDROID_LOG_DEBUG) {
+ }
+#endif // !WEAKS_AVAILABLE
+
+#ifdef WEAKS_AVAILABLE
+ static String8 ALWAYS_INLINE stackToString(const char* prefix = nullptr,
+ const CallStack* stack = getCurrent().get()) {
+ if (reinterpret_cast<uintptr_t>(stackToStringInternal) != 0 && stack != nullptr) {
+ return stackToStringInternal(prefix, stack);
+ } else {
+ return String8("<CallStack package not linked>");
+ }
+ }
+#else // !WEAKS_AVAILABLE
+ static String8 ALWAYS_INLINE stackToString(const char* = nullptr,
+ const CallStack* = getCurrent().get()) {
+ return String8("<CallStack package not linked>");
+ }
+#endif // !WEAKS_AVAILABLE
+
+ private:
+#ifdef WEAKS_AVAILABLE
+ static CallStackUPtr CALLSTACK_WEAK getCurrentInternal(int32_t ignoreDepth);
+ static void CALLSTACK_WEAK logStackInternal(const char* logtag, const CallStack* stack,
+ android_LogPriority priority);
+ static String8 CALLSTACK_WEAK stackToStringInternal(const char* prefix, const CallStack* stack);
+ // The deleter is only invoked on non-null pointers. Hence it will never be
+ // invoked if CallStack is not linked.
+ static void CALLSTACK_WEAK deleteStack(CallStack* stack);
+#endif // WEAKS_AVAILABLE
+
Vector<String8> mFrameLines;
};
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 377479f..23dd5dc 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -643,6 +643,55 @@
ASSERT_STREQ("I/O error", ErrorCodeString(kIoError));
}
+// A zip file whose local file header at offset zero is corrupted.
+//
+// ---------------
+// cat foo > a.txt
+// zip a.zip a.txt
+// cat a.zip | xxd -i
+//
+// Manual changes :
+// [2] = 0xff // Corrupt the LFH signature of entry 0.
+// [3] = 0xff // Corrupt the LFH signature of entry 0.
+static const std::vector<uint8_t> kZipFileWithBrokenLfhSignature{
+ //[lfh-sig-----------], [lfh contents---------------------------------
+ 0x50, 0x4b, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80,
+ //--------------------------------------------------------------------
+ 0x09, 0x4b, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
+ //-------------------------------] [file-name-----------------], [---
+ 0x00, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55,
+ // entry-contents------------------------------------------------------
+ 0x54, 0x09, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x51, 0x24, 0x8b, 0x59,
+ //--------------------------------------------------------------------
+ 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88,
+ //-------------------------------------], [cd-record-sig-------], [---
+ 0x13, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x0a, 0x50, 0x4b, 0x01, 0x02, 0x1e,
+ // cd-record-----------------------------------------------------------
+ 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80, 0x09, 0x4b, 0xa8,
+ //--------------------------------------------------------------------
+ 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05,
+ //--------------------------------------------------------------------
+ 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0,
+ //-] [lfh-file-header-off-], [file-name-----------------], [extra----
+ 0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54,
+ //--------------------------------------------------------------------
+ 0x05, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x75, 0x78, 0x0b, 0x00, 0x01,
+ //-------------------------------------------------------], [eocd-sig-
+ 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88, 0x13, 0x00, 0x00, 0x50, 0x4b,
+ //-------], [---------------------------------------------------------
+ 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4b, 0x00,
+ //-------------------------------------------]
+ 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+TEST(ziparchive, BrokenLfhSignature) {
+ TemporaryFile tmp_file;
+ ASSERT_NE(-1, tmp_file.fd);
+ ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &kZipFileWithBrokenLfhSignature[0],
+ kZipFileWithBrokenLfhSignature.size()));
+ ZipArchiveHandle handle;
+ ASSERT_EQ(-1, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle));
+}
+
class VectorReader : public zip_archive::Reader {
public:
VectorReader(const std::vector<uint8_t>& input) : Reader(), input_(input) {}
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index f357cc2..3b28775 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -55,6 +55,7 @@
using namespace std::chrono_literals;
using namespace std::chrono;
+using namespace std::literals;
namespace {
@@ -497,8 +498,7 @@
}
::usleep(200000); // let everything settle
}
- llkWriteStringToFile(std::string("SysRq : Trigger a crash : 'livelock,") + state + "'\n",
- "/dev/kmsg");
+ llkWriteStringToFile("SysRq : Trigger a crash : 'livelock,"s + state + "'\n", "/dev/kmsg");
android::base::WriteStringToFd("c", sysrqTriggerFd);
// NOTREACHED
// DYB
@@ -1070,7 +1070,7 @@
std::to_string(kthreaddPid) + "," + std::to_string(::getpid()) + "," +
std::to_string(::gettid()) + "," LLK_BLACKLIST_PROCESS_DEFAULT);
if (threadname) {
- defaultBlacklistProcess += std::string(",") + threadname;
+ defaultBlacklistProcess += ","s + threadname;
}
for (int cpu = 1; cpu < get_nprocs_conf(); ++cpu) {
defaultBlacklistProcess += ",[watchdog/" + std::to_string(cpu) + "]";
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index 2efda86..903d0e2 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -6,18 +6,34 @@
"libcutils",
"liblog",
],
+ static_libs: [
+ "libstatslogc",
+ "libstatssocket",
+ ],
local_include_dirs: ["include"],
- cflags: ["-Werror"],
-
+ cflags: ["-Werror", "-DLMKD_TRACE_KILLS"],
init_rc: ["lmkd.rc"],
-
product_variables: {
- debuggable: {
+ use_lmkd_stats_log: {
cflags: [
- "-DLMKD_TRACE_KILLS"
+ "-DLMKD_LOG_STATS"
],
},
},
+ logtags: ["event.logtags"],
+}
+
+cc_library_static {
+ name: "libstatslogc",
+ srcs: ["statslog.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: ["libstatssocket",],
}
cc_library_static {
diff --git a/lmkd/event.logtags b/lmkd/event.logtags
new file mode 100644
index 0000000..7c2cd18
--- /dev/null
+++ b/lmkd/event.logtags
@@ -0,0 +1,38 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace. Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+# (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# s: Number of seconds (monotonic time)
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+# for meminfo logs
+10195355 meminfo (MemFree|1),(Cached|1),(SwapCached|1),(Buffers|1),(Shmem|1),(Unevictable|1),(SwapFree|1),(ActiveAnon|1),(InactiveAnon|1),(ActiveFile|1),(InactiveFile|1),(SReclaimable|1),(SUnreclaim|1),(KernelStack|1),(PageTables|1),(ION_heap|1),(ION_heap_pool|1),(CmaFree|1)
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index c2487d6..59f17f2 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -37,6 +37,11 @@
#include <cutils/sockets.h>
#include <lmkd.h>
#include <log/log.h>
+#include <log/log_event_list.h>
+
+#ifdef LMKD_LOG_STATS
+#include "statslog.h"
+#endif
/*
* Define LMKD_TRACE_KILLS to record lmkd kills in kernel traces
@@ -52,8 +57,8 @@
#else /* LMKD_TRACE_KILLS */
-#define TRACE_KILL_START(pid)
-#define TRACE_KILL_END()
+#define TRACE_KILL_START(pid) ((void)(pid))
+#define TRACE_KILL_END() ((void)0)
#endif /* LMKD_TRACE_KILLS */
@@ -68,6 +73,9 @@
#define MEMINFO_PATH "/proc/meminfo"
#define LINE_MAX 128
+/* Android Logger event logtags (see event.logtags) */
+#define MEMINFO_LOG_TAG 10195355
+
/* gid containing AID_SYSTEM required */
#define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
#define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
@@ -78,6 +86,11 @@
/* Defined as ProcessList.SYSTEM_ADJ in ProcessList.java */
#define SYSTEM_ADJ (-900)
+#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
+#define STRINGIFY_INTERNAL(x) #x
+
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
/* default to old in-kernel interface if no memory pressure events */
static bool use_inkernel_interface = true;
static bool has_inkernel_module;
@@ -111,6 +124,9 @@
static bool kill_heaviest_task;
static unsigned long kill_timeout_ms;
static bool use_minfree_levels;
+static bool per_app_memcg;
+
+static android_log_context ctx;
/* data required to handle events */
struct event_handler_info {
@@ -190,7 +206,17 @@
MI_SHMEM,
MI_UNEVICTABLE,
MI_FREE_SWAP,
- MI_DIRTY,
+ MI_ACTIVE_ANON,
+ MI_INACTIVE_ANON,
+ MI_ACTIVE_FILE,
+ MI_INACTIVE_FILE,
+ MI_SRECLAIMABLE,
+ MI_SUNRECLAIM,
+ MI_KERNEL_STACK,
+ MI_PAGE_TABLES,
+ MI_ION_HELP,
+ MI_ION_HELP_POOL,
+ MI_CMA_FREE,
MI_FIELD_COUNT
};
@@ -202,7 +228,17 @@
"Shmem:",
"Unevictable:",
"SwapFree:",
- "Dirty:",
+ "Active(anon):",
+ "Inactive(anon):",
+ "Active(file):",
+ "Inactive(file):",
+ "SReclaimable:",
+ "SUnreclaim:",
+ "KernelStack:",
+ "PageTables:",
+ "ION_heap:",
+ "ION_heap_pool:",
+ "CmaFree:",
};
union meminfo {
@@ -214,7 +250,17 @@
int64_t shmem;
int64_t unevictable;
int64_t free_swap;
- int64_t dirty;
+ int64_t active_anon;
+ int64_t inactive_anon;
+ int64_t active_file;
+ int64_t inactive_file;
+ int64_t sreclaimable;
+ int64_t sunreclaimable;
+ int64_t kernel_stack;
+ int64_t page_tables;
+ int64_t ion_heap;
+ int64_t ion_heap_pool;
+ int64_t cma_free;
/* fields below are calculated rather than read from the file */
int64_t nr_file_pages;
} field;
@@ -245,6 +291,11 @@
int fd;
};
+#ifdef LMKD_LOG_STATS
+static bool enable_stats_log;
+static android_log_context log_ctx;
+#endif
+
#define PIDHASH_SZ 1024
static struct proc *pidhash[PIDHASH_SZ];
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
@@ -472,7 +523,7 @@
return;
}
- if (low_ram_device) {
+ if (per_app_memcg) {
if (params.oomadj >= 900) {
soft_limit_mult = 0;
} else if (params.oomadj >= 800) {
@@ -718,6 +769,58 @@
maxevents++;
}
+#ifdef LMKD_LOG_STATS
+static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) {
+ char key[LINE_MAX + 1];
+ int64_t value;
+
+ sscanf(line, "%" STRINGIFY(LINE_MAX) "s %" SCNd64 "", key, &value);
+
+ if (strcmp(key, "total_") < 0) {
+ return;
+ }
+
+ if (!strcmp(key, "total_pgfault"))
+ mem_st->pgfault = value;
+ else if (!strcmp(key, "total_pgmajfault"))
+ mem_st->pgmajfault = value;
+ else if (!strcmp(key, "total_rss"))
+ mem_st->rss_in_bytes = value;
+ else if (!strcmp(key, "total_cache"))
+ mem_st->cache_in_bytes = value;
+ else if (!strcmp(key, "total_swap"))
+ mem_st->swap_in_bytes = value;
+}
+
+static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) {
+ FILE *fp;
+ char buf[PATH_MAX];
+
+ /*
+ * Per-application memory.stat files are available only when
+ * per-application memcgs are enabled.
+ */
+ if (!per_app_memcg)
+ return -1;
+
+ snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid);
+
+ fp = fopen(buf, "r");
+
+ if (fp == NULL) {
+ ALOGE("%s open failed: %s", buf, strerror(errno));
+ return -1;
+ }
+
+ while (fgets(buf, PAGE_SIZE, fp) != NULL ) {
+ memory_stat_parse_line(buf, mem_st);
+ }
+ fclose(fp);
+
+ return 0;
+}
+#endif
+
/* /prop/zoneinfo parsing routines */
static int64_t zoneinfo_parse_protection(char *cp) {
int64_t max = 0;
@@ -857,6 +960,15 @@
return 0;
}
+static void meminfo_log(union meminfo *mi) {
+ for (int field_idx = 0; field_idx < MI_FIELD_COUNT; field_idx++) {
+ android_log_write_int32(ctx, (int32_t)min(mi->arr[field_idx] * page_k, INT32_MAX));
+ }
+
+ android_log_write_list(ctx, LOG_ID_EVENTS);
+ android_log_reset(ctx);
+}
+
static int proc_get_size(int pid) {
char path[PATH_MAX];
char line[LINE_MAX];
@@ -943,6 +1055,11 @@
int tasksize;
int r;
+#ifdef LMKD_LOG_STATS
+ struct memory_stat mem_st = {};
+ int memory_stat_parse_result = -1;
+#endif
+
taskname = proc_get_name(pid);
if (!taskname) {
pid_remove(pid);
@@ -955,6 +1072,12 @@
return -1;
}
+#ifdef LMKD_LOG_STATS
+ if (enable_stats_log) {
+ memory_stat_parse_result = memory_stat_parse(&mem_st, pid, uid);
+ }
+#endif
+
TRACE_KILL_START(pid);
/* CAP_KILL required */
@@ -971,6 +1094,15 @@
if (r) {
ALOGE("kill(%d): errno=%d", pid, errno);
return -1;
+ } else {
+#ifdef LMKD_LOG_STATS
+ if (memory_stat_parse_result == 0) {
+ stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname,
+ procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes,
+ mem_st.cache_in_bytes, mem_st.swap_in_bytes);
+ }
+#endif
+ return tasksize;
}
return tasksize;
@@ -987,6 +1119,10 @@
int killed_size;
int pages_freed = 0;
+#ifdef LMKD_LOG_STATS
+ bool lmk_state_change_start = false;
+#endif
+
for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
struct proc *procp;
@@ -999,14 +1135,35 @@
killed_size = kill_one_process(procp, min_score_adj, level);
if (killed_size >= 0) {
+#ifdef LMKD_LOG_STATS
+ if (enable_stats_log && !lmk_state_change_start) {
+ lmk_state_change_start = true;
+ stats_write_lmk_state_changed(log_ctx, LMK_STATE_CHANGED,
+ LMK_STATE_CHANGE_START);
+ }
+#endif
+
pages_freed += killed_size;
if (pages_freed >= pages_to_free) {
+
+#ifdef LMKD_LOG_STATS
+ if (enable_stats_log && lmk_state_change_start) {
+ stats_write_lmk_state_changed(log_ctx, LMK_STATE_CHANGED,
+ LMK_STATE_CHANGE_STOP);
+ }
+#endif
return pages_freed;
}
}
}
}
+#ifdef LMKD_LOG_STATS
+ if (enable_stats_log && lmk_state_change_start) {
+ stats_write_lmk_state_changed(log_ctx, LMK_STATE_CHANGED, LMK_STATE_CHANGE_STOP);
+ }
+#endif
+
return pages_freed;
}
@@ -1121,10 +1278,8 @@
}
if (skip_count > 0) {
- if (debug_process_killing) {
- ALOGI("%lu memory pressure events were skipped after a kill!",
- skip_count);
- }
+ ALOGI("%lu memory pressure events were skipped after a kill!",
+ skip_count);
skip_count = 0;
}
@@ -1221,6 +1376,8 @@
if (debug_process_killing) {
ALOGI("Nothing to kill");
}
+ } else {
+ meminfo_log(&mi);
}
} else {
int pages_freed;
@@ -1249,27 +1406,29 @@
return;
}
min_score_adj = level_oomadj[level];
- } else {
- if (debug_process_killing) {
- ALOGI("Killing because cache %ldkB is below "
- "limit %ldkB for oom_adj %d\n"
- " Free memory is %ldkB %s reserved",
- other_file * page_k, minfree * page_k, min_score_adj,
- other_free * page_k, other_free >= 0 ? "above" : "below");
- }
}
- if (debug_process_killing) {
- ALOGI("Trying to free %d pages", pages_to_free);
- }
pages_freed = find_and_kill_processes(level, min_score_adj, pages_to_free);
+
+ if (use_minfree_levels) {
+ ALOGI("Killing because cache %ldkB is below "
+ "limit %ldkB for oom_adj %d\n"
+ " Free memory is %ldkB %s reserved",
+ other_file * page_k, minfree * page_k, min_score_adj,
+ other_free * page_k, other_free >= 0 ? "above" : "below");
+ }
+
if (pages_freed < pages_to_free) {
- if (debug_process_killing) {
- ALOGI("Unable to free enough memory (pages freed=%d)", pages_freed);
- }
+ ALOGI("Unable to free enough memory (pages to free=%d, pages freed=%d)",
+ pages_to_free, pages_freed);
} else {
+ ALOGI("Reclaimed enough memory (pages to free=%d, pages freed=%d)",
+ pages_to_free, pages_freed);
gettimeofday(&last_report_tm, NULL);
}
+ if (pages_freed > 0) {
+ meminfo_log(&mi);
+ }
}
}
@@ -1481,6 +1640,14 @@
(unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
use_minfree_levels =
property_get_bool("ro.lmk.use_minfree_levels", false);
+ per_app_memcg =
+ property_get_bool("ro.config.per_app_memcg", low_ram_device);
+
+ ctx = create_android_logger(MEMINFO_LOG_TAG);
+
+#ifdef LMKD_LOG_STATS
+ statslog_init(&log_ctx, &enable_stats_log);
+#endif
if (!init()) {
if (!use_inkernel_interface) {
@@ -1509,6 +1676,12 @@
mainloop();
}
+#ifdef LMKD_LOG_STATS
+ statslog_destroy(&log_ctx);
+#endif
+
+ android_log_destroy(&ctx);
+
ALOGI("exiting");
return 0;
}
diff --git a/lmkd/statslog.c b/lmkd/statslog.c
new file mode 100644
index 0000000..66d1164
--- /dev/null
+++ b/lmkd/statslog.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2018 Google, Inc
+ *
+ * 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 <assert.h>
+#include <errno.h>
+#include <log/log_id.h>
+#include <stats_event_list.h>
+#include <time.h>
+
+static int64_t getElapsedRealTimeNs() {
+ struct timespec t;
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(CLOCK_BOOTTIME, &t);
+ return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;
+}
+
+/**
+ * Logs the change in LMKD state which is used as start/stop boundaries for logging
+ * LMK_KILL_OCCURRED event.
+ * Code: LMK_STATE_CHANGED = 54
+ */
+int
+stats_write_lmk_state_changed(android_log_context ctx, int32_t code, int32_t state) {
+ assert(ctx != NULL);
+ int ret = -EINVAL;
+ if (!ctx) {
+ return ret;
+ }
+
+ reset_log_context(ctx);
+
+ if ((ret = android_log_write_int64(ctx, getElapsedRealTimeNs())) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int32(ctx, code)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int32(ctx, state)) < 0) {
+ return ret;
+ }
+
+ return write_to_logger(ctx, LOG_ID_STATS);
+}
+
+/**
+ * Logs the event when LMKD kills a process to reduce memory pressure.
+ * Code: LMK_KILL_OCCURRED = 51
+ */
+int
+stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid,
+ char const* process_name, int32_t oom_score, int64_t pgfault,
+ int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes,
+ int64_t swap_in_bytes) {
+ assert(ctx != NULL);
+ int ret = -EINVAL;
+ if (!ctx) {
+ return ret;
+ }
+ reset_log_context(ctx);
+
+ if ((ret = android_log_write_int64(ctx, getElapsedRealTimeNs())) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int32(ctx, code)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int32(ctx, uid)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_string8(ctx, (process_name == NULL) ? "" : process_name)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int32(ctx, oom_score)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int64(ctx, pgfault)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int64(ctx, pgmajfault)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int64(ctx, rss_in_bytes)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int64(ctx, cache_in_bytes)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int64(ctx, swap_in_bytes)) < 0) {
+ return ret;
+ }
+
+ return write_to_logger(ctx, LOG_ID_STATS);
+}
diff --git a/lmkd/statslog.h b/lmkd/statslog.h
new file mode 100644
index 0000000..edebb19
--- /dev/null
+++ b/lmkd/statslog.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018 Google, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _STATSLOG_H_
+#define _STATSLOG_H_
+
+#include <assert.h>
+#include <stats_event_list.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+
+#include <cutils/properties.h>
+
+__BEGIN_DECLS
+
+/*
+ * These are defined in
+ * http://cs/android/frameworks/base/cmds/statsd/src/atoms.proto
+ */
+#define LMK_KILL_OCCURRED 51
+#define LMK_STATE_CHANGED 54
+#define LMK_STATE_CHANGE_START 1
+#define LMK_STATE_CHANGE_STOP 2
+
+/*
+ * The single event tag id for all stats logs.
+ * Keep this in sync with system/core/logcat/event.logtags
+ */
+const static int kStatsEventTag = 1937006964;
+
+static inline void statslog_init(android_log_context* log_ctx, bool* enable_stats_log) {
+ assert(log_ctx != NULL);
+ assert(enable_stats_log != NULL);
+ *enable_stats_log = property_get_bool("ro.lmk.log_stats", false);
+
+ if (*enable_stats_log) {
+ *log_ctx = create_android_logger(kStatsEventTag);
+ }
+}
+
+static inline void statslog_destroy(android_log_context* log_ctx) {
+ assert(log_ctx != NULL);
+ if (*log_ctx) {
+ android_log_destroy(log_ctx);
+ }
+}
+
+struct memory_stat {
+ int64_t pgfault;
+ int64_t pgmajfault;
+ int64_t rss_in_bytes;
+ int64_t cache_in_bytes;
+ int64_t swap_in_bytes;
+};
+
+#define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat"
+
+/**
+ * Logs the change in LMKD state which is used as start/stop boundaries for logging
+ * LMK_KILL_OCCURRED event.
+ * Code: LMK_STATE_CHANGED = 54
+ */
+int
+stats_write_lmk_state_changed(android_log_context ctx, int32_t code, int32_t state);
+
+/**
+ * Logs the event when LMKD kills a process to reduce memory pressure.
+ * Code: LMK_KILL_OCCURRED = 51
+ */
+int
+stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid,
+ char const* process_name, int32_t oom_score, int64_t pgfault,
+ int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes,
+ int64_t swap_in_bytes);
+
+__END_DECLS
+
+#endif /* _STATSLOG_H_ */
diff --git a/lmkd/tests/lmkd_test.cpp b/lmkd/tests/lmkd_test.cpp
index 8c7a75f..1996bae 100644
--- a/lmkd/tests/lmkd_test.cpp
+++ b/lmkd/tests/lmkd_test.cpp
@@ -110,9 +110,14 @@
}
bool getExecPath(std::string &path) {
- // exec path as utf8z c_str().
- // std::string contains _all_ nul terminated argv[] strings.
- return android::base::ReadFileToString("/proc/self/cmdline", &path);
+ char buf[PATH_MAX + 1];
+ int ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
+ if (ret < 0) {
+ return false;
+ }
+ buf[ret] = '\0';
+ path = buf;
+ return true;
}
/* Child synchronization primitives */
@@ -310,8 +315,8 @@
if (getuid() != static_cast<unsigned>(AID_ROOT)) {
// if not root respawn itself as root and capture output
std::string command = StringPrintf(
- "%s=true su root %s --gtest_filter=lmkd.check_for_oom 2>&1",
- LMKDTEST_RESPAWN_FLAG, test_path.c_str());
+ "%s=true su root %s 2>&1", LMKDTEST_RESPAWN_FLAG,
+ test_path.c_str());
std::string test_output = readCommand(command);
GTEST_LOG_(INFO) << test_output;
} else {
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index a78319f..9b04363 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -1115,9 +1115,6 @@
// client wants to start from the beginning
it = mLogElements.begin();
} else {
- // 3 second limit to continue search for out-of-order entries.
- log_time min = start - pruneMargin;
-
// Cap to 300 iterations we look back for out-of-order entries.
size_t count = 300;
@@ -1133,7 +1130,7 @@
} else if (element->getRealTime() == start) {
last = ++it;
break;
- } else if (!--count || (element->getRealTime() < min)) {
+ } else if (!--count) {
break;
}
}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 763dc79..3a6a5e8 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -98,6 +98,9 @@
else
LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product-services $(TARGET_ROOT_OUT)/product-services
endif
+ifdef BOARD_USES_METADATA_PARTITION
+ LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/metadata
+endif
# For /odm partition.
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/odm
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 486d096..bf22951 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -84,7 +84,7 @@
restorecon_recursive /mnt
mount configfs none /config nodev noexec nosuid
- chmod 0775 /config/sdcardfs
+ chmod 0770 /config/sdcardfs
chown system package_info /config/sdcardfs
mkdir /mnt/secure 0700 root root
@@ -180,6 +180,12 @@
copy /dev/cpuset/cpus /dev/cpuset/system-background/cpus
copy /dev/cpuset/mems /dev/cpuset/system-background/mems
+ # restricted is for system tasks that are being throttled
+ # due to screen off.
+ mkdir /dev/cpuset/restricted
+ copy /dev/cpuset/cpus /dev/cpuset/restricted/cpus
+ copy /dev/cpuset/mems /dev/cpuset/restricted/mems
+
mkdir /dev/cpuset/top-app
copy /dev/cpuset/cpus /dev/cpuset/top-app/cpus
copy /dev/cpuset/mems /dev/cpuset/top-app/mems
@@ -190,11 +196,13 @@
chown system system /dev/cpuset/background
chown system system /dev/cpuset/system-background
chown system system /dev/cpuset/top-app
+ chown system system /dev/cpuset/restricted
chown system system /dev/cpuset/tasks
chown system system /dev/cpuset/foreground/tasks
chown system system /dev/cpuset/background/tasks
chown system system /dev/cpuset/system-background/tasks
chown system system /dev/cpuset/top-app/tasks
+ chown system system /dev/cpuset/restricted/tasks
# set system-background to 0775 so SurfaceFlinger can touch it
chmod 0775 /dev/cpuset/system-background
@@ -203,6 +211,7 @@
chmod 0664 /dev/cpuset/background/tasks
chmod 0664 /dev/cpuset/system-background/tasks
chmod 0664 /dev/cpuset/top-app/tasks
+ chmod 0664 /dev/cpuset/restricted/tasks
chmod 0664 /dev/cpuset/tasks
@@ -366,6 +375,10 @@
# create the lost+found directories, so as to enforce our permissions
mkdir /cache/lost+found 0770 root root
+ restorecon_recursive /metadata
+ mkdir /metadata/vold
+ chmod 0700 /metadata/vold
+
on late-fs
# Ensure that tracefs has the correct permissions.
# This does not work correctly if it is called in post-fs.
@@ -424,6 +437,7 @@
mkdir /data/misc/carrierid 0770 system radio
mkdir /data/misc/apns 0770 system radio
mkdir /data/misc/zoneinfo 0775 system system
+ mkdir /data/misc/network_watchlist 0774 system system
mkdir /data/misc/textclassifier 0771 system system
mkdir /data/misc/vpn 0770 system vpn
mkdir /data/misc/shared_relro 0771 shared_relro shared_relro
@@ -456,6 +470,8 @@
mkdir /data/misc/gcov 0770 root root
mkdir /data/vendor 0771 root root
+ mkdir /data/vendor_ce 0771 root root
+ mkdir /data/vendor_de 0771 root root
mkdir /data/vendor/hardware 0771 root root
# For security reasons, /data/local/tmp should always be empty.
@@ -688,6 +704,7 @@
on property:vold.decrypt=trigger_post_fs_data
trigger post-fs-data
+ trigger zygote-start
on property:vold.decrypt=trigger_restart_min_framework
# A/B update verifier that marks a successful boot.
@@ -695,6 +712,8 @@
class_start main
on property:vold.decrypt=trigger_restart_framework
+ stop surfaceflinger
+ start surfaceflinger
# A/B update verifier that marks a successful boot.
exec_start update_verifier
class_start main
@@ -732,17 +751,12 @@
## Daemon processes to be run by init.
##
-service ueventd /sbin/ueventd
+service ueventd /system/bin/ueventd
class core
critical
seclabel u:r:ueventd:s0
shutdown critical
-service healthd /system/bin/healthd
- class core
- critical
- group root system wakelock
-
service console /system/bin/sh
class core
console
diff --git a/rootdir/init.usb.configfs.rc b/rootdir/init.usb.configfs.rc
index de1aab3..3a33c94 100644
--- a/rootdir/init.usb.configfs.rc
+++ b/rootdir/init.usb.configfs.rc
@@ -2,7 +2,6 @@
write /config/usb_gadget/g1/UDC "none"
stop adbd
setprop sys.usb.ffs.ready 0
- setprop sys.usb.ffs.mtp.ready 0
write /config/usb_gadget/g1/bDeviceClass 0
write /config/usb_gadget/g1/bDeviceSubClass 0
write /config/usb_gadget/g1/bDeviceProtocol 0
@@ -24,7 +23,7 @@
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
setprop sys.usb.state ${sys.usb.config}
-on property:sys.usb.ffs.mtp.ready=1 && property:sys.usb.config=mtp && property:sys.usb.configfs=1
+on property:sys.usb.config=mtp && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp"
symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -33,15 +32,14 @@
on property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
start adbd
-on property:sys.usb.ffs.ready=1 && property:sys.usb.ffs.mtp.ready=1 && \
-property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp_adb"
symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
setprop sys.usb.state ${sys.usb.config}
-on property:sys.usb.ffs.mtp.ready=1 && property:sys.usb.config=ptp && property:sys.usb.configfs=1
+on property:sys.usb.config=ptp && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp"
symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -50,8 +48,7 @@
on property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
start adbd
-on property:sys.usb.ffs.ready=1 && property:sys.usb.ffs.mtp.ready=1 && \
-property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp_adb"
symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index 574bbfe..dc36596 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -43,6 +43,44 @@
#include <private/android_filesystem_config.h>
+#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
+#define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
+
+static bool supports_esdfs(void) {
+ std::string filesystems;
+ if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) {
+ PLOG(ERROR) << "Could not read /proc/filesystems";
+ return false;
+ }
+ for (const auto& fs : android::base::Split(filesystems, "\n")) {
+ if (fs.find("esdfs") != std::string::npos) return true;
+ }
+ return false;
+}
+
+static bool should_use_sdcardfs(void) {
+ char property[PROPERTY_VALUE_MAX];
+
+ // Allow user to have a strong opinion about state
+ property_get(PROP_SDCARDFS_USER, property, "");
+ if (!strcmp(property, "force_on")) {
+ LOG(WARNING) << "User explicitly enabled sdcardfs";
+ return true;
+ } else if (!strcmp(property, "force_off")) {
+ LOG(WARNING) << "User explicitly disabled sdcardfs";
+ return !supports_esdfs();
+ }
+
+ // Fall back to device opinion about state
+ if (property_get_bool(PROP_SDCARDFS_DEVICE, true)) {
+ LOG(WARNING) << "Device explicitly enabled sdcardfs";
+ return true;
+ } else {
+ LOG(WARNING) << "Device explicitly disabled sdcardfs";
+ return !supports_esdfs();
+ }
+}
+
// NOTE: This is a vestigial program that simply exists to mount the in-kernel
// sdcardfs filesystem. The older FUSE-based design that used to live here has
// been completely removed to avoid confusion.
@@ -61,7 +99,7 @@
static bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path,
uid_t fsuid, gid_t fsgid, bool multi_user, userid_t userid, gid_t gid,
- mode_t mask, bool derive_gid, bool default_normal) {
+ mode_t mask, bool derive_gid, bool default_normal, bool use_esdfs) {
// Try several attempts, each time with one less option, to gracefully
// handle older kernels that aren't updated yet.
for (int i = 0; i < 4; i++) {
@@ -72,7 +110,7 @@
auto opts = android::base::StringPrintf("fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
fsuid, fsgid, new_opts.c_str(), mask, userid, gid);
- if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs",
+ if (mount(source_path.c_str(), dest_path.c_str(), use_esdfs ? "esdfs" : "sdcardfs",
MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) {
PLOG(WARNING) << "Failed to mount sdcardfs with options " << opts;
} else {
@@ -104,9 +142,21 @@
return true;
}
+static bool sdcardfs_setup_secondary(const std::string& default_path, const std::string& source_path,
+ const std::string& dest_path, uid_t fsuid, gid_t fsgid,
+ bool multi_user, userid_t userid, gid_t gid, mode_t mask,
+ bool derive_gid, bool default_normal, bool use_esdfs) {
+ if (use_esdfs) {
+ return sdcardfs_setup(source_path, dest_path, fsuid, fsgid, multi_user, userid, gid, mask,
+ derive_gid, default_normal, use_esdfs);
+ } else {
+ return sdcardfs_setup_bind_remount(default_path, dest_path, gid, mask);
+ }
+}
+
static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid,
gid_t gid, userid_t userid, bool multi_user, bool full_write,
- bool derive_gid, bool default_normal) {
+ bool derive_gid, bool default_normal, bool use_esdfs) {
std::string dest_path_default = "/mnt/runtime/default/" + label;
std::string dest_path_read = "/mnt/runtime/read/" + label;
std::string dest_path_write = "/mnt/runtime/write/" + label;
@@ -116,10 +166,13 @@
// Multi-user storage is fully isolated per user, so "other"
// permissions are completely masked off.
if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
- AID_SDCARD_RW, 0006, derive_gid, default_normal) ||
- !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027) ||
- !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY,
- full_write ? 0007 : 0027)) {
+ AID_SDCARD_RW, 0006, derive_gid, default_normal, use_esdfs) ||
+ !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_read, uid, gid,
+ multi_user, userid, AID_EVERYBODY, 0027, derive_gid,
+ default_normal, use_esdfs) ||
+ !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_write, uid, gid,
+ multi_user, userid, AID_EVERYBODY, full_write ? 0007 : 0027,
+ derive_gid, default_normal, use_esdfs)) {
LOG(FATAL) << "failed to sdcardfs_setup";
}
} else {
@@ -127,11 +180,13 @@
// the Android directories are masked off to a single user
// deep inside attr_from_stat().
if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
- AID_SDCARD_RW, 0006, derive_gid, default_normal) ||
- !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY,
- full_write ? 0027 : 0022) ||
- !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY,
- full_write ? 0007 : 0022)) {
+ AID_SDCARD_RW, 0006, derive_gid, default_normal, use_esdfs) ||
+ !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_read, uid, gid,
+ multi_user, userid, AID_EVERYBODY, full_write ? 0027 : 0022,
+ derive_gid, default_normal, use_esdfs) ||
+ !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_write, uid, gid,
+ multi_user, userid, AID_EVERYBODY, full_write ? 0007 : 0022,
+ derive_gid, default_normal, use_esdfs)) {
LOG(FATAL) << "failed to sdcardfs_setup";
}
}
@@ -242,6 +297,6 @@
}
run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write, derive_gid,
- default_normal);
+ default_normal, !should_use_sdcardfs());
return 1;
}
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 0586381..3d7521c 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -27,6 +27,7 @@
phony {
name: "shell_and_utilities_recovery",
required: [
+ "grep.recovery",
"sh.recovery",
"toolbox.recovery",
"toybox.recovery",
diff --git a/storaged/Android.bp b/storaged/Android.bp
new file mode 100644
index 0000000..7466728
--- /dev/null
+++ b/storaged/Android.bp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+cc_defaults {
+ name: "storaged_defaults",
+
+ shared_libs: [
+ "android.hardware.health@1.0",
+ "android.hardware.health@2.0",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libprotobuf-cpp-lite",
+ "libsysutils",
+ "libutils",
+ "libz",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wno-unused-parameter"
+ ],
+}
+
+cc_library_static {
+ name: "libstoraged",
+
+ defaults: ["storaged_defaults"],
+
+ aidl: {
+ export_aidl_headers: true,
+ local_include_dirs: ["binder"],
+ include_dirs: ["frameworks/native/aidl/binder"],
+ },
+
+ srcs: [
+ "storaged.cpp",
+ "storaged_diskstats.cpp",
+ "storaged_info.cpp",
+ "storaged_service.cpp",
+ "storaged_utils.cpp",
+ "storaged_uid_monitor.cpp",
+ "uid_info.cpp",
+ "storaged.proto",
+ ":storaged_aidl",
+ "binder/android/os/storaged/IStoragedPrivate.aidl",
+ ],
+
+ static_libs: ["libhealthhalutils"],
+ header_libs: ["libbatteryservice_headers"],
+
+ logtags: ["EventLogTags.logtags"],
+
+ proto: {
+ type: "lite",
+ export_proto_headers: true,
+ },
+
+ export_include_dirs: ["include"],
+}
+
+cc_binary {
+ name: "storaged",
+
+ defaults: ["storaged_defaults"],
+
+ init_rc: ["storaged.rc"],
+
+ srcs: ["main.cpp"],
+
+ static_libs: [
+ "libhealthhalutils",
+ "libstoraged",
+ ],
+}
+
+/*
+ * Run with:
+ * adb shell /data/nativetest/storaged-unit-tests/storaged-unit-tests
+ */
+cc_test {
+ name: "storaged-unit-tests",
+
+ defaults: ["storaged_defaults"],
+
+ srcs: ["tests/storaged_test.cpp"],
+
+ static_libs: [
+ "libhealthhalutils",
+ "libstoraged",
+ ],
+}
+
+// AIDL interface between storaged and framework.jar
+filegroup {
+ name: "storaged_aidl",
+ srcs: [
+ "binder/android/os/IStoraged.aidl",
+ ],
+}
diff --git a/storaged/Android.mk b/storaged/Android.mk
deleted file mode 100644
index a1abe0f..0000000
--- a/storaged/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright 2016 The Android Open Source Project
-
-LOCAL_PATH := $(call my-dir)
-
-LIBSTORAGED_SHARED_LIBRARIES := \
- libbinder \
- libbase \
- libutils \
- libcutils \
- liblog \
- libsysutils \
- libbatteryservice \
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- storaged.cpp \
- storaged_info.cpp \
- storaged_service.cpp \
- storaged_utils.cpp \
- storaged_uid_monitor.cpp \
- EventLogTags.logtags
-
-LOCAL_MODULE := libstoraged
-LOCAL_CFLAGS := -Werror
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/googletest/googletest/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES)
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := storaged
-LOCAL_INIT_RC := storaged.rc
-LOCAL_SRC_FILES := main.cpp
-# libstoraged is an internal static library, only main.cpp and storaged_test.cpp should be using it
-LOCAL_STATIC_LIBRARIES := libstoraged
-LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES)
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
-LOCAL_C_INCLUDES := external/googletest/googletest/include
-
-include $(BUILD_EXECUTABLE)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/init/watchdogd.h b/storaged/binder/android/os/IStoraged.aidl
similarity index 69%
copy from init/watchdogd.h
copy to storaged/binder/android/os/IStoraged.aidl
index 73f77d5..0bcc70c 100644
--- a/init/watchdogd.h
+++ b/storaged/binder/android/os/IStoraged.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,15 +14,11 @@
* limitations under the License.
*/
-#ifndef _INIT_WATCHDOGD_H_
-#define _INIT_WATCHDOGD_H_
+package android.os;
-namespace android {
-namespace init {
-
-int watchdogd_main(int argc, char **argv);
-
-} // namespace init
-} // namespace android
-
-#endif
+/** {@hide} */
+interface IStoraged {
+ void onUserStarted(int userId);
+ void onUserStopped(int userId);
+ int getRecentPerf();
+}
\ No newline at end of file
diff --git a/init/watchdogd.h b/storaged/binder/android/os/storaged/IStoragedPrivate.aidl
similarity index 69%
copy from init/watchdogd.h
copy to storaged/binder/android/os/storaged/IStoragedPrivate.aidl
index 73f77d5..9c888e3 100644
--- a/init/watchdogd.h
+++ b/storaged/binder/android/os/storaged/IStoragedPrivate.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-#ifndef _INIT_WATCHDOGD_H_
-#define _INIT_WATCHDOGD_H_
+package android.os.storaged;
-namespace android {
-namespace init {
+import android.os.storaged.UidInfo;
-int watchdogd_main(int argc, char **argv);
-
-} // namespace init
-} // namespace android
-
-#endif
+/** {@hide} */
+interface IStoragedPrivate {
+ UidInfo[] dumpUids();
+ int[] dumpPerfHistory();
+}
\ No newline at end of file
diff --git a/init/watchdogd.h b/storaged/binder/android/os/storaged/UidInfo.aidl
similarity index 69%
copy from init/watchdogd.h
copy to storaged/binder/android/os/storaged/UidInfo.aidl
index 73f77d5..440f386 100644
--- a/init/watchdogd.h
+++ b/storaged/binder/android/os/storaged/UidInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-#ifndef _INIT_WATCHDOGD_H_
-#define _INIT_WATCHDOGD_H_
+package android.os.storaged;
-namespace android {
-namespace init {
-
-int watchdogd_main(int argc, char **argv);
-
-} // namespace init
-} // namespace android
-
-#endif
+parcelable UidInfo cpp_header "include/uid_info.h";
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index fa68406..6f92048 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -26,28 +26,18 @@
#include <unordered_map>
#include <vector>
-#include <batteryservice/IBatteryPropertiesListener.h>
-#include <batteryservice/IBatteryPropertiesRegistrar.h>
+#include <utils/Mutex.h>
-#include "storaged_info.h"
-#include "storaged_uid_monitor.h"
-
-using namespace android;
+#include <android/hardware/health/2.0/IHealth.h>
#define FRIEND_TEST(test_case_name, test_name) \
friend class test_case_name##_##test_name##_Test
-/* For debug */
-#ifdef DEBUG
-#define debuginfo(fmt, ...) \
- do {printf("%s():\t" fmt "\t[%s:%d]\n", __FUNCTION__, ##__VA_ARGS__, __FILE__, __LINE__);} \
- while(0)
-#else
-#define debuginfo(...)
-#endif
-
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define IS_ALIGNED(x, align) (!((x) & ((align) - 1)))
+#define ROUND_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
+
#define SECTOR_SIZE ( 512 )
#define SEC_TO_MSEC ( 1000 )
#define MSEC_TO_USEC ( 1000 )
@@ -55,184 +45,24 @@
#define SEC_TO_USEC ( 1000000 )
#define HOUR_TO_SEC ( 3600 )
#define DAY_TO_SEC ( 3600 * 24 )
+#define WEEK_TO_DAYS ( 7 )
+#define YEAR_TO_WEEKS ( 52 )
-// number of attributes diskstats has
-#define DISK_STATS_SIZE ( 11 )
-// maximum size limit of a stats file
-#define DISK_STATS_FILE_MAX_SIZE ( 256 )
-#define DISK_STATS_IO_IN_FLIGHT_IDX ( 8 )
-struct disk_stats {
- /* It will be extremely unlikely for any of the following entries to overflow.
- * For read_bytes(which will be greater than any of the following entries), it
- * will take 27 years to overflow uint64_t at the reading rate of 20GB/s, which
- * is the peak memory transfer rate for current memory.
- * The diskstats entries (first 11) need to be at top in this structure _after_
- * compiler's optimization.
- */
- uint64_t read_ios; // number of read I/Os processed
- uint64_t read_merges; // number of read I/Os merged with in-queue I/Os
- uint64_t read_sectors; // number of sectors read
- uint64_t read_ticks; // total wait time for read requests
- uint64_t write_ios; // number of write I/Os processed
- uint64_t write_merges; // number of write I/Os merged with in-queue I/Os
- uint64_t write_sectors; // number of sectors written
- uint64_t write_ticks; // total wait time for write requests
- uint64_t io_in_flight; // number of I/Os currently in flight
- uint64_t io_ticks; // total time this block device has been active
- uint64_t io_in_queue; // total wait time for all requests
+#include "storaged_diskstats.h"
+#include "storaged_info.h"
+#include "storaged_uid_monitor.h"
+#include "storaged.pb.h"
+#include "uid_info.h"
- uint64_t start_time; // monotonic time accounting starts
- uint64_t end_time; // monotonic time accounting ends
- uint32_t counter; // private counter for accumulate calculations
- double io_avg; // average io_in_flight for accumulate calculations
-};
-
-
-
-struct disk_perf {
- uint32_t read_perf; // read speed (kbytes/s)
- uint32_t read_ios; // read I/Os per second
- uint32_t write_perf; // write speed (kbytes/s)
- uint32_t write_ios; // write I/Os per second
- uint32_t queue; // I/Os in queue
-};
-
-#define CMD_MAX_LEN ( 64 )
-struct task_info {
- uint32_t pid; // task id
- uint64_t rchar; // characters read
- uint64_t wchar; // characters written
- uint64_t syscr; // read syscalls
- uint64_t syscw; // write syscalls
- uint64_t read_bytes; // bytes read (from storage layer)
- uint64_t write_bytes; // bytes written (to storage layer)
- uint64_t cancelled_write_bytes; // cancelled write byte by truncate
-
- uint64_t starttime; // start time of task
-
- char cmd[CMD_MAX_LEN]; // filename of the executable
-};
-
-class lock_t {
- sem_t* mSem;
-public:
- lock_t(sem_t* sem) {
- mSem = sem;
- sem_wait(mSem);
- }
- ~lock_t() {
- sem_post(mSem);
- }
-};
-
-class stream_stats {
-private:
- double mSum;
- double mSquareSum;
- uint32_t mCnt;
-public:
- stream_stats() : mSum(0), mSquareSum(0), mCnt(0) {};
- ~stream_stats() {};
- double get_mean() {
- return mSum / mCnt;
- }
- double get_std() {
- return sqrt(mSquareSum / mCnt - mSum * mSum / (mCnt * mCnt));
- }
- void add(uint32_t num) {
- mSum += (double)num;
- mSquareSum += (double)num * (double)num;
- mCnt++;
- }
- void evict(uint32_t num) {
- if (mSum < num || mSquareSum < (double)num * (double)num) return;
- mSum -= (double)num;
- mSquareSum -= (double)num * (double)num;
- mCnt--;
- }
-};
-
-#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
-#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
-#define EMMC_ECSD_PATH "/d/mmc0/mmc0:0001/ext_csd"
-#define UID_IO_STATS_PATH "/proc/uid_io/stats"
-
-class disk_stats_monitor {
-private:
- FRIEND_TEST(storaged_test, disk_stats_monitor);
- const char* DISK_STATS_PATH;
- struct disk_stats mPrevious;
- struct disk_stats mAccumulate;
- bool mStall;
- std::queue<struct disk_perf> mBuffer;
- struct {
- stream_stats read_perf; // read speed (bytes/s)
- stream_stats read_ios; // read I/Os per second
- stream_stats write_perf; // write speed (bytes/s)
- stream_stats write_ios; // write I/O per second
- stream_stats queue; // I/Os in queue
- } mStats;
- bool mValid;
- const uint32_t mWindow;
- const double mSigma;
- struct disk_perf mMean;
- struct disk_perf mStd;
-
- void update_mean();
- void update_std();
- void add(struct disk_perf* perf);
- void evict(struct disk_perf* perf);
- bool detect(struct disk_perf* perf);
-
- void update(struct disk_stats* stats);
-
-public:
- disk_stats_monitor(uint32_t window_size = 5, double sigma = 1.0) :
- mStall(false),
- mValid(false),
- mWindow(window_size),
- mSigma(sigma) {
- memset(&mPrevious, 0, sizeof(mPrevious));
- memset(&mMean, 0, sizeof(mMean));
- memset(&mStd, 0, sizeof(mStd));
-
- if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
- DISK_STATS_PATH = MMC_DISK_STATS_PATH;
- } else {
- DISK_STATS_PATH = SDA_DISK_STATS_PATH;
- }
- }
- void update(void);
-};
-
-class disk_stats_publisher {
-private:
- FRIEND_TEST(storaged_test, disk_stats_publisher);
- const char* DISK_STATS_PATH;
- struct disk_stats mAccumulate;
- struct disk_stats mPrevious;
-public:
- disk_stats_publisher(void) {
- memset(&mAccumulate, 0, sizeof(struct disk_stats));
- memset(&mPrevious, 0, sizeof(struct disk_stats));
-
- if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
- DISK_STATS_PATH = MMC_DISK_STATS_PATH;
- } else {
- DISK_STATS_PATH = SDA_DISK_STATS_PATH;
- }
- }
-
- ~disk_stats_publisher(void) {}
- void publish(void);
- void update(void);
-};
+using namespace std;
+using namespace android;
// Periodic chores intervals in seconds
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 )
#define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 )
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 )
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT (300)
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT ( 300 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_FLUSH_PROTO ( 3600 )
// UID IO threshold in bytes
#define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL )
@@ -241,25 +71,35 @@
int periodic_chores_interval_unit;
int periodic_chores_interval_disk_stats_publish;
int periodic_chores_interval_uid_io;
- bool proc_uid_io_available; // whether uid_io is accessible
- bool diskstats_available; // whether diskstats is accessible
+ int periodic_chores_interval_flush_proto;
int event_time_check_usec; // check how much cputime spent in event loop
};
-class storaged_t : public BnBatteryPropertiesListener,
- public IBinder::DeathRecipient {
-private:
+class storaged_t : public android::hardware::health::V2_0::IHealthInfoCallback,
+ public android::hardware::hidl_death_recipient {
+ private:
time_t mTimer;
storaged_config mConfig;
- disk_stats_publisher mDiskStats;
- disk_stats_monitor mDsm;
+ unique_ptr<disk_stats_monitor> mDsm;
uid_monitor mUidm;
time_t mStarttime;
- sp<IBatteryPropertiesRegistrar> battery_properties;
- std::unique_ptr<storage_info_t> storage_info;
-public:
+ sp<android::hardware::health::V2_0::IHealth> health;
+ unique_ptr<storage_info_t> storage_info;
+ static const uint32_t current_version;
+ unordered_map<userid_t, bool> proto_loaded;
+ void load_proto(userid_t user_id);
+ char* prepare_proto(userid_t user_id, StoragedProto* proto);
+ void flush_proto(userid_t user_id, StoragedProto* proto);
+ void flush_proto_data(userid_t user_id, const char* data, ssize_t size);
+ string proto_path(userid_t user_id) {
+ return string("/data/misc_ce/") + to_string(user_id) +
+ "/storaged/storaged.proto";
+ }
+ void init_health_service();
+
+ public:
storaged_t(void);
- ~storaged_t() {}
+ void init(void);
void event(void);
void event_checked(void);
void pause(void) {
@@ -270,24 +110,37 @@
return mStarttime;
}
- std::unordered_map<uint32_t, struct uid_info> get_uids(void) {
+ unordered_map<uint32_t, uid_info> get_uids(void) {
return mUidm.get_uid_io_stats();
}
- std::map<uint64_t, struct uid_records> get_uid_records(
+
+ vector<int> get_perf_history(void) {
+ return storage_info->get_perf_history();
+ }
+
+ uint32_t get_recent_perf(void) { return storage_info->get_recent_perf(); }
+
+ map<uint64_t, struct uid_records> get_uid_records(
double hours, uint64_t threshold, bool force_report) {
return mUidm.dump(hours, threshold, force_report);
}
+
void update_uid_io_interval(int interval) {
if (interval >= DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT) {
mConfig.periodic_chores_interval_uid_io = interval;
}
}
- void init_battery_service();
- virtual void batteryPropertiesChanged(struct BatteryProperties props);
- void binderDied(const wp<IBinder>& who);
+ void add_user_ce(userid_t user_id);
+ void remove_user_ce(userid_t user_id);
+
+ virtual ::android::hardware::Return<void> healthInfoChanged(
+ const ::android::hardware::health::V2_0::HealthInfo& info);
+ void serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who);
void report_storage_info();
+
+ void flush_protos(unordered_map<int, StoragedProto>* protos);
};
// Eventlog tag
diff --git a/storaged/include/storaged_diskstats.h b/storaged/include/storaged_diskstats.h
new file mode 100644
index 0000000..0b93ba6
--- /dev/null
+++ b/storaged/include/storaged_diskstats.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _STORAGED_DISKSTATS_H_
+#define _STORAGED_DISKSTATS_H_
+
+#include <stdint.h>
+
+#include <android/hardware/health/2.0/IHealth.h>
+
+// number of attributes diskstats has
+#define DISK_STATS_SIZE ( 11 )
+
+#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
+#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
+
+struct disk_stats {
+ /* It will be extremely unlikely for any of the following entries to overflow.
+ * For read_bytes(which will be greater than any of the following entries), it
+ * will take 27 years to overflow uint64_t at the reading rate of 20GB/s, which
+ * is the peak memory transfer rate for current memory.
+ * The diskstats entries (first 11) need to be at top in this structure _after_
+ * compiler's optimization.
+ */
+ uint64_t read_ios; // number of read I/Os processed
+ uint64_t read_merges; // number of read I/Os merged with in-queue I/Os
+ uint64_t read_sectors; // number of sectors read
+ uint64_t read_ticks; // total wait time for read requests
+ uint64_t write_ios; // number of write I/Os processed
+ uint64_t write_merges; // number of write I/Os merged with in-queue I/Os
+ uint64_t write_sectors; // number of sectors written
+ uint64_t write_ticks; // total wait time for write requests
+ uint64_t io_in_flight; // number of I/Os currently in flight
+ uint64_t io_ticks; // total time this block device has been active
+ uint64_t io_in_queue; // total wait time for all requests
+
+ uint64_t start_time; // monotonic time accounting starts
+ uint64_t end_time; // monotonic time accounting ends
+ uint32_t counter; // private counter for accumulate calculations
+ double io_avg; // average io_in_flight for accumulate calculations
+
+ bool is_zero() {
+ return read_ios == 0 && write_ios == 0 &&
+ io_in_flight == 0 && io_ticks == 0 && io_in_queue == 0;
+ }
+
+ friend disk_stats operator- (disk_stats curr, const disk_stats& prev) {
+ curr.read_ios -= prev.read_ios;
+ curr.read_merges -= prev.read_merges;
+ curr.read_sectors -= prev.read_sectors;
+ curr.read_ticks -= prev.read_ticks;
+ curr.write_ios -= prev.write_ios;
+ curr.write_merges -= prev.write_merges;
+ curr.write_sectors -= prev.write_sectors;
+ curr.write_ticks -= prev.write_ticks;
+ /* skips io_in_flight, use current value */
+ curr.io_ticks -= prev.io_ticks;
+ curr.io_in_queue -= prev.io_in_queue;
+ return curr;
+ }
+
+ friend bool operator== (const disk_stats& a, const disk_stats& b) {
+ return a.read_ios == b.read_ios &&
+ a.read_merges == b.read_merges &&
+ a.read_sectors == b.read_sectors &&
+ a.read_ticks == b.read_ticks &&
+ a.write_ios == b.write_ios &&
+ a.write_merges == b.write_merges &&
+ a.write_sectors == b.write_sectors &&
+ a.write_ticks == b.write_ticks &&
+ /* skips io_in_flight */
+ a.io_ticks == b.io_ticks &&
+ a.io_in_queue == b.io_in_queue;
+ }
+
+ disk_stats& operator+= (const disk_stats& stats) {
+ read_ios += stats.read_ios;
+ read_merges += stats.read_merges;
+ read_sectors += stats.read_sectors;
+ read_ticks += stats.read_ticks;
+ write_ios += stats.write_ios;
+ write_merges += stats.write_merges;
+ write_sectors += stats.write_sectors;
+ write_ticks += stats.write_ticks;
+ /* skips io_in_flight, use current value */
+ io_ticks += stats.io_ticks;
+ io_in_queue += stats.io_in_queue;
+ return *this;
+ }
+};
+
+struct disk_perf {
+ uint32_t read_perf; // read speed (kbytes/s)
+ uint32_t read_ios; // read I/Os per second
+ uint32_t write_perf; // write speed (kbytes/s)
+ uint32_t write_ios; // write I/Os per second
+ uint32_t queue; // I/Os in queue
+ bool is_zero() {
+ return read_perf == 0 && read_ios == 0 &&
+ write_perf == 0 && write_ios == 0 && queue == 0;
+ }
+};
+
+class stream_stats {
+private:
+ double mSum;
+ double mSquareSum;
+ uint32_t mCnt;
+public:
+ stream_stats() : mSum(0), mSquareSum(0), mCnt(0) {};
+ ~stream_stats() {};
+ double get_mean() {
+ return mSum / mCnt;
+ }
+ double get_std() {
+ return sqrt(mSquareSum / mCnt - mSum * mSum / (mCnt * mCnt));
+ }
+ void add(uint32_t num) {
+ mSum += (double)num;
+ mSquareSum += (double)num * (double)num;
+ mCnt++;
+ }
+ void evict(uint32_t num) {
+ if (mSum < num || mSquareSum < (double)num * (double)num) return;
+ mSum -= (double)num;
+ mSquareSum -= (double)num * (double)num;
+ mCnt--;
+ }
+};
+
+class disk_stats_monitor {
+private:
+ FRIEND_TEST(storaged_test, disk_stats_monitor);
+ const char* const DISK_STATS_PATH;
+ struct disk_stats mPrevious;
+ struct disk_stats mAccumulate; /* reset after stall */
+ struct disk_stats mAccumulate_pub; /* reset after publish */
+ bool mStall;
+ std::queue<struct disk_perf> mBuffer;
+ struct {
+ stream_stats read_perf; // read speed (bytes/s)
+ stream_stats read_ios; // read I/Os per second
+ stream_stats write_perf; // write speed (bytes/s)
+ stream_stats write_ios; // write I/O per second
+ stream_stats queue; // I/Os in queue
+ } mStats;
+ bool mValid;
+ const uint32_t mWindow;
+ const double mSigma;
+ struct disk_perf mMean;
+ struct disk_perf mStd;
+ android::sp<android::hardware::health::V2_0::IHealth> mHealth;
+
+ void update_mean();
+ void update_std();
+ void add(struct disk_perf* perf);
+ void evict(struct disk_perf* perf);
+ bool detect(struct disk_perf* perf);
+
+ void update(struct disk_stats* stats);
+
+public:
+ disk_stats_monitor(const android::sp<android::hardware::health::V2_0::IHealth>& healthService,
+ uint32_t window_size = 5, double sigma = 1.0)
+ : DISK_STATS_PATH(
+ healthService != nullptr
+ ? nullptr
+ : (access(MMC_DISK_STATS_PATH, R_OK) == 0
+ ? MMC_DISK_STATS_PATH
+ : (access(SDA_DISK_STATS_PATH, R_OK) == 0 ? SDA_DISK_STATS_PATH : nullptr))),
+ mPrevious(),
+ mAccumulate(),
+ mAccumulate_pub(),
+ mStall(false),
+ mValid(false),
+ mWindow(window_size),
+ mSigma(sigma),
+ mMean(),
+ mStd(),
+ mHealth(healthService) {}
+ bool enabled() { return mHealth != nullptr || DISK_STATS_PATH != nullptr; }
+ void update(void);
+ void publish(void);
+};
+
+#endif /* _STORAGED_DISKSTATS_H_ */
diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h
index 7d04c7a..9c3d0e7 100644
--- a/storaged/include/storaged_info.h
+++ b/storaged/include/storaged_info.h
@@ -19,14 +19,26 @@
#include <string.h>
+#include <chrono>
+
+#include <android/hardware/health/2.0/IHealth.h>
+#include <utils/Mutex.h>
+
+#include "storaged.h"
+#include "storaged.pb.h"
+
#define FRIEND_TEST(test_case_name, test_name) \
friend class test_case_name##_##test_name##_Test
using namespace std;
+using namespace android;
+using namespace chrono;
+using namespace storaged_proto;
class storage_info_t {
-protected:
+ protected:
FRIEND_TEST(storaged_test, storage_info_t);
+ FRIEND_TEST(storaged_test, storage_info_t_proto);
// emmc lifetime
uint16_t eol; // pre-eol (end of life) information
uint16_t lifetime_a; // device life time estimation (type A)
@@ -36,16 +48,38 @@
const string userdata_path = "/data";
uint64_t userdata_total_kb;
uint64_t userdata_free_kb;
+ // io perf history
+ time_point<system_clock> day_start_tp;
+ vector<uint32_t> recent_perf;
+ uint32_t nr_samples;
+ vector<uint32_t> daily_perf;
+ uint32_t nr_days;
+ vector<uint32_t> weekly_perf;
+ uint32_t nr_weeks;
+ Mutex si_mutex;
storage_info_t() : eol(0), lifetime_a(0), lifetime_b(0),
- userdata_total_kb(0), userdata_free_kb(0) {}
+ userdata_total_kb(0), userdata_free_kb(0), nr_samples(0),
+ daily_perf(WEEK_TO_DAYS, 0), nr_days(0),
+ weekly_perf(YEAR_TO_WEEKS, 0), nr_weeks(0) {
+ day_start_tp = system_clock::now();
+ day_start_tp -= chrono::seconds(duration_cast<chrono::seconds>(
+ day_start_tp.time_since_epoch()).count() % DAY_TO_SEC);
+ }
void publish();
storage_info_t* s_info;
-public:
- static storage_info_t* get_storage_info();
- virtual ~storage_info_t() {}
+
+ public:
+ static storage_info_t* get_storage_info(
+ const sp<android::hardware::health::V2_0::IHealth>& healthService);
+ virtual ~storage_info_t() {};
virtual void report() {};
- void refresh();
+ void load_perf_history_proto(const IOPerfHistory& perf_history);
+ void refresh(IOPerfHistory* perf_history);
+ void update_perf_history(uint32_t bw,
+ const time_point<system_clock>& tp);
+ vector<int> get_perf_history();
+ uint32_t get_recent_perf();
};
class emmc_info_t : public storage_info_t {
@@ -69,4 +103,18 @@
virtual void report();
};
+class health_storage_info_t : public storage_info_t {
+ private:
+ using IHealth = hardware::health::V2_0::IHealth;
+ using StorageInfo = hardware::health::V2_0::StorageInfo;
+
+ sp<IHealth> mHealth;
+ void set_values_from_hal_storage_info(const StorageInfo& halInfo);
+
+ public:
+ health_storage_info_t(const sp<IHealth>& service) : mHealth(service){};
+ virtual ~health_storage_info_t() {}
+ virtual void report();
+};
+
#endif /* _STORAGED_INFO_H_ */
diff --git a/storaged/include/storaged_service.h b/storaged/include/storaged_service.h
index a8ddf4c..7ec6864 100644
--- a/storaged/include/storaged_service.h
+++ b/storaged/include/storaged_service.h
@@ -19,42 +19,38 @@
#include <vector>
-#include <binder/IInterface.h>
-#include <binder/IBinder.h>
+#include <binder/BinderService.h>
-#include "storaged.h"
+#include "android/os/BnStoraged.h"
+#include "android/os/storaged/BnStoragedPrivate.h"
-using namespace android;
+using namespace std;
+using namespace android::os;
+using namespace android::os::storaged;
-// Interface
-class IStoraged : public IInterface {
+class StoragedService : public BinderService<StoragedService>, public BnStoraged {
+private:
+ void dumpUidRecordsDebug(int fd, const vector<struct uid_record>& entries);
+ void dumpUidRecords(int fd, const vector<struct uid_record>& entries);
public:
- enum {
- DUMPUIDS = IBinder::FIRST_CALL_TRANSACTION,
- };
- // Request the service to run the test function
- virtual std::vector<struct uid_info> dump_uids(const char* option) = 0;
+ static status_t start();
+ static char const* getServiceName() { return "storaged"; }
+ virtual status_t dump(int fd, const Vector<String16> &args) override;
- DECLARE_META_INTERFACE(Storaged);
+ binder::Status onUserStarted(int32_t userId);
+ binder::Status onUserStopped(int32_t userId);
+ binder::Status getRecentPerf(int32_t* _aidl_return);
};
-// Client
-class BpStoraged : public BpInterface<IStoraged> {
+class StoragedPrivateService : public BinderService<StoragedPrivateService>, public BnStoragedPrivate {
public:
- BpStoraged(const sp<IBinder>& impl) : BpInterface<IStoraged>(impl){};
- virtual std::vector<struct uid_info> dump_uids(const char* option);
+ static status_t start();
+ static char const* getServiceName() { return "storaged_pri"; }
+
+ binder::Status dumpUids(vector<UidInfo>* _aidl_return);
+ binder::Status dumpPerfHistory(vector<int32_t>* _aidl_return);
};
-// Server
-class BnStoraged : public BnInterface<IStoraged> {
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
-};
-
-class Storaged : public BnStoraged {
- virtual std::vector<struct uid_info> dump_uids(const char* option);
- virtual status_t dump(int fd, const Vector<String16>& args);
-};
-
-sp<IStoraged> get_storaged_service();
+sp<IStoragedPrivate> get_storaged_pri_service();
#endif /* _STORAGED_SERVICE_H_ */
\ No newline at end of file
diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h
index 901a872..3a718fa 100644
--- a/storaged/include/storaged_uid_monitor.h
+++ b/storaged/include/storaged_uid_monitor.h
@@ -23,88 +23,103 @@
#include <unordered_map>
#include <vector>
-enum uid_stat_t {
- FOREGROUND = 0,
- BACKGROUND = 1,
- UID_STATS = 2
+#include <cutils/multiuser.h>
+#include <utils/Mutex.h>
+
+#include "storaged.pb.h"
+#include "uid_info.h"
+
+#define FRIEND_TEST(test_case_name, test_name) \
+friend class test_case_name##_##test_name##_Test
+
+using namespace std;
+using namespace storaged_proto;
+using namespace android;
+using namespace android::os::storaged;
+
+class uid_info : public UidInfo {
+public:
+ bool parse_uid_io_stats(string&& s);
};
-enum charger_stat_t {
- CHARGER_OFF = 0,
- CHARGER_ON = 1,
- CHARGER_STATS = 2
-};
-
-enum io_type_t {
- READ = 0,
- WRITE = 1,
- IO_TYPES = 2
-};
-
-struct uid_io_stats {
- uint64_t rchar; // characters read
- uint64_t wchar; // characters written
- uint64_t read_bytes; // bytes read (from storage layer)
- uint64_t write_bytes; // bytes written (to storage layer)
- uint64_t fsync; // number of fsync syscalls
-};
-
-struct uid_info {
- uint32_t uid; // user id
- std::string name; // package name
- struct uid_io_stats io[UID_STATS]; // [0]:foreground [1]:background
+class io_usage {
+public:
+ io_usage() : bytes{{{0}}} {};
+ uint64_t bytes[IO_TYPES][UID_STATS][CHARGER_STATS];
+ bool is_zero() const;
+ io_usage& operator+= (const io_usage& stats) {
+ for (int i = 0; i < IO_TYPES; i++) {
+ for (int j = 0; j < UID_STATS; j++) {
+ for (int k = 0; k < CHARGER_STATS; k++) {
+ bytes[i][j][k] += stats.bytes[i][j][k];
+ }
+ }
+ }
+ return *this;
+ }
};
struct uid_io_usage {
- uint64_t bytes[IO_TYPES][UID_STATS][CHARGER_STATS];
+ userid_t user_id;
+ io_usage uid_ios;
+ // mapped from task comm to task io usage
+ map<string, io_usage> task_ios;
};
struct uid_record {
- std::string name;
+ string name;
struct uid_io_usage ios;
};
struct uid_records {
uint64_t start_ts;
- std::vector<struct uid_record> entries;
+ vector<struct uid_record> entries;
};
class uid_monitor {
private:
+ FRIEND_TEST(storaged_test, uid_monitor);
// last dump from /proc/uid_io/stats, uid -> uid_info
- std::unordered_map<uint32_t, struct uid_info> last_uid_io_stats;
+ unordered_map<uint32_t, uid_info> last_uid_io_stats;
// current io usage for next report, app name -> uid_io_usage
- std::unordered_map<std::string, struct uid_io_usage> curr_io_stats;
+ unordered_map<string, struct uid_io_usage> curr_io_stats;
// io usage records, end timestamp -> {start timestamp, vector of records}
- std::map<uint64_t, struct uid_records> records;
+ map<uint64_t, struct uid_records> io_history;
// charger ON/OFF
charger_stat_t charger_stat;
// protects curr_io_stats, last_uid_io_stats, records and charger_stat
- sem_t um_lock;
+ Mutex uidm_mutex;
// start time for IO records
uint64_t start_ts;
+ // true if UID_IO_STATS_PATH is accessible
+ const bool enable;
// reads from /proc/uid_io/stats
- std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats_locked();
+ unordered_map<uint32_t, uid_info> get_uid_io_stats_locked();
// flushes curr_io_stats to records
void add_records_locked(uint64_t curr_ts);
// updates curr_io_stats and set last_uid_io_stats
void update_curr_io_stats_locked();
+ // writes io_history to protobuf
+ void update_uid_io_proto(unordered_map<int, StoragedProto>* protos);
public:
uid_monitor();
- ~uid_monitor();
// called by storaged main thread
void init(charger_stat_t stat);
// called by storaged -u
- std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats();
+ unordered_map<uint32_t, uid_info> get_uid_io_stats();
// called by dumpsys
- std::map<uint64_t, struct uid_records> dump(
+ map<uint64_t, struct uid_records> dump(
double hours, uint64_t threshold, bool force_report);
// called by battery properties listener
void set_charger_state(charger_stat_t stat);
// called by storaged periodic_chore or dump with force_report
- void report();
+ bool enabled() { return enable; };
+ void report(unordered_map<int, StoragedProto>* protos);
+ // restores io_history from protobuf
+ void load_uid_io_proto(const UidIOUsage& proto);
+ void clear_user_history(userid_t user_id);
};
#endif /* _STORAGED_UID_MONITOR_H_ */
diff --git a/storaged/include/storaged_utils.h b/storaged/include/storaged_utils.h
index 2161c40..62cb12d 100644
--- a/storaged/include/storaged_utils.h
+++ b/storaged/include/storaged_utils.h
@@ -24,21 +24,20 @@
#include "storaged.h"
+using namespace android::os::storaged;
+
// Diskstats
bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats);
struct disk_perf get_disk_perf(struct disk_stats* stats);
-struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr);
+void get_inc_disk_stats(const struct disk_stats* prev, const struct disk_stats* curr, struct disk_stats* inc);
void add_disk_stats(struct disk_stats* src, struct disk_stats* dst);
-bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info);
// UID I/O
-void sort_running_uids_info(std::vector<struct uid_info> &uids);
+map<string, io_usage> merge_io_usage(const vector<uid_record>& entries);
+void sort_running_uids_info(std::vector<UidInfo> &uids);
// Logging
-void log_console_running_uids_info(std::vector<struct uid_info> uids);
+void log_console_running_uids_info(const std::vector<UidInfo>& uids, bool flag_dump_task);
+void log_console_perf_history(const vector<int>& perf_history);
-void log_debug_disk_perf(struct disk_perf* perf, const char* type);
-
-void log_event_disk_stats(struct disk_stats* stats, const char* type);
-void log_event_emmc_info(struct emmc_info* info_);
#endif /* _STORAGED_UTILS_H_ */
diff --git a/storaged/include/uid_info.h b/storaged/include/uid_info.h
new file mode 100644
index 0000000..c5533ac
--- /dev/null
+++ b/storaged/include/uid_info.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _UID_INFO_H_
+#define _UID_INFO_H_
+
+#include <string>
+#include <unordered_map>
+
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace os {
+namespace storaged {
+
+enum uid_stat_t {
+ FOREGROUND = 0,
+ BACKGROUND = 1,
+ UID_STATS = 2
+};
+
+enum charger_stat_t {
+ CHARGER_OFF = 0,
+ CHARGER_ON = 1,
+ CHARGER_STATS = 2
+};
+
+enum io_type_t {
+ READ = 0,
+ WRITE = 1,
+ IO_TYPES = 2
+};
+
+struct io_stats {
+ uint64_t rchar; // characters read
+ uint64_t wchar; // characters written
+ uint64_t read_bytes; // bytes read (from storage layer)
+ uint64_t write_bytes; // bytes written (to storage layer)
+ uint64_t fsync; // number of fsync syscalls
+};
+
+class task_info {
+public:
+ std::string comm;
+ pid_t pid;
+ io_stats io[UID_STATS];
+ bool parse_task_io_stats(std::string&& s);
+};
+
+class UidInfo : public Parcelable {
+public:
+ uint32_t uid; // user id
+ std::string name; // package name
+ io_stats io[UID_STATS]; // [0]:foreground [1]:background
+ std::unordered_map<uint32_t, task_info> tasks; // mapped from pid
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace storaged
+} // namespace os
+} // namespace android
+
+#endif /* _UID_INFO_H_ */
\ No newline at end of file
diff --git a/storaged/main.cpp b/storaged/main.cpp
index 72ec58f..3817fb5 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -39,72 +39,81 @@
#include <storaged_service.h>
#include <storaged_utils.h>
-sp<storaged_t> storaged;
+using namespace std;
+using namespace android;
+
+sp<storaged_t> storaged_sp;
// Function of storaged's main thread
void* storaged_main(void* /* unused */) {
- storaged = new storaged_t();
+ storaged_sp = new storaged_t();
- storaged->init_battery_service();
- storaged->report_storage_info();
+ storaged_sp->init();
+ storaged_sp->report_storage_info();
LOG_TO(SYSTEM, INFO) << "storaged: Start";
for (;;) {
- storaged->event_checked();
- storaged->pause();
+ storaged_sp->event_checked();
+ storaged_sp->pause();
}
return NULL;
}
-static void help_message(void) {
+void help_message(void) {
printf("usage: storaged [OPTION]\n");
printf(" -u --uid Dump uid I/O usage to stdout\n");
+ printf(" -t --task Dump task I/O usage to stdout\n");
+ printf(" -p --perf Dump I/O perf history to stdout\n");
printf(" -s --start Start storaged (default)\n");
fflush(stdout);
}
int main(int argc, char** argv) {
- int flag_main_service = 0;
- int flag_dump_uid = 0;
+ bool flag_main_service = false;
+ bool flag_dump_uid = false;
+ bool flag_dump_task = false;
+ bool flag_dump_perf = false;
int opt;
for (;;) {
int opt_idx = 0;
static struct option long_options[] = {
- {"start", no_argument, 0, 's'},
- {"kill", no_argument, 0, 'k'},
- {"uid", no_argument, 0, 'u'},
- {"help", no_argument, 0, 'h'}
+ {"perf", no_argument, nullptr, 'p'},
+ {"start", no_argument, nullptr, 's'},
+ {"task", no_argument, nullptr, 't'},
+ {"uid", no_argument, nullptr, 'u'},
+ {nullptr, 0, nullptr, 0}
};
- opt = getopt_long(argc, argv, ":skdhu0", long_options, &opt_idx);
+ opt = getopt_long(argc, argv, ":pstu", long_options, &opt_idx);
if (opt == -1) {
break;
}
switch (opt) {
+ case 'p':
+ flag_dump_perf = true;
+ break;
case 's':
- flag_main_service = 1;
+ flag_main_service = true;
+ break;
+ case 't':
+ flag_dump_task = true;
break;
case 'u':
- flag_dump_uid = 1;
+ flag_dump_uid = true;
break;
- case 'h':
+ default:
help_message();
return 0;
- case '?':
- default:
- fprintf(stderr, "no supported option\n");
- help_message();
- return -1;
}
}
if (argc == 1) {
- flag_main_service = 1;
+ flag_main_service = true;
}
- if (flag_main_service && flag_dump_uid) {
+ if (flag_main_service && (flag_dump_uid || flag_dump_task)) {
fprintf(stderr, "Invalid arguments. Option \"start\" and \"dump\" cannot be used together.\n");
help_message();
return -1;
@@ -119,7 +128,12 @@
return -1;
}
- defaultServiceManager()->addService(String16("storaged"), new Storaged());
+ if (StoragedService::start() != android::OK ||
+ StoragedPrivateService::start() != android::OK) {
+ PLOG_TO(SYSTEM, ERROR) << "Failed to start storaged service";
+ return -1;
+ }
+
android::ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
pthread_join(storaged_main_thread, NULL);
@@ -127,23 +141,33 @@
return 0;
}
- if (flag_dump_uid) {
- sp<IStoraged> storaged_service = get_storaged_service();
- if (storaged_service == NULL) {
- fprintf(stderr, "Cannot find storaged service.\nMaybe run storaged --start first?\n");
- return -1;
- }
- std::vector<struct uid_info> res = storaged_service->dump_uids(NULL);
+ sp<IStoragedPrivate> storaged_service = get_storaged_pri_service();
+ if (storaged_service == NULL) {
+ fprintf(stderr, "Cannot find storaged service.\nMaybe run storaged --start first?\n");
+ return -1;
+ }
- if (res.size() == 0) {
- fprintf(stderr, "UID I/O is not readable in this version of kernel.\n");
+ if (flag_dump_uid || flag_dump_task) {
+ vector<UidInfo> uid_io;
+ binder::Status status = storaged_service->dumpUids(&uid_io);
+ if (!status.isOk() || uid_io.size() == 0) {
+ fprintf(stderr, "UID I/O info is not available.\n");
return 0;
}
- sort_running_uids_info(res);
- log_console_running_uids_info(res);
+ sort_running_uids_info(uid_io);
+ log_console_running_uids_info(uid_io, flag_dump_task);
+ }
- return 0;
+ if (flag_dump_perf) {
+ vector<int> perf_history;
+ binder::Status status = storaged_service->dumpPerfHistory(&perf_history);
+ if (!status.isOk() || perf_history.size() == 0) {
+ fprintf(stderr, "I/O perf history is not available.\n");
+ return 0;
+ }
+
+ log_console_perf_history(perf_history);
}
return 0;
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 06afea6..f346c38 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -16,184 +16,118 @@
#define LOG_TAG "storaged"
+#include <dirent.h>
#include <stdlib.h>
+#include <stdio.h>
#include <time.h>
#include <unistd.h>
+#include <zlib.h>
+#include <chrono>
+#include <fstream>
+#include <sstream>
+#include <string>
+
+#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
#include <batteryservice/BatteryServiceConstants.h>
-#include <batteryservice/IBatteryPropertiesRegistrar.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
#include <cutils/properties.h>
+#include <healthhalutils/HealthHalUtils.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
#include <log/log.h>
#include <storaged.h>
#include <storaged_utils.h>
-/* disk_stats_publisher */
-void disk_stats_publisher::publish(void) {
- // Logging
- struct disk_perf perf = get_disk_perf(&mAccumulate);
- log_debug_disk_perf(&perf, "regular");
- log_event_disk_stats(&mAccumulate, "regular");
- // Reset global structures
- memset(&mAccumulate, 0, sizeof(struct disk_stats));
-}
+using namespace android::base;
+using namespace chrono;
+using namespace google::protobuf::io;
+using namespace storaged_proto;
-void disk_stats_publisher::update(void) {
- struct disk_stats curr;
- if (parse_disk_stats(DISK_STATS_PATH, &curr)) {
- struct disk_stats inc = get_inc_disk_stats(&mPrevious, &curr);
- add_disk_stats(&inc, &mAccumulate);
-#ifdef DEBUG
-// log_kernel_disk_stats(&mPrevious, "prev stats");
-// log_kernel_disk_stats(&curr, "curr stats");
-// log_kernel_disk_stats(&inc, "inc stats");
-// log_kernel_disk_stats(&mAccumulate, "accumulated stats");
-#endif
- mPrevious = curr;
- }
-}
+namespace {
-/* disk_stats_monitor */
-void disk_stats_monitor::update_mean() {
- CHECK(mValid);
- mMean.read_perf = (uint32_t)mStats.read_perf.get_mean();
- mMean.read_ios = (uint32_t)mStats.read_ios.get_mean();
- mMean.write_perf = (uint32_t)mStats.write_perf.get_mean();
- mMean.write_ios = (uint32_t)mStats.write_ios.get_mean();
- mMean.queue = (uint32_t)mStats.queue.get_mean();
-}
+/*
+ * The system user is the initial user that is implicitly created on first boot
+ * and hosts most of the system services. Keep this in sync with
+ * frameworks/base/core/java/android/os/UserManager.java
+ */
+constexpr int USER_SYSTEM = 0;
-void disk_stats_monitor::update_std() {
- CHECK(mValid);
- mStd.read_perf = (uint32_t)mStats.read_perf.get_std();
- mStd.read_ios = (uint32_t)mStats.read_ios.get_std();
- mStd.write_perf = (uint32_t)mStats.write_perf.get_std();
- mStd.write_ios = (uint32_t)mStats.write_ios.get_std();
- mStd.queue = (uint32_t)mStats.queue.get_std();
-}
+constexpr ssize_t benchmark_unit_size = 16 * 1024; // 16KB
-void disk_stats_monitor::add(struct disk_perf* perf) {
- mStats.read_perf.add(perf->read_perf);
- mStats.read_ios.add(perf->read_ios);
- mStats.write_perf.add(perf->write_perf);
- mStats.write_ios.add(perf->write_ios);
- mStats.queue.add(perf->queue);
-}
+constexpr ssize_t min_benchmark_size = 128 * 1024; // 128KB
-void disk_stats_monitor::evict(struct disk_perf* perf) {
- mStats.read_perf.evict(perf->read_perf);
- mStats.read_ios.evict(perf->read_ios);
- mStats.write_perf.evict(perf->write_perf);
- mStats.write_ios.evict(perf->write_ios);
- mStats.queue.evict(perf->queue);
-}
+} // namespace
-bool disk_stats_monitor::detect(struct disk_perf* perf) {
- return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) &&
- ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) &&
- ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf);
-}
+const uint32_t storaged_t::current_version = 4;
-void disk_stats_monitor::update(struct disk_stats* stats) {
- struct disk_stats inc = get_inc_disk_stats(&mPrevious, stats);
- struct disk_perf perf = get_disk_perf(&inc);
- // Update internal data structures
- if (LIKELY(mValid)) {
- CHECK_EQ(mBuffer.size(), mWindow);
+using android::hardware::interfacesEqual;
+using android::hardware::Return;
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V1_0::toString;
+using android::hardware::health::V2_0::get_health_service;
+using android::hardware::health::V2_0::HealthInfo;
+using android::hardware::health::V2_0::IHealth;
+using android::hardware::health::V2_0::Result;
+using android::hidl::manager::V1_0::IServiceManager;
- if (UNLIKELY(detect(&perf))) {
- mStall = true;
- add_disk_stats(&inc, &mAccumulate);
- log_debug_disk_perf(&mMean, "stalled_mean");
- log_debug_disk_perf(&mStd, "stalled_std");
- } else {
- if (mStall) {
- struct disk_perf acc_perf = get_disk_perf(&mAccumulate);
- log_debug_disk_perf(&acc_perf, "stalled");
- log_event_disk_stats(&mAccumulate, "stalled");
- mStall = false;
- memset(&mAccumulate, 0, sizeof(mAccumulate));
- }
- }
- evict(&mBuffer.front());
- mBuffer.pop();
- add(&perf);
- mBuffer.push(perf);
-
- update_mean();
- update_std();
-
- } else { /* mValid == false */
- CHECK_LT(mBuffer.size(), mWindow);
- add(&perf);
- mBuffer.push(perf);
- if (mBuffer.size() == mWindow) {
- mValid = true;
- update_mean();
- update_std();
- }
- }
-
- mPrevious = *stats;
-}
-
-void disk_stats_monitor::update(void) {
- struct disk_stats curr;
- if (LIKELY(parse_disk_stats(DISK_STATS_PATH, &curr))) {
- update(&curr);
- }
-}
-
-static sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm == NULL) return NULL;
-
- sp<IBinder> binder = sm->getService(String16("batteryproperties"));
- if (binder == NULL) return NULL;
-
- sp<IBatteryPropertiesRegistrar> battery_properties =
- interface_cast<IBatteryPropertiesRegistrar>(binder);
-
- return battery_properties;
-}
-
-static inline charger_stat_t is_charger_on(int64_t prop) {
- return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ?
+inline charger_stat_t is_charger_on(BatteryStatus prop) {
+ return (prop == BatteryStatus::CHARGING || prop == BatteryStatus::FULL) ?
CHARGER_ON : CHARGER_OFF;
}
-void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) {
- mUidm.set_charger_state(is_charger_on(props.batteryStatus));
+Return<void> storaged_t::healthInfoChanged(const HealthInfo& props) {
+ mUidm.set_charger_state(is_charger_on(props.legacy.batteryStatus));
+ return android::hardware::Void();
}
-void storaged_t::init_battery_service() {
- if (!mConfig.proc_uid_io_available)
+void storaged_t::init() {
+ init_health_service();
+ mDsm = std::make_unique<disk_stats_monitor>(health);
+ storage_info.reset(storage_info_t::get_storage_info(health));
+}
+
+void storaged_t::init_health_service() {
+ if (!mUidm.enabled())
return;
- battery_properties = get_battery_properties_service();
- if (battery_properties == NULL) {
- LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service";
+ health = get_health_service();
+ if (health == NULL) {
+ LOG_TO(SYSTEM, WARNING) << "health: failed to find IHealth service";
return;
}
- struct BatteryProperty val;
- battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val);
- mUidm.init(is_charger_on(val.valueInt64));
+ BatteryStatus status = BatteryStatus::UNKNOWN;
+ auto ret = health->getChargeStatus([&](Result r, BatteryStatus v) {
+ if (r != Result::SUCCESS) {
+ LOG_TO(SYSTEM, WARNING)
+ << "health: cannot get battery status " << toString(r);
+ return;
+ }
+ if (v == BatteryStatus::UNKNOWN) {
+ LOG_TO(SYSTEM, WARNING) << "health: invalid battery status";
+ }
+ status = v;
+ });
+ if (!ret.isOk()) {
+ LOG_TO(SYSTEM, WARNING) << "health: get charge status transaction error "
+ << ret.description();
+ }
+ mUidm.init(is_charger_on(status));
// register listener after init uid_monitor
- battery_properties->registerListener(this);
- IInterface::asBinder(battery_properties)->linkToDeath(this);
+ health->registerCallback(this);
+ health->linkToDeath(this, 0 /* cookie */);
}
-void storaged_t::binderDied(const wp<IBinder>& who) {
- if (battery_properties != NULL &&
- IInterface::asBinder(battery_properties) == who) {
- LOG_TO(SYSTEM, ERROR) << "batteryproperties service died, exiting";
- IPCThreadState::self()->stopProcess();
+void storaged_t::serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who) {
+ if (health != NULL && interfacesEqual(health, who.promote())) {
+ LOG_TO(SYSTEM, ERROR) << "health service died, exiting";
+ android::hardware::IPCThreadState::self()->stopProcess();
exit(1);
} else {
LOG_TO(SYSTEM, ERROR) << "unknown service died";
@@ -206,44 +140,195 @@
/* storaged_t */
storaged_t::storaged_t(void) {
- if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) {
- mConfig.diskstats_available = false;
- } else {
- mConfig.diskstats_available = true;
- }
-
- mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0);
-
mConfig.periodic_chores_interval_unit =
- property_get_int32("ro.storaged.event.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT);
+ property_get_int32("ro.storaged.event.interval",
+ DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT);
mConfig.event_time_check_usec =
property_get_int32("ro.storaged.event.perf_check", 0);
mConfig.periodic_chores_interval_disk_stats_publish =
- property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH);
+ property_get_int32("ro.storaged.disk_stats_pub",
+ DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH);
mConfig.periodic_chores_interval_uid_io =
- property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
+ property_get_int32("ro.storaged.uid_io.interval",
+ DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
- storage_info.reset(storage_info_t::get_storage_info());
+ mConfig.periodic_chores_interval_flush_proto =
+ property_get_int32("ro.storaged.flush_proto.interval",
+ DEFAULT_PERIODIC_CHORES_INTERVAL_FLUSH_PROTO);
mStarttime = time(NULL);
+ mTimer = 0;
}
-void storaged_t::event(void) {
- if (mConfig.diskstats_available) {
- mDiskStats.update();
- mDsm.update();
- storage_info->refresh();
- if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) {
- mDiskStats.publish();
+void storaged_t::add_user_ce(userid_t user_id) {
+ load_proto(user_id);
+ proto_loaded[user_id] = true;
+}
+
+void storaged_t::remove_user_ce(userid_t user_id) {
+ proto_loaded[user_id] = false;
+ mUidm.clear_user_history(user_id);
+ RemoveFileIfExists(proto_path(user_id), nullptr);
+}
+
+void storaged_t::load_proto(userid_t user_id) {
+ string proto_file = proto_path(user_id);
+ ifstream in(proto_file, ofstream::in | ofstream::binary);
+
+ if (!in.good()) return;
+
+ stringstream ss;
+ ss << in.rdbuf();
+ StoragedProto proto;
+ proto.ParseFromString(ss.str());
+
+ const UidIOUsage& uid_io_usage = proto.uid_io_usage();
+ uint32_t computed_crc = crc32(current_version,
+ reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()),
+ uid_io_usage.ByteSize());
+ if (proto.crc() != computed_crc) {
+ LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << proto_file;
+ return;
+ }
+
+ mUidm.load_uid_io_proto(proto.uid_io_usage());
+
+ if (user_id == USER_SYSTEM) {
+ storage_info->load_perf_history_proto(proto.perf_history());
+ }
+}
+
+char* storaged_t:: prepare_proto(userid_t user_id, StoragedProto* proto) {
+ proto->set_version(current_version);
+
+ const UidIOUsage& uid_io_usage = proto->uid_io_usage();
+ proto->set_crc(crc32(current_version,
+ reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()),
+ uid_io_usage.ByteSize()));
+
+ uint32_t pagesize = sysconf(_SC_PAGESIZE);
+ if (user_id == USER_SYSTEM) {
+ proto->set_padding("", 1);
+ vector<char> padding;
+ ssize_t size = ROUND_UP(MAX(min_benchmark_size, proto->ByteSize()),
+ pagesize);
+ padding = vector<char>(size - proto->ByteSize(), 0xFD);
+ proto->set_padding(padding.data(), padding.size());
+ while (!IS_ALIGNED(proto->ByteSize(), pagesize)) {
+ padding.push_back(0xFD);
+ proto->set_padding(padding.data(), padding.size());
}
}
- if (mConfig.proc_uid_io_available && mTimer &&
- (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) {
- mUidm.report();
+ char* data = nullptr;
+ if (posix_memalign(reinterpret_cast<void**>(&data),
+ pagesize, proto->ByteSize())) {
+ PLOG_TO(SYSTEM, ERROR) << "Faied to alloc aligned buffer (size: "
+ << proto->ByteSize() << ")";
+ return data;
+ }
+
+ proto->SerializeToArray(data, proto->ByteSize());
+ return data;
+}
+
+void storaged_t::flush_proto_data(userid_t user_id,
+ const char* data, ssize_t size) {
+ string proto_file = proto_path(user_id);
+ string tmp_file = proto_file + "_tmp";
+ unique_fd fd(TEMP_FAILURE_RETRY(open(tmp_file.c_str(),
+ O_SYNC | O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC |
+ (user_id == USER_SYSTEM ? O_DIRECT : 0),
+ S_IRUSR | S_IWUSR)));
+ if (fd == -1) {
+ PLOG_TO(SYSTEM, ERROR) << "Faied to open tmp file: " << tmp_file;
+ return;
+ }
+
+ if (user_id == USER_SYSTEM) {
+ time_point<steady_clock> start, end;
+ uint32_t benchmark_size = 0;
+ uint64_t benchmark_time_ns = 0;
+ ssize_t ret;
+ bool first_write = true;
+
+ while (size > 0) {
+ start = steady_clock::now();
+ ret = write(fd, data, MIN(benchmark_unit_size, size));
+ if (ret <= 0) {
+ PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file;
+ return;
+ }
+ end = steady_clock::now();
+ /*
+ * compute bandwidth after the first write and if write returns
+ * exactly unit size.
+ */
+ if (!first_write && ret == benchmark_unit_size) {
+ benchmark_size += benchmark_unit_size;
+ benchmark_time_ns += duration_cast<nanoseconds>(end - start).count();
+ }
+ size -= ret;
+ data += ret;
+ first_write = false;
+ }
+
+ if (benchmark_size) {
+ int perf = benchmark_size * 1000000LLU / benchmark_time_ns;
+ storage_info->update_perf_history(perf, system_clock::now());
+ }
+ } else {
+ if (!WriteFully(fd, data, size)) {
+ PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file;
+ return;
+ }
+ }
+
+ fd.reset(-1);
+ rename(tmp_file.c_str(), proto_file.c_str());
+}
+
+void storaged_t::flush_proto(userid_t user_id, StoragedProto* proto) {
+ unique_ptr<char> proto_data(prepare_proto(user_id, proto));
+ if (proto_data == nullptr) return;
+
+ flush_proto_data(user_id, proto_data.get(), proto->ByteSize());
+}
+
+void storaged_t::flush_protos(unordered_map<int, StoragedProto>* protos) {
+ for (auto& it : *protos) {
+ /*
+ * Don't flush proto if we haven't attempted to load it from file.
+ */
+ if (proto_loaded[it.first]) {
+ flush_proto(it.first, &it.second);
+ }
+ }
+}
+
+void storaged_t::event(void) {
+ unordered_map<int, StoragedProto> protos;
+
+ if (mDsm->enabled()) {
+ mDsm->update();
+ if (!(mTimer % mConfig.periodic_chores_interval_disk_stats_publish)) {
+ mDsm->publish();
+ }
+ }
+
+ if (!(mTimer % mConfig.periodic_chores_interval_uid_io)) {
+ mUidm.report(&protos);
+ }
+
+ if (storage_info) {
+ storage_info->refresh(protos[USER_SYSTEM].mutable_perf_history());
+ }
+
+ if (!(mTimer % mConfig.periodic_chores_interval_flush_proto)) {
+ flush_protos(&protos);
}
mTimer += mConfig.periodic_chores_interval_unit;
diff --git a/storaged/storaged.proto b/storaged/storaged.proto
new file mode 100644
index 0000000..2000c0b
--- /dev/null
+++ b/storaged/storaged.proto
@@ -0,0 +1,60 @@
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+package storaged_proto;
+option java_package = "com.android.storaged.proto";
+option java_outer_classname = "Storaged";
+
+message IOUsage {
+ optional uint64 rd_fg_chg_on = 1;
+ optional uint64 rd_fg_chg_off = 2;
+ optional uint64 rd_bg_chg_on = 3;
+ optional uint64 rd_bg_chg_off = 4;
+ optional uint64 wr_fg_chg_on = 5;
+ optional uint64 wr_fg_chg_off = 6;
+ optional uint64 wr_bg_chg_on = 7;
+ optional uint64 wr_bg_chg_off = 8;
+}
+
+message TaskIOUsage {
+ optional string task_name = 1;
+ optional IOUsage ios = 2;
+}
+
+message UidRecord {
+ optional string uid_name = 1;
+ optional uint32 user_id = 2;
+ optional IOUsage uid_io = 3;
+ repeated TaskIOUsage task_io = 4;
+}
+
+message UidIORecords {
+ optional uint64 start_ts = 1;
+ repeated UidRecord entries = 2;
+}
+
+message UidIOItem {
+ optional uint64 end_ts = 1;
+ optional UidIORecords records = 2;
+}
+
+message UidIOUsage {
+ repeated UidIOItem uid_io_items = 2;
+}
+
+message IOPerfHistory {
+ optional uint64 day_start_sec = 1;
+ repeated uint32 recent_perf = 2;
+ optional uint32 nr_samples = 3;
+ repeated uint32 daily_perf = 4;
+ optional uint32 nr_days = 5;
+ repeated uint32 weekly_perf = 6;
+ optional uint32 nr_weeks = 7;
+}
+
+message StoragedProto {
+ optional uint32 crc = 1;
+ optional uint32 version = 2;
+ optional UidIOUsage uid_io_usage = 3;
+ optional IOPerfHistory perf_history = 4;
+ optional bytes padding = 5;
+}
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
index ed2cf14..0614fad 100644
--- a/storaged/storaged.rc
+++ b/storaged/storaged.rc
@@ -5,4 +5,4 @@
file /d/mmc0/mmc0:0001/ext_csd r
writepid /dev/cpuset/system-background/tasks
user root
- group package_info
\ No newline at end of file
+ group package_info
diff --git a/storaged/storaged_diskstats.cpp b/storaged/storaged_diskstats.cpp
new file mode 100644
index 0000000..1050033
--- /dev/null
+++ b/storaged/storaged_diskstats.cpp
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "storaged"
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <sstream>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <log/log_event_list.h>
+
+#include "storaged.h"
+#include "storaged_diskstats.h"
+
+namespace {
+
+using android::sp;
+using android::hardware::health::V2_0::DiskStats;
+using android::hardware::health::V2_0::IHealth;
+using android::hardware::health::V2_0::Result;
+using android::hardware::health::V2_0::toString;
+
+#ifdef DEBUG
+void log_debug_disk_perf(struct disk_perf* perf, const char* type) {
+ // skip if the input structure are all zeros
+ if (perf == NULL || perf->is_zero()) return;
+
+ LOG_TO(SYSTEM, INFO) << "disk_perf " << type
+ << " rd: " << perf->read_perf << " kbps, " << perf->read_ios << " iops"
+ << " wr: " << perf->write_perf << " kbps, " << perf->write_ios << " iops"
+ << " q: " << perf->queue;
+}
+#else
+void log_debug_disk_perf(struct disk_perf* perf, const char* type) {}
+#endif
+
+void log_event_disk_stats(struct disk_stats* stats, const char* type) {
+ // skip if the input structure are all zeros
+ if (stats == NULL || stats->is_zero()) return;
+
+ android_log_event_list(EVENTLOGTAG_DISKSTATS)
+ << type << stats->start_time << stats->end_time
+ << stats->read_ios << stats->read_merges
+ << stats->read_sectors << stats->read_ticks
+ << stats->write_ios << stats->write_merges
+ << stats->write_sectors << stats->write_ticks
+ << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue
+ << LOG_ID_EVENTS;
+}
+
+} // namespace
+
+bool get_time(struct timespec* ts) {
+ // Use monotonic to exclude suspend time so that we measure IO bytes/sec
+ // when system is running.
+ int ret = clock_gettime(CLOCK_MONOTONIC, ts);
+ if (ret < 0) {
+ PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+ return false;
+ }
+ return true;
+}
+
+void init_disk_stats_other(const struct timespec& ts, struct disk_stats* stats) {
+ stats->start_time = 0;
+ stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC + ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC);
+ stats->counter = 1;
+ stats->io_avg = (double)stats->io_in_flight;
+}
+
+bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
+ // Get time
+ struct timespec ts;
+ if (!get_time(&ts)) {
+ return false;
+ }
+
+ std::string buffer;
+ if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
+ PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed.";
+ return false;
+ }
+
+ // Regular diskstats entries
+ std::stringstream ss(buffer);
+ for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+ ss >> *((uint64_t*)stats + i);
+ }
+ // Other entries
+ init_disk_stats_other(ts, stats);
+ return true;
+}
+
+void convert_hal_disk_stats(struct disk_stats* dst, const DiskStats& src) {
+ dst->read_ios = src.reads;
+ dst->read_merges = src.readMerges;
+ dst->read_sectors = src.readSectors;
+ dst->read_ticks = src.readTicks;
+ dst->write_ios = src.writes;
+ dst->write_merges = src.writeMerges;
+ dst->write_sectors = src.writeSectors;
+ dst->write_ticks = src.writeTicks;
+ dst->io_in_flight = src.ioInFlight;
+ dst->io_ticks = src.ioTicks;
+ dst->io_in_queue = src.ioInQueue;
+}
+
+bool get_disk_stats_from_health_hal(const sp<IHealth>& service, struct disk_stats* stats) {
+ struct timespec ts;
+ if (!get_time(&ts)) {
+ return false;
+ }
+
+ bool success = false;
+ auto ret = service->getDiskStats([&success, stats](auto result, const auto& halStats) {
+ if (result != Result::SUCCESS || halStats.size() == 0) {
+ LOG_TO(SYSTEM, ERROR) << "getDiskStats failed with result " << toString(result)
+ << " and size " << halStats.size();
+ return;
+ }
+
+ convert_hal_disk_stats(stats, halStats[0]);
+ success = true;
+ });
+
+ if (!ret.isOk()) {
+ LOG_TO(SYSTEM, ERROR) << "getDiskStats failed with " << ret.description();
+ return false;
+ }
+
+ if (!success) {
+ return false;
+ }
+
+ init_disk_stats_other(ts, stats);
+ return true;
+}
+
+struct disk_perf get_disk_perf(struct disk_stats* stats)
+{
+ struct disk_perf perf = {};
+
+ if (stats->io_ticks) {
+ if (stats->read_ticks) {
+ unsigned long long divisor = stats->read_ticks * stats->io_ticks;
+ perf.read_perf = ((unsigned long long)SECTOR_SIZE *
+ stats->read_sectors * stats->io_in_queue +
+ (divisor >> 1)) / divisor;
+ perf.read_ios = ((unsigned long long)SEC_TO_MSEC *
+ stats->read_ios * stats->io_in_queue +
+ (divisor >> 1)) / divisor;
+ }
+ if (stats->write_ticks) {
+ unsigned long long divisor = stats->write_ticks * stats->io_ticks;
+ perf.write_perf = ((unsigned long long)SECTOR_SIZE *
+ stats->write_sectors * stats->io_in_queue +
+ (divisor >> 1)) / divisor;
+ perf.write_ios = ((unsigned long long)SEC_TO_MSEC *
+ stats->write_ios * stats->io_in_queue +
+ (divisor >> 1)) / divisor;
+ }
+ perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) /
+ stats->io_ticks;
+ }
+ return perf;
+}
+
+void get_inc_disk_stats(const struct disk_stats* prev, const struct disk_stats* curr,
+ struct disk_stats* inc)
+{
+ *inc = *curr - *prev;
+ inc->start_time = prev->end_time;
+ inc->end_time = curr->end_time;
+ inc->io_avg = curr->io_avg;
+ inc->counter = 1;
+}
+
+// Add src to dst
+void add_disk_stats(struct disk_stats* src, struct disk_stats* dst)
+{
+ if (dst->end_time != 0 && dst->end_time != src->start_time) {
+ LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats"
+ << " are added. dst end with " << dst->end_time
+ << ", src start with " << src->start_time;
+ }
+
+ *dst += *src;
+
+ dst->io_in_flight = src->io_in_flight;
+ if (dst->counter + src->counter) {
+ dst->io_avg =
+ ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) /
+ (dst->counter + src->counter);
+ }
+ dst->counter += src->counter;
+ dst->end_time = src->end_time;
+ if (dst->start_time == 0) {
+ dst->start_time = src->start_time;
+ }
+}
+
+/* disk_stats_monitor */
+void disk_stats_monitor::update_mean()
+{
+ CHECK(mValid);
+ mMean.read_perf = (uint32_t)mStats.read_perf.get_mean();
+ mMean.read_ios = (uint32_t)mStats.read_ios.get_mean();
+ mMean.write_perf = (uint32_t)mStats.write_perf.get_mean();
+ mMean.write_ios = (uint32_t)mStats.write_ios.get_mean();
+ mMean.queue = (uint32_t)mStats.queue.get_mean();
+}
+
+void disk_stats_monitor::update_std()
+{
+ CHECK(mValid);
+ mStd.read_perf = (uint32_t)mStats.read_perf.get_std();
+ mStd.read_ios = (uint32_t)mStats.read_ios.get_std();
+ mStd.write_perf = (uint32_t)mStats.write_perf.get_std();
+ mStd.write_ios = (uint32_t)mStats.write_ios.get_std();
+ mStd.queue = (uint32_t)mStats.queue.get_std();
+}
+
+void disk_stats_monitor::add(struct disk_perf* perf)
+{
+ mStats.read_perf.add(perf->read_perf);
+ mStats.read_ios.add(perf->read_ios);
+ mStats.write_perf.add(perf->write_perf);
+ mStats.write_ios.add(perf->write_ios);
+ mStats.queue.add(perf->queue);
+}
+
+void disk_stats_monitor::evict(struct disk_perf* perf) {
+ mStats.read_perf.evict(perf->read_perf);
+ mStats.read_ios.evict(perf->read_ios);
+ mStats.write_perf.evict(perf->write_perf);
+ mStats.write_ios.evict(perf->write_ios);
+ mStats.queue.evict(perf->queue);
+}
+
+bool disk_stats_monitor::detect(struct disk_perf* perf)
+{
+ return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) &&
+ ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) &&
+ ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf);
+}
+
+void disk_stats_monitor::update(struct disk_stats* curr)
+{
+ disk_stats inc;
+ get_inc_disk_stats(&mPrevious, curr, &inc);
+ add_disk_stats(&inc, &mAccumulate_pub);
+
+ struct disk_perf perf = get_disk_perf(&inc);
+ log_debug_disk_perf(&perf, "regular");
+
+ add(&perf);
+ mBuffer.push(perf);
+ if (mBuffer.size() > mWindow) {
+ evict(&mBuffer.front());
+ mBuffer.pop();
+ mValid = true;
+ }
+
+ // Update internal data structures
+ if (LIKELY(mValid)) {
+ CHECK_EQ(mBuffer.size(), mWindow);
+ update_mean();
+ update_std();
+ if (UNLIKELY(detect(&perf))) {
+ mStall = true;
+ add_disk_stats(&inc, &mAccumulate);
+ log_debug_disk_perf(&mMean, "stalled_mean");
+ log_debug_disk_perf(&mStd, "stalled_std");
+ } else {
+ if (mStall) {
+ struct disk_perf acc_perf = get_disk_perf(&mAccumulate);
+ log_debug_disk_perf(&acc_perf, "stalled");
+ log_event_disk_stats(&mAccumulate, "stalled");
+ mStall = false;
+ memset(&mAccumulate, 0, sizeof(mAccumulate));
+ }
+ }
+ }
+
+ mPrevious = *curr;
+}
+
+void disk_stats_monitor::update() {
+ disk_stats curr;
+ if (mHealth != nullptr) {
+ if (!get_disk_stats_from_health_hal(mHealth, &curr)) {
+ return;
+ }
+ } else {
+ if (!parse_disk_stats(DISK_STATS_PATH, &curr)) {
+ return;
+ }
+ }
+
+ update(&curr);
+}
+
+void disk_stats_monitor::publish(void)
+{
+ struct disk_perf perf = get_disk_perf(&mAccumulate_pub);
+ log_debug_disk_perf(&perf, "regular");
+ log_event_disk_stats(&mAccumulate, "regular");
+ // Reset global structures
+ memset(&mAccumulate_pub, 0, sizeof(struct disk_stats));
+}
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index b5fb13e..5605f66 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -20,6 +20,8 @@
#include <string.h>
#include <sys/statvfs.h>
+#include <numeric>
+
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/logging.h>
@@ -27,9 +29,16 @@
#include <log/log_event_list.h>
#include "storaged.h"
+#include "storaged_info.h"
using namespace std;
+using namespace chrono;
using namespace android::base;
+using namespace storaged_proto;
+
+using android::hardware::health::V2_0::IHealth;
+using android::hardware::health::V2_0::Result;
+using android::hardware::health::V2_0::StorageInfo;
const string emmc_info_t::emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
const string emmc_info_t::emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd";
@@ -39,14 +48,20 @@
const string ufs_info_t::health_file = "/sys/devices/soc/624000.ufshc/health";
-static bool FileExists(const std::string& filename)
+namespace {
+
+bool FileExists(const std::string& filename)
{
struct stat buffer;
return stat(filename.c_str(), &buffer) == 0;
}
-storage_info_t* storage_info_t::get_storage_info()
-{
+} // namespace
+
+storage_info_t* storage_info_t::get_storage_info(const sp<IHealth>& healthService) {
+ if (healthService != nullptr) {
+ return new health_storage_info_t(healthService);
+ }
if (FileExists(emmc_info_t::emmc_sysfs) ||
FileExists(emmc_info_t::emmc_debugfs)) {
return new emmc_info_t;
@@ -57,7 +72,39 @@
return new storage_info_t;
}
-void storage_info_t::refresh()
+void storage_info_t::load_perf_history_proto(const IOPerfHistory& perf_history)
+{
+ Mutex::Autolock _l(si_mutex);
+
+ if (!perf_history.has_day_start_sec() ||
+ perf_history.daily_perf_size() > (int)daily_perf.size() ||
+ perf_history.weekly_perf_size() > (int)weekly_perf.size()) {
+ LOG_TO(SYSTEM, ERROR) << "Invalid IOPerfHistory proto";
+ return;
+ }
+
+ day_start_tp = {};
+ day_start_tp += chrono::seconds(perf_history.day_start_sec());
+
+ nr_samples = perf_history.nr_samples();
+ for (auto bw : perf_history.recent_perf()) {
+ recent_perf.push_back(bw);
+ }
+
+ nr_days = perf_history.nr_days();
+ int i = 0;
+ for (auto bw : perf_history.daily_perf()) {
+ daily_perf[i++] = bw;
+ }
+
+ nr_weeks = perf_history.nr_weeks();
+ i = 0;
+ for (auto bw : perf_history.weekly_perf()) {
+ weekly_perf[i++] = bw;
+ }
+}
+
+void storage_info_t::refresh(IOPerfHistory* perf_history)
{
struct statvfs buf;
if (statvfs(userdata_path.c_str(), &buf) != 0) {
@@ -67,6 +114,24 @@
userdata_total_kb = buf.f_bsize * buf.f_blocks >> 10;
userdata_free_kb = buf.f_bfree * buf.f_blocks >> 10;
+
+ Mutex::Autolock _l(si_mutex);
+
+ perf_history->Clear();
+ perf_history->set_day_start_sec(
+ duration_cast<chrono::seconds>(day_start_tp.time_since_epoch()).count());
+ for (const uint32_t& bw : recent_perf) {
+ perf_history->add_recent_perf(bw);
+ }
+ perf_history->set_nr_samples(nr_samples);
+ for (const uint32_t& bw : daily_perf) {
+ perf_history->add_daily_perf(bw);
+ }
+ perf_history->set_nr_days(nr_days);
+ for (const uint32_t& bw : weekly_perf) {
+ perf_history->add_weekly_perf(bw);
+ }
+ perf_history->set_nr_weeks(nr_weeks);
}
void storage_info_t::publish()
@@ -76,6 +141,95 @@
<< LOG_ID_EVENTS;
}
+void storage_info_t::update_perf_history(uint32_t bw,
+ const time_point<system_clock>& tp)
+{
+ Mutex::Autolock _l(si_mutex);
+
+ if (tp > day_start_tp &&
+ duration_cast<chrono::seconds>(tp - day_start_tp).count() < DAY_TO_SEC) {
+ if (nr_samples >= recent_perf.size()) {
+ recent_perf.push_back(bw);
+ } else {
+ recent_perf[nr_samples] = bw;
+ }
+ nr_samples++;
+ return;
+ }
+
+ if (nr_samples < recent_perf.size()) {
+ recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end());
+ }
+
+ uint32_t daily_avg_bw = 0;
+ if (!recent_perf.empty()) {
+ daily_avg_bw = accumulate(recent_perf.begin(), recent_perf.end(), 0) / recent_perf.size();
+ }
+
+ day_start_tp = tp - chrono::seconds(duration_cast<chrono::seconds>(
+ tp.time_since_epoch()).count() % DAY_TO_SEC);
+
+ nr_samples = 0;
+ if (recent_perf.empty())
+ recent_perf.resize(1);
+ recent_perf[nr_samples++] = bw;
+
+ if (nr_days < WEEK_TO_DAYS) {
+ daily_perf[nr_days++] = daily_avg_bw;
+ return;
+ }
+
+ DCHECK(nr_days > 0);
+ uint32_t week_avg_bw = accumulate(daily_perf.begin(),
+ daily_perf.begin() + nr_days, 0) / nr_days;
+
+ nr_days = 0;
+ daily_perf[nr_days++] = daily_avg_bw;
+
+ if (nr_weeks >= YEAR_TO_WEEKS) {
+ nr_weeks = 0;
+ }
+ weekly_perf[nr_weeks++] = week_avg_bw;
+}
+
+vector<int> storage_info_t::get_perf_history()
+{
+ Mutex::Autolock _l(si_mutex);
+
+ vector<int> ret(3 + recent_perf.size() + daily_perf.size() + weekly_perf.size());
+
+ ret[0] = recent_perf.size();
+ ret[1] = daily_perf.size();
+ ret[2] = weekly_perf.size();
+
+ int start = 3;
+ for (size_t i = 0; i < recent_perf.size(); i++) {
+ int idx = (recent_perf.size() + nr_samples - 1 - i) % recent_perf.size();
+ ret[start + i] = recent_perf[idx];
+ }
+
+ start += recent_perf.size();
+ for (size_t i = 0; i < daily_perf.size(); i++) {
+ int idx = (daily_perf.size() + nr_days - 1 - i) % daily_perf.size();
+ ret[start + i] = daily_perf[idx];
+ }
+
+ start += daily_perf.size();
+ for (size_t i = 0; i < weekly_perf.size(); i++) {
+ int idx = (weekly_perf.size() + nr_weeks - 1 - i) % weekly_perf.size();
+ ret[start + i] = weekly_perf[idx];
+ }
+
+ return ret;
+}
+
+uint32_t storage_info_t::get_recent_perf() {
+ Mutex::Autolock _l(si_mutex);
+ if (recent_perf.size() == 0) return 0;
+ return accumulate(recent_perf.begin(), recent_perf.end(), recent_perf.size() / 2) /
+ recent_perf.size();
+}
+
void emmc_info_t::report()
{
if (!report_sysfs() && !report_debugfs())
@@ -121,6 +275,8 @@
return true;
}
+namespace {
+
const size_t EXT_CSD_FILE_MIN_SIZE = 1024;
/* 2 characters in string for each byte */
const size_t EXT_CSD_REV_IDX = 192 * 2;
@@ -128,6 +284,8 @@
const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * 2;
const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * 2;
+} // namespace
+
bool emmc_info_t::report_debugfs()
{
string buffer;
@@ -210,3 +368,25 @@
publish();
}
+void health_storage_info_t::report() {
+ auto ret = mHealth->getStorageInfo([this](auto result, const auto& halInfos) {
+ if (result != Result::SUCCESS || halInfos.size() == 0) {
+ LOG_TO(SYSTEM, DEBUG) << "getStorageInfo failed with result " << toString(result)
+ << " and size " << halInfos.size();
+ return;
+ }
+ set_values_from_hal_storage_info(halInfos[0]);
+ publish();
+ });
+
+ if (!ret.isOk()) {
+ LOG_TO(SYSTEM, DEBUG) << "getStorageInfo failed with " << ret.description();
+ }
+}
+
+void health_storage_info_t::set_values_from_hal_storage_info(const StorageInfo& halInfo) {
+ eol = halInfo.eol;
+ lifetime_a = halInfo.lifetimeA;
+ lifetime_b = halInfo.lifetimeB;
+ version = halInfo.version;
+}
diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp
index b1d3bfd..17ea25b 100644
--- a/storaged/storaged_service.cpp
+++ b/storaged/storaged_service.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <inttypes.h>
#include <stdint.h>
#include <vector>
@@ -29,60 +30,69 @@
#include <private/android_filesystem_config.h>
#include <storaged.h>
+#include <storaged_utils.h>
#include <storaged_service.h>
+using namespace std;
using namespace android::base;
-extern sp<storaged_t> storaged;
+extern sp<storaged_t> storaged_sp;
-std::vector<struct uid_info> BpStoraged::dump_uids(const char* /*option*/) {
- Parcel data, reply;
- data.writeInterfaceToken(IStoraged::getInterfaceDescriptor());
-
- remote()->transact(DUMPUIDS, data, &reply);
-
- uint32_t res_size = reply.readInt32();
- std::vector<struct uid_info> res(res_size);
- for (auto&& uid : res) {
- uid.uid = reply.readInt32();
- uid.name = reply.readCString();
- reply.read(&uid.io, sizeof(uid.io));
- }
- return res;
+status_t StoragedService::start() {
+ return BinderService<StoragedService>::publish();
}
-IMPLEMENT_META_INTERFACE(Storaged, "Storaged");
-status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- switch(code) {
- case DUMPUIDS: {
- if (!data.checkInterface(this))
- return BAD_TYPE;
- std::vector<struct uid_info> res = dump_uids(NULL);
- reply->writeInt32(res.size());
- for (auto uid : res) {
- reply->writeInt32(uid.uid);
- reply->writeCString(uid.name.c_str());
- reply->write(&uid.io, sizeof(uid.io));
- }
- return NO_ERROR;
- }
- break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
+void StoragedService::dumpUidRecords(int fd, const vector<uid_record>& entries) {
+ map<string, io_usage> merged_entries = merge_io_usage(entries);
+ for (const auto& rec : merged_entries) {
+ dprintf(fd, "%s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
+ " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ rec.first.c_str(),
+ rec.second.bytes[READ][FOREGROUND][CHARGER_OFF],
+ rec.second.bytes[WRITE][FOREGROUND][CHARGER_OFF],
+ rec.second.bytes[READ][BACKGROUND][CHARGER_OFF],
+ rec.second.bytes[WRITE][BACKGROUND][CHARGER_OFF],
+ rec.second.bytes[READ][FOREGROUND][CHARGER_ON],
+ rec.second.bytes[WRITE][FOREGROUND][CHARGER_ON],
+ rec.second.bytes[READ][BACKGROUND][CHARGER_ON],
+ rec.second.bytes[WRITE][BACKGROUND][CHARGER_ON]);
}
}
-std::vector<struct uid_info> Storaged::dump_uids(const char* /* option */) {
- std::vector<struct uid_info> uids_v;
- std::unordered_map<uint32_t, struct uid_info> uids_m = storaged->get_uids();
+void StoragedService::dumpUidRecordsDebug(int fd, const vector<uid_record>& entries) {
+ for (const auto& record : entries) {
+ const io_usage& uid_usage = record.ios.uid_ios;
+ dprintf(fd, "%s_%d %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
+ " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ record.name.c_str(), record.ios.user_id,
+ uid_usage.bytes[READ][FOREGROUND][CHARGER_OFF],
+ uid_usage.bytes[WRITE][FOREGROUND][CHARGER_OFF],
+ uid_usage.bytes[READ][BACKGROUND][CHARGER_OFF],
+ uid_usage.bytes[WRITE][BACKGROUND][CHARGER_OFF],
+ uid_usage.bytes[READ][FOREGROUND][CHARGER_ON],
+ uid_usage.bytes[WRITE][FOREGROUND][CHARGER_ON],
+ uid_usage.bytes[READ][BACKGROUND][CHARGER_ON],
+ uid_usage.bytes[WRITE][BACKGROUND][CHARGER_ON]);
- for (const auto& it : uids_m) {
- uids_v.push_back(it.second);
+ for (const auto& task_it : record.ios.task_ios) {
+ const io_usage& task_usage = task_it.second;
+ const string& comm = task_it.first;
+ dprintf(fd, "-> %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
+ " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ comm.c_str(),
+ task_usage.bytes[READ][FOREGROUND][CHARGER_OFF],
+ task_usage.bytes[WRITE][FOREGROUND][CHARGER_OFF],
+ task_usage.bytes[READ][BACKGROUND][CHARGER_OFF],
+ task_usage.bytes[WRITE][BACKGROUND][CHARGER_OFF],
+ task_usage.bytes[READ][FOREGROUND][CHARGER_ON],
+ task_usage.bytes[WRITE][FOREGROUND][CHARGER_ON],
+ task_usage.bytes[READ][BACKGROUND][CHARGER_ON],
+ task_usage.bytes[WRITE][BACKGROUND][CHARGER_ON]);
+ }
}
- return uids_v;
}
-status_t Storaged::dump(int fd, const Vector<String16>& args) {
+status_t StoragedService::dump(int fd, const Vector<String16>& args) {
IPCThreadState* self = IPCThreadState::self();
const int pid = self->getCallingPid();
const int uid = self->getCallingUid();
@@ -96,6 +106,7 @@
int time_window = 0;
uint64_t threshold = 0;
bool force_report = false;
+ bool debug = false;
for (size_t i = 0; i < args.size(); i++) {
const auto& arg = args[i];
if (arg == String16("--hours")) {
@@ -123,47 +134,87 @@
force_report = true;
continue;
}
+ if (arg == String16("--debug")) {
+ debug = true;
+ continue;
+ }
}
uint64_t last_ts = 0;
- const std::map<uint64_t, struct uid_records>& records =
- storaged->get_uid_records(hours, threshold, force_report);
+ map<uint64_t, struct uid_records> records =
+ storaged_sp->get_uid_records(hours, threshold, force_report);
for (const auto& it : records) {
if (last_ts != it.second.start_ts) {
- dprintf(fd, "%llu", (unsigned long long)it.second.start_ts);
+ dprintf(fd, "%" PRIu64, it.second.start_ts);
}
- dprintf(fd, ",%llu\n", (unsigned long long)it.first);
+ dprintf(fd, ",%" PRIu64 "\n", it.first);
last_ts = it.first;
- for (const auto& record : it.second.entries) {
- dprintf(fd, "%s %ju %ju %ju %ju %ju %ju %ju %ju\n",
- record.name.c_str(),
- record.ios.bytes[READ][FOREGROUND][CHARGER_OFF],
- record.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF],
- record.ios.bytes[READ][BACKGROUND][CHARGER_OFF],
- record.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF],
- record.ios.bytes[READ][FOREGROUND][CHARGER_ON],
- record.ios.bytes[WRITE][FOREGROUND][CHARGER_ON],
- record.ios.bytes[READ][BACKGROUND][CHARGER_ON],
- record.ios.bytes[WRITE][BACKGROUND][CHARGER_ON]);
+ if (!debug) {
+ dumpUidRecords(fd, it.second.entries);
+ } else {
+ dumpUidRecordsDebug(fd, it.second.entries);
}
}
if (time_window) {
- storaged->update_uid_io_interval(time_window);
+ storaged_sp->update_uid_io_interval(time_window);
}
return NO_ERROR;
}
-sp<IStoraged> get_storaged_service() {
+binder::Status StoragedService::onUserStarted(int32_t userId) {
+ storaged_sp->add_user_ce(userId);
+ return binder::Status::ok();
+}
+
+binder::Status StoragedService::onUserStopped(int32_t userId) {
+ storaged_sp->remove_user_ce(userId);
+ return binder::Status::ok();
+}
+
+binder::Status StoragedService::getRecentPerf(int32_t* _aidl_return) {
+ uint32_t recent_perf = storaged_sp->get_recent_perf();
+ if (recent_perf > INT32_MAX) {
+ *_aidl_return = INT32_MAX;
+ } else {
+ *_aidl_return = static_cast<int32_t>(recent_perf);
+ }
+ return binder::Status::ok();
+}
+
+status_t StoragedPrivateService::start() {
+ return BinderService<StoragedPrivateService>::publish();
+}
+
+binder::Status StoragedPrivateService::dumpUids(
+ vector<::android::os::storaged::UidInfo>* _aidl_return) {
+ unordered_map<uint32_t, uid_info> uids_m = storaged_sp->get_uids();
+
+ for (const auto& it : uids_m) {
+ UidInfo uinfo;
+ uinfo.uid = it.second.uid;
+ uinfo.name = it.second.name;
+ uinfo.tasks = it.second.tasks;
+ memcpy(&uinfo.io, &it.second.io, sizeof(uinfo.io));
+ _aidl_return->push_back(uinfo);
+ }
+ return binder::Status::ok();
+}
+
+binder::Status StoragedPrivateService::dumpPerfHistory(
+ vector<int32_t>* _aidl_return) {
+ *_aidl_return = storaged_sp->get_perf_history();
+ return binder::Status::ok();
+}
+
+sp<IStoragedPrivate> get_storaged_pri_service() {
sp<IServiceManager> sm = defaultServiceManager();
if (sm == NULL) return NULL;
- sp<IBinder> binder = sm->getService(String16("storaged"));
+ sp<IBinder> binder = sm->getService(String16("storaged_pri"));
if (binder == NULL) return NULL;
- sp<IStoraged> storaged = interface_cast<IStoraged>(binder);
-
- return storaged;
+ return interface_cast<IStoragedPrivate>(binder);
}
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index dd8bdd6..5745782 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -38,16 +38,87 @@
using namespace android;
using namespace android::base;
using namespace android::content::pm;
+using namespace android::os::storaged;
+using namespace storaged_proto;
-static bool refresh_uid_names;
+namespace {
-std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
+bool refresh_uid_names;
+const char* UID_IO_STATS_PATH = "/proc/uid_io/stats";
+
+} // namepsace
+
+std::unordered_map<uint32_t, uid_info> uid_monitor::get_uid_io_stats()
{
- std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+ Mutex::Autolock _l(uidm_mutex);
return get_uid_io_stats_locked();
};
-static void get_uid_names(const vector<int>& uids, const vector<std::string*>& uid_names)
+/* return true on parse success and false on failure */
+bool uid_info::parse_uid_io_stats(std::string&& s)
+{
+ std::vector<std::string> fields = Split(s, " ");
+ if (fields.size() < 11 ||
+ !ParseUint(fields[0], &uid) ||
+ !ParseUint(fields[1], &io[FOREGROUND].rchar) ||
+ !ParseUint(fields[2], &io[FOREGROUND].wchar) ||
+ !ParseUint(fields[3], &io[FOREGROUND].read_bytes) ||
+ !ParseUint(fields[4], &io[FOREGROUND].write_bytes) ||
+ !ParseUint(fields[5], &io[BACKGROUND].rchar) ||
+ !ParseUint(fields[6], &io[BACKGROUND].wchar) ||
+ !ParseUint(fields[7], &io[BACKGROUND].read_bytes) ||
+ !ParseUint(fields[8], &io[BACKGROUND].write_bytes) ||
+ !ParseUint(fields[9], &io[FOREGROUND].fsync) ||
+ !ParseUint(fields[10], &io[BACKGROUND].fsync)) {
+ LOG_TO(SYSTEM, WARNING) << "Invalid uid I/O stats: \""
+ << s << "\"";
+ return false;
+ }
+ return true;
+}
+
+/* return true on parse success and false on failure */
+bool task_info::parse_task_io_stats(std::string&& s)
+{
+ std::vector<std::string> fields = Split(s, ",");
+ size_t size = fields.size();
+ if (size < 13 ||
+ !ParseInt(fields[size - 11], &pid) ||
+ !ParseUint(fields[size - 10], &io[FOREGROUND].rchar) ||
+ !ParseUint(fields[size - 9], &io[FOREGROUND].wchar) ||
+ !ParseUint(fields[size - 8], &io[FOREGROUND].read_bytes) ||
+ !ParseUint(fields[size - 7], &io[FOREGROUND].write_bytes) ||
+ !ParseUint(fields[size - 6], &io[BACKGROUND].rchar) ||
+ !ParseUint(fields[size - 5], &io[BACKGROUND].wchar) ||
+ !ParseUint(fields[size - 4], &io[BACKGROUND].read_bytes) ||
+ !ParseUint(fields[size - 3], &io[BACKGROUND].write_bytes) ||
+ !ParseUint(fields[size - 2], &io[FOREGROUND].fsync) ||
+ !ParseUint(fields[size - 1], &io[BACKGROUND].fsync)) {
+ LOG_TO(SYSTEM, WARNING) << "Invalid task I/O stats: \""
+ << s << "\"";
+ return false;
+ }
+ comm = Join(std::vector<std::string>(
+ fields.begin() + 1, fields.end() - 11), ',');
+ return true;
+}
+
+bool io_usage::is_zero() const
+{
+ for (int i = 0; i < IO_TYPES; i++) {
+ for (int j = 0; j < UID_STATS; j++) {
+ for (int k = 0; k < CHARGER_STATS; k++) {
+ if (bytes[i][j][k])
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+namespace {
+
+void get_uid_names(const vector<int>& uids, const vector<std::string*>& uid_names)
{
sp<IServiceManager> sm = defaultServiceManager();
if (sm == NULL) {
@@ -79,17 +150,19 @@
refresh_uid_names = false;
}
-std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
+} // namespace
+
+std::unordered_map<uint32_t, uid_info> uid_monitor::get_uid_io_stats_locked()
{
- std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
+ std::unordered_map<uint32_t, uid_info> uid_io_stats;
std::string buffer;
if (!ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
return uid_io_stats;
}
- std::vector<std::string> io_stats = Split(buffer, "\n");
- struct uid_info u;
+ std::vector<std::string> io_stats = Split(std::move(buffer), "\n");
+ uid_info u;
vector<int> uids;
vector<std::string*> uid_names;
@@ -97,32 +170,24 @@
if (io_stats[i].empty()) {
continue;
}
- std::vector<std::string> fields = Split(io_stats[i], " ");
- if (fields.size() < 11 ||
- !ParseUint(fields[0], &u.uid) ||
- !ParseUint(fields[1], &u.io[FOREGROUND].rchar) ||
- !ParseUint(fields[2], &u.io[FOREGROUND].wchar) ||
- !ParseUint(fields[3], &u.io[FOREGROUND].read_bytes) ||
- !ParseUint(fields[4], &u.io[FOREGROUND].write_bytes) ||
- !ParseUint(fields[5], &u.io[BACKGROUND].rchar) ||
- !ParseUint(fields[6], &u.io[BACKGROUND].wchar) ||
- !ParseUint(fields[7], &u.io[BACKGROUND].read_bytes) ||
- !ParseUint(fields[8], &u.io[BACKGROUND].write_bytes) ||
- !ParseUint(fields[9], &u.io[FOREGROUND].fsync) ||
- !ParseUint(fields[10], &u.io[BACKGROUND].fsync)) {
- LOG_TO(SYSTEM, WARNING) << "Invalid I/O stats: \""
- << io_stats[i] << "\"";
- continue;
- }
- uid_io_stats[u.uid] = u;
- uid_io_stats[u.uid].name = std::to_string(u.uid);
- uids.push_back(u.uid);
- uid_names.push_back(&uid_io_stats[u.uid].name);
- if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
- refresh_uid_names = true;
+ if (io_stats[i].compare(0, 4, "task")) {
+ if (!u.parse_uid_io_stats(std::move(io_stats[i])))
+ continue;
+ uid_io_stats[u.uid] = u;
+ uid_io_stats[u.uid].name = std::to_string(u.uid);
+ uids.push_back(u.uid);
+ uid_names.push_back(&uid_io_stats[u.uid].name);
+ if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
+ refresh_uid_names = true;
+ } else {
+ uid_io_stats[u.uid].name = last_uid_io_stats[u.uid].name;
+ }
} else {
- uid_io_stats[u.uid].name = last_uid_io_stats[u.uid].name;
+ task_info t;
+ if (!t.parse_task_io_stats(std::move(io_stats[i])))
+ continue;
+ uid_io_stats[u.uid].tasks[t.pid] = t;
}
}
@@ -133,34 +198,41 @@
return uid_io_stats;
}
-static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
+namespace {
-static inline int records_size(
- const std::map<uint64_t, struct uid_records>& curr_records)
+const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
+
+inline size_t history_size(
+ const std::map<uint64_t, struct uid_records>& history)
{
- int count = 0;
- for (auto const& it : curr_records) {
+ size_t count = 0;
+ for (auto const& it : history) {
count += it.second.entries.size();
}
return count;
}
-static struct uid_io_usage zero_io_usage;
+} // namespace
void uid_monitor::add_records_locked(uint64_t curr_ts)
{
// remove records more than 5 days old
if (curr_ts > 5 * DAY_TO_SEC) {
- auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC);
- records.erase(records.begin(), it);
+ auto it = io_history.lower_bound(curr_ts - 5 * DAY_TO_SEC);
+ io_history.erase(io_history.begin(), it);
}
struct uid_records new_records;
for (const auto& p : curr_io_stats) {
struct uid_record record = {};
record.name = p.first;
- record.ios = p.second;
- if (memcmp(&record.ios, &zero_io_usage, sizeof(struct uid_io_usage))) {
+ if (!p.second.uid_ios.is_zero()) {
+ record.ios.user_id = p.second.user_id;
+ record.ios.uid_ios = p.second.uid_ios;
+ for (const auto& p_task : p.second.task_ios) {
+ if (!p_task.second.is_zero())
+ record.ios.task_ios[p_task.first] = p_task.second;
+ }
new_records.entries.push_back(record);
}
}
@@ -173,25 +245,25 @@
return;
// make some room for new records
- int overflow = records_size(records) +
+ ssize_t overflow = history_size(io_history) +
new_records.entries.size() - MAX_UID_RECORDS_SIZE;
- while (overflow > 0 && records.size() > 0) {
- auto del_it = records.begin();
+ while (overflow > 0 && io_history.size() > 0) {
+ auto del_it = io_history.begin();
overflow -= del_it->second.entries.size();
- records.erase(records.begin());
+ io_history.erase(io_history.begin());
}
- records[curr_ts] = new_records;
+ io_history[curr_ts] = new_records;
}
std::map<uint64_t, struct uid_records> uid_monitor::dump(
double hours, uint64_t threshold, bool force_report)
{
if (force_report) {
- report();
+ report(nullptr);
}
- std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+ Mutex::Autolock _l(uidm_mutex);
std::map<uint64_t, struct uid_records> dump_records;
uint64_t first_ts = 0;
@@ -200,19 +272,20 @@
first_ts = time(NULL) - hours * HOUR_TO_SEC;
}
- for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) {
+ for (auto it = io_history.lower_bound(first_ts); it != io_history.end(); ++it) {
const std::vector<struct uid_record>& recs = it->second.entries;
struct uid_records filtered;
for (const auto& rec : recs) {
- if (rec.ios.bytes[READ][FOREGROUND][CHARGER_ON] +
- rec.ios.bytes[READ][FOREGROUND][CHARGER_OFF] +
- rec.ios.bytes[READ][BACKGROUND][CHARGER_ON] +
- rec.ios.bytes[READ][BACKGROUND][CHARGER_OFF] +
- rec.ios.bytes[WRITE][FOREGROUND][CHARGER_ON] +
- rec.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF] +
- rec.ios.bytes[WRITE][BACKGROUND][CHARGER_ON] +
- rec.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) {
+ const io_usage& uid_usage = rec.ios.uid_ios;
+ if (uid_usage.bytes[READ][FOREGROUND][CHARGER_ON] +
+ uid_usage.bytes[READ][FOREGROUND][CHARGER_OFF] +
+ uid_usage.bytes[READ][BACKGROUND][CHARGER_ON] +
+ uid_usage.bytes[READ][BACKGROUND][CHARGER_OFF] +
+ uid_usage.bytes[WRITE][FOREGROUND][CHARGER_ON] +
+ uid_usage.bytes[WRITE][FOREGROUND][CHARGER_OFF] +
+ uid_usage.bytes[WRITE][BACKGROUND][CHARGER_ON] +
+ uid_usage.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) {
filtered.entries.push_back(rec);
}
}
@@ -230,20 +303,21 @@
void uid_monitor::update_curr_io_stats_locked()
{
- std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
+ std::unordered_map<uint32_t, uid_info> uid_io_stats =
get_uid_io_stats_locked();
if (uid_io_stats.empty()) {
return;
}
for (const auto& it : uid_io_stats) {
- const struct uid_info& uid = it.second;
-
+ const uid_info& uid = it.second;
if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
- curr_io_stats[uid.name] = {};
+ curr_io_stats[uid.name] = {};
}
struct uid_io_usage& usage = curr_io_stats[uid.name];
+ usage.user_id = multiuser_get_user_id(uid.uid);
+
int64_t fg_rd_delta = uid.io[FOREGROUND].read_bytes -
last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes;
int64_t bg_rd_delta = uid.io[BACKGROUND].read_bytes -
@@ -253,30 +327,177 @@
int64_t bg_wr_delta = uid.io[BACKGROUND].write_bytes -
last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;
- usage.bytes[READ][FOREGROUND][charger_stat] +=
+ usage.uid_ios.bytes[READ][FOREGROUND][charger_stat] +=
(fg_rd_delta < 0) ? 0 : fg_rd_delta;
- usage.bytes[READ][BACKGROUND][charger_stat] +=
+ usage.uid_ios.bytes[READ][BACKGROUND][charger_stat] +=
(bg_rd_delta < 0) ? 0 : bg_rd_delta;
- usage.bytes[WRITE][FOREGROUND][charger_stat] +=
+ usage.uid_ios.bytes[WRITE][FOREGROUND][charger_stat] +=
(fg_wr_delta < 0) ? 0 : fg_wr_delta;
- usage.bytes[WRITE][BACKGROUND][charger_stat] +=
+ usage.uid_ios.bytes[WRITE][BACKGROUND][charger_stat] +=
(bg_wr_delta < 0) ? 0 : bg_wr_delta;
+
+ for (const auto& task_it : uid.tasks) {
+ const task_info& task = task_it.second;
+ const pid_t pid = task_it.first;
+ const std::string& comm = task_it.second.comm;
+ int64_t task_fg_rd_delta = task.io[FOREGROUND].read_bytes -
+ last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].read_bytes;
+ int64_t task_bg_rd_delta = task.io[BACKGROUND].read_bytes -
+ last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].read_bytes;
+ int64_t task_fg_wr_delta = task.io[FOREGROUND].write_bytes -
+ last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].write_bytes;
+ int64_t task_bg_wr_delta = task.io[BACKGROUND].write_bytes -
+ last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].write_bytes;
+
+ io_usage& task_usage = usage.task_ios[comm];
+ task_usage.bytes[READ][FOREGROUND][charger_stat] +=
+ (task_fg_rd_delta < 0) ? 0 : task_fg_rd_delta;
+ task_usage.bytes[READ][BACKGROUND][charger_stat] +=
+ (task_bg_rd_delta < 0) ? 0 : task_bg_rd_delta;
+ task_usage.bytes[WRITE][FOREGROUND][charger_stat] +=
+ (task_fg_wr_delta < 0) ? 0 : task_fg_wr_delta;
+ task_usage.bytes[WRITE][BACKGROUND][charger_stat] +=
+ (task_bg_wr_delta < 0) ? 0 : task_bg_wr_delta;
+ }
}
last_uid_io_stats = uid_io_stats;
}
-void uid_monitor::report()
+void uid_monitor::report(unordered_map<int, StoragedProto>* protos)
{
- std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+ if (!enabled()) return;
+
+ Mutex::Autolock _l(uidm_mutex);
update_curr_io_stats_locked();
add_records_locked(time(NULL));
+
+ if (protos) {
+ update_uid_io_proto(protos);
+ }
+}
+
+namespace {
+
+void set_io_usage_proto(IOUsage* usage_proto, const io_usage& usage)
+{
+ usage_proto->set_rd_fg_chg_on(usage.bytes[READ][FOREGROUND][CHARGER_ON]);
+ usage_proto->set_rd_fg_chg_off(usage.bytes[READ][FOREGROUND][CHARGER_OFF]);
+ usage_proto->set_rd_bg_chg_on(usage.bytes[READ][BACKGROUND][CHARGER_ON]);
+ usage_proto->set_rd_bg_chg_off(usage.bytes[READ][BACKGROUND][CHARGER_OFF]);
+ usage_proto->set_wr_fg_chg_on(usage.bytes[WRITE][FOREGROUND][CHARGER_ON]);
+ usage_proto->set_wr_fg_chg_off(usage.bytes[WRITE][FOREGROUND][CHARGER_OFF]);
+ usage_proto->set_wr_bg_chg_on(usage.bytes[WRITE][BACKGROUND][CHARGER_ON]);
+ usage_proto->set_wr_bg_chg_off(usage.bytes[WRITE][BACKGROUND][CHARGER_OFF]);
+}
+
+void get_io_usage_proto(io_usage* usage, const IOUsage& io_proto)
+{
+ usage->bytes[READ][FOREGROUND][CHARGER_ON] = io_proto.rd_fg_chg_on();
+ usage->bytes[READ][FOREGROUND][CHARGER_OFF] = io_proto.rd_fg_chg_off();
+ usage->bytes[READ][BACKGROUND][CHARGER_ON] = io_proto.rd_bg_chg_on();
+ usage->bytes[READ][BACKGROUND][CHARGER_OFF] = io_proto.rd_bg_chg_off();
+ usage->bytes[WRITE][FOREGROUND][CHARGER_ON] = io_proto.wr_fg_chg_on();
+ usage->bytes[WRITE][FOREGROUND][CHARGER_OFF] = io_proto.wr_fg_chg_off();
+ usage->bytes[WRITE][BACKGROUND][CHARGER_ON] = io_proto.wr_bg_chg_on();
+ usage->bytes[WRITE][BACKGROUND][CHARGER_OFF] = io_proto.wr_bg_chg_off();
+}
+
+} // namespace
+
+void uid_monitor::update_uid_io_proto(unordered_map<int, StoragedProto>* protos)
+{
+ for (const auto& item : io_history) {
+ const uint64_t& end_ts = item.first;
+ const struct uid_records& recs = item.second;
+ unordered_map<userid_t, UidIOItem*> user_items;
+
+ for (const auto& entry : recs.entries) {
+ userid_t user_id = entry.ios.user_id;
+ UidIOItem* item_proto = user_items[user_id];
+ if (item_proto == nullptr) {
+ item_proto = (*protos)[user_id].mutable_uid_io_usage()
+ ->add_uid_io_items();
+ user_items[user_id] = item_proto;
+ }
+ item_proto->set_end_ts(end_ts);
+
+ UidIORecords* recs_proto = item_proto->mutable_records();
+ recs_proto->set_start_ts(recs.start_ts);
+
+ UidRecord* rec_proto = recs_proto->add_entries();
+ rec_proto->set_uid_name(entry.name);
+ rec_proto->set_user_id(user_id);
+
+ IOUsage* uid_io_proto = rec_proto->mutable_uid_io();
+ const io_usage& uio_ios = entry.ios.uid_ios;
+ set_io_usage_proto(uid_io_proto, uio_ios);
+
+ for (const auto& task_io : entry.ios.task_ios) {
+ const std::string& task_name = task_io.first;
+ const io_usage& task_ios = task_io.second;
+
+ TaskIOUsage* task_io_proto = rec_proto->add_task_io();
+ task_io_proto->set_task_name(task_name);
+ set_io_usage_proto(task_io_proto->mutable_ios(), task_ios);
+ }
+ }
+ }
+}
+
+void uid_monitor::clear_user_history(userid_t user_id)
+{
+ Mutex::Autolock _l(uidm_mutex);
+
+ for (auto& item : io_history) {
+ vector<uid_record>* entries = &item.second.entries;
+ entries->erase(
+ remove_if(entries->begin(), entries->end(),
+ [user_id](const uid_record& rec) {
+ return rec.ios.user_id == user_id;}),
+ entries->end());
+ }
+
+ for (auto it = io_history.begin(); it != io_history.end(); ) {
+ if (it->second.entries.empty()) {
+ it = io_history.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
+void uid_monitor::load_uid_io_proto(const UidIOUsage& uid_io_proto)
+{
+ if (!enabled()) return;
+
+ Mutex::Autolock _l(uidm_mutex);
+
+ for (const auto& item_proto : uid_io_proto.uid_io_items()) {
+ const UidIORecords& records_proto = item_proto.records();
+ struct uid_records* recs = &io_history[item_proto.end_ts()];
+
+ recs->start_ts = records_proto.start_ts();
+ for (const auto& rec_proto : records_proto.entries()) {
+ struct uid_record record;
+ record.name = rec_proto.uid_name();
+ record.ios.user_id = rec_proto.user_id();
+ get_io_usage_proto(&record.ios.uid_ios, rec_proto.uid_io());
+
+ for (const auto& task_io_proto : rec_proto.task_io()) {
+ get_io_usage_proto(
+ &record.ios.task_ios[task_io_proto.task_name()],
+ task_io_proto.ios());
+ }
+ recs->entries.push_back(record);
+ }
+ }
}
void uid_monitor::set_charger_state(charger_stat_t stat)
{
- std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+ Mutex::Autolock _l(uidm_mutex);
if (charger_stat == stat) {
return;
@@ -289,16 +510,11 @@
void uid_monitor::init(charger_stat_t stat)
{
charger_stat = stat;
+
start_ts = time(NULL);
last_uid_io_stats = get_uid_io_stats();
}
uid_monitor::uid_monitor()
-{
- sem_init(&um_lock, 0, 1);
-}
-
-uid_monitor::~uid_monitor()
-{
- sem_destroy(&um_lock);
+ : enable(!access(UID_IO_STATS_PATH, R_OK)) {
}
diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp
index 74b7436..4fd4bc9 100644
--- a/storaged/storaged_utils.cpp
+++ b/storaged/storaged_utils.cpp
@@ -18,6 +18,7 @@
#include <dirent.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <linux/time.h>
#include <stdint.h>
#include <stdio.h>
@@ -41,124 +42,7 @@
#include <storaged.h>
#include <storaged_utils.h>
-bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
- // Get time
- struct timespec ts;
- // Use monotonic to exclude suspend time so that we measure IO bytes/sec
- // when system is running.
- int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (ret < 0) {
- PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
- return false;
- }
-
- std::string buffer;
- if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
- PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed.";
- return false;
- }
-
- // Regular diskstats entries
- std::stringstream ss(buffer);
- for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
- ss >> *((uint64_t*)stats + i);
- }
- // Other entries
- stats->start_time = 0;
- stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC +
- ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC);
- stats->counter = 1;
- stats->io_avg = (double)stats->io_in_flight;
- return true;
-}
-
-struct disk_perf get_disk_perf(struct disk_stats* stats) {
- struct disk_perf perf;
- memset(&perf, 0, sizeof(struct disk_perf)); // initialize
-
- if (stats->io_ticks) {
- if (stats->read_ticks) {
- unsigned long long divisor = stats->read_ticks * stats->io_ticks;
- perf.read_perf = ((unsigned long long)SECTOR_SIZE *
- stats->read_sectors *
- stats->io_in_queue +
- (divisor >> 1)) /
- divisor;
- perf.read_ios = ((unsigned long long)SEC_TO_MSEC *
- stats->read_ios *
- stats->io_in_queue +
- (divisor >> 1)) /
- divisor;
- }
- if (stats->write_ticks) {
- unsigned long long divisor = stats->write_ticks * stats->io_ticks;
- perf.write_perf = ((unsigned long long)SECTOR_SIZE *
- stats->write_sectors *
- stats->io_in_queue +
- (divisor >> 1)) /
- divisor;
- perf.write_ios = ((unsigned long long)SEC_TO_MSEC *
- stats->write_ios *
- stats->io_in_queue +
- (divisor >> 1)) /
- divisor;
- }
- perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) /
- stats->io_ticks;
- }
- return perf;
-}
-
-struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr) {
- struct disk_stats inc;
- for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
- if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
- continue;
- }
-
- *((uint64_t*)&inc + i) =
- *((uint64_t*)curr + i) - *((uint64_t*)prev + i);
- }
- // io_in_flight is exception
- inc.io_in_flight = curr->io_in_flight;
-
- inc.start_time = prev->end_time;
- inc.end_time = curr->end_time;
- inc.io_avg = curr->io_avg;
- inc.counter = 1;
-
- return inc;
-}
-
-// Add src to dst
-void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) {
- if (dst->end_time != 0 && dst->end_time != src->start_time) {
- LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats"
- << " are added. dst end with " << dst->end_time
- << ", src start with " << src->start_time;
- }
-
- for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
- if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
- continue;
- }
-
- *((uint64_t*)dst + i) += *((uint64_t*)src + i);
- }
-
- dst->io_in_flight = src->io_in_flight;
- if (dst->counter + src->counter) {
- dst->io_avg = ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) /
- (dst->counter + src->counter);
- }
- dst->counter += src->counter;
- dst->end_time = src->end_time;
- if (dst->start_time == 0) {
- dst->start_time = src->start_time;
- }
-}
-
-static bool cmp_uid_info(struct uid_info l, struct uid_info r) {
+bool cmp_uid_info(const UidInfo& l, const UidInfo& r) {
// Compare background I/O first.
for (int i = UID_STATS - 1; i >= 0; i--) {
uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes;
@@ -177,56 +61,72 @@
return l.name < r.name;
}
-void sort_running_uids_info(std::vector<struct uid_info> &uids) {
+void sort_running_uids_info(std::vector<UidInfo> &uids) {
std::sort(uids.begin(), uids.end(), cmp_uid_info);
}
// Logging functions
-void log_console_running_uids_info(std::vector<struct uid_info> uids) {
+void log_console_running_uids_info(const std::vector<UidInfo>& uids, bool flag_dump_task) {
printf("name/uid fg_rchar fg_wchar fg_rbytes fg_wbytes "
"bg_rchar bg_wchar bg_rbytes bg_wbytes fg_fsync bg_fsync\n");
for (const auto& uid : uids) {
- printf("%s %ju %ju %ju %ju %ju %ju %ju %ju %ju %ju\n", uid.name.c_str(),
+ printf("%s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
+ " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ uid.name.c_str(),
uid.io[0].rchar, uid.io[0].wchar, uid.io[0].read_bytes, uid.io[0].write_bytes,
uid.io[1].rchar, uid.io[1].wchar, uid.io[1].read_bytes, uid.io[1].write_bytes,
uid.io[0].fsync, uid.io[1].fsync);
+ if (flag_dump_task) {
+ for (const auto& task_it : uid.tasks) {
+ const task_info& task = task_it.second;
+ printf("-> %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
+ " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ task.comm.c_str(),
+ task.io[0].rchar, task.io[0].wchar, task.io[0].read_bytes, task.io[0].write_bytes,
+ task.io[1].rchar, task.io[1].wchar, task.io[1].read_bytes, task.io[1].write_bytes,
+ task.io[0].fsync, task.io[1].fsync);
+ }
+ }
}
fflush(stdout);
}
-#if DEBUG
-void log_debug_disk_perf(struct disk_perf* perf, const char* type) {
- // skip if the input structure are all zeros
- if (perf == NULL) return;
- struct disk_perf zero_cmp;
- memset(&zero_cmp, 0, sizeof(zero_cmp));
- if (memcmp(&zero_cmp, perf, sizeof(struct disk_perf)) == 0) return;
+void log_console_perf_history(const vector<int>& perf_history) {
+ if (perf_history.size() < 3 ||
+ perf_history.size() != perf_history[0] +
+ perf_history[1] +
+ perf_history[2] + (size_t)3) {
+ return;
+ }
- LOG_TO(SYSTEM, INFO) << "perf(ios) " << type
- << " rd:" << perf->read_perf << "KB/s(" << perf->read_ios << "/s)"
- << " wr:" << perf->write_perf << "KB/s(" << perf->write_ios << "/s)"
- << " q:" << perf->queue;
-}
-#else
-void log_debug_disk_perf(struct disk_perf* /* perf */, const char* /* type */) {}
-#endif
+ printf("\nI/O perf history (KB/s) : most_recent <--------- least_recent \n");
-void log_event_disk_stats(struct disk_stats* stats, const char* type) {
- // skip if the input structure are all zeros
- if (stats == NULL) return;
- struct disk_stats zero_cmp;
- memset(&zero_cmp, 0, sizeof(zero_cmp));
- // skip event logging diskstats when it is zero increment (all first 11 entries are zero)
- if (memcmp(&zero_cmp, stats, sizeof(uint64_t) * DISK_STATS_SIZE) == 0) return;
+ std::stringstream line;
+ int start = 3;
+ int end = 3 + perf_history[0];
+ std::copy(perf_history.begin() + start, perf_history.begin() + end,
+ std::ostream_iterator<int>(line, " "));
+ printf("last 24 hours : %s\n", line.str().c_str());
- android_log_event_list(EVENTLOGTAG_DISKSTATS)
- << type << stats->start_time << stats->end_time
- << stats->read_ios << stats->read_merges
- << stats->read_sectors << stats->read_ticks
- << stats->write_ios << stats->write_merges
- << stats->write_sectors << stats->write_ticks
- << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue
- << LOG_ID_EVENTS;
+ line.str("");
+ start = end;
+ end += perf_history[1];
+ std::copy(perf_history.begin() + start, perf_history.begin() + end,
+ std::ostream_iterator<int>(line, " "));
+ printf("last 7 days : %s\n", line.str().c_str());
+
+ line.str("");
+ start = end;
+ std::copy(perf_history.begin() + start, perf_history.end(),
+ std::ostream_iterator<int>(line, " "));
+ printf("last 52 weeks : %s\n", line.str().c_str());
}
+map<string, io_usage> merge_io_usage(const vector<uid_record>& entries) {
+ map<string, io_usage> merged_entries;
+ for (const auto& record : entries) {
+ merged_entries[record.name] += record.ios.uid_ios;
+ }
+ return merged_entries;
+}
diff --git a/storaged/tests/Android.mk b/storaged/tests/Android.mk
deleted file mode 100644
index 26d04b1..0000000
--- a/storaged/tests/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-test_module_prefix := storaged-
-test_tags := tests
-
-# -----------------------------------------------------------------------------
-# Unit tests.
-# -----------------------------------------------------------------------------
-
-test_c_flags := \
- -fstack-protector-all \
- -g \
- -Wall -Wextra \
- -Werror \
- -fno-builtin \
-
-test_src_files := \
- storaged_test.cpp \
-
-# Build tests for the logger. Run with:
-# adb shell /data/nativetest/storaged-unit-tests/storaged-unit-tests
-include $(CLEAR_VARS)
-LOCAL_MODULE := $(test_module_prefix)unit-tests
-LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_STATIC_LIBRARIES := libstoraged
-LOCAL_SHARED_LIBRARIES := libbase libcutils liblog libpackagelistparser
-LOCAL_SRC_FILES := $(test_src_files)
-include $(BUILD_NATIVE_TEST)
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
index b103ac1..ec47b65 100644
--- a/storaged/tests/storaged_test.cpp
+++ b/storaged/tests/storaged_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <chrono>
#include <deque>
#include <fcntl.h>
#include <random>
@@ -24,13 +25,20 @@
#include <gtest/gtest.h>
+#include <healthhalutils/HealthHalUtils.h>
#include <storaged.h> // data structures
#include <storaged_utils.h> // functions to test
#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
-static void pause(uint32_t sec) {
+using namespace std;
+using namespace chrono;
+using namespace storaged_proto;
+
+namespace {
+
+void write_and_pause(uint32_t sec) {
const char* path = "/cache/test";
int fd = open(path, O_WRONLY | O_CREAT, 0600);
ASSERT_LT(-1, fd);
@@ -53,6 +61,8 @@
sleep(sec);
}
+} // namespace
+
// the return values of the tested functions should be the expected ones
const char* DISK_STATS_PATH;
TEST(storaged_test, retvals) {
@@ -77,13 +87,11 @@
EXPECT_FALSE(parse_disk_stats(wrong_path, &stats));
// reading a wrong path should not damage the output structure
- EXPECT_EQ(0, memcmp(&stats, &old_stats, sizeof(disk_stats)));
+ EXPECT_EQ(stats, old_stats);
}
TEST(storaged_test, disk_stats) {
- struct disk_stats stats;
- memset(&stats, 0, sizeof(struct disk_stats));
-
+ struct disk_stats stats = {};
ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &stats));
// every entry of stats (except io_in_flight) should all be greater than 0
@@ -93,11 +101,7 @@
}
// accumulation of the increments should be the same with the overall increment
- struct disk_stats base, tmp, curr, acc, inc[5];
- memset(&base, 0, sizeof(struct disk_stats));
- memset(&tmp, 0, sizeof(struct disk_stats));
- memset(&acc, 0, sizeof(struct disk_stats));
-
+ struct disk_stats base = {}, tmp = {}, curr, acc = {}, inc[5];
for (uint i = 0; i < 5; ++i) {
ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &curr));
if (i == 0) {
@@ -106,22 +110,18 @@
sleep(5);
continue;
}
- inc[i] = get_inc_disk_stats(&tmp, &curr);
+ get_inc_disk_stats(&tmp, &curr, &inc[i]);
add_disk_stats(&inc[i], &acc);
tmp = curr;
- pause(5);
+ write_and_pause(5);
}
- struct disk_stats overall_inc;
- memset(&overall_inc, 0, sizeof(disk_stats));
- overall_inc= get_inc_disk_stats(&base, &curr);
+ struct disk_stats overall_inc = {};
+ get_inc_disk_stats(&base, &curr, &overall_inc);
- for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
- if (i == 8) continue; // skip io_in_flight which can be 0
- EXPECT_EQ(*((uint64_t*)&overall_inc + i), *((uint64_t*)&acc + i));
- }
+ EXPECT_EQ(overall_inc, acc);
}
-static double mean(std::deque<uint32_t> nums) {
+double mean(std::deque<uint32_t> nums) {
double sum = 0.0;
for (uint32_t i : nums) {
sum += i;
@@ -129,7 +129,7 @@
return sum / nums.size();
}
-static double standard_deviation(std::deque<uint32_t> nums) {
+double standard_deviation(std::deque<uint32_t> nums) {
double sum = 0.0;
double avg = mean(nums);
for (uint32_t i : nums) {
@@ -181,7 +181,7 @@
}
}
-static struct disk_perf disk_perf_multiply(struct disk_perf perf, double mul) {
+struct disk_perf disk_perf_multiply(struct disk_perf perf, double mul) {
struct disk_perf retval;
retval.read_perf = (double)perf.read_perf * mul;
retval.read_ios = (double)perf.read_ios * mul;
@@ -192,7 +192,7 @@
return retval;
}
-static struct disk_stats disk_stats_add(struct disk_stats stats1, struct disk_stats stats2) {
+struct disk_stats disk_stats_add(struct disk_stats stats1, struct disk_stats stats2) {
struct disk_stats retval;
retval.read_ios = stats1.read_ios + stats2.read_ios;
retval.read_merges = stats1.read_merges + stats2.read_merges;
@@ -210,11 +210,42 @@
return retval;
}
+void expect_increasing(struct disk_stats stats1, struct disk_stats stats2) {
+ EXPECT_LE(stats1.read_ios, stats2.read_ios);
+ EXPECT_LE(stats1.read_merges, stats2.read_merges);
+ EXPECT_LE(stats1.read_sectors, stats2.read_sectors);
+ EXPECT_LE(stats1.read_ticks, stats2.read_ticks);
+ EXPECT_LE(stats1.write_ios, stats2.write_ios);
+ EXPECT_LE(stats1.write_merges, stats2.write_merges);
+ EXPECT_LE(stats1.write_sectors, stats2.write_sectors);
+ EXPECT_LE(stats1.write_ticks, stats2.write_ticks);
+ EXPECT_LE(stats1.io_ticks, stats2.io_ticks);
+ EXPECT_LE(stats1.io_in_queue, stats2.io_in_queue);
+
+ EXPECT_TRUE(stats1.read_ios < stats2.read_ios ||
+ stats1.read_merges < stats2.read_merges ||
+ stats1.read_sectors < stats2.read_sectors ||
+ stats1.read_ticks < stats2.read_ticks ||
+ stats1.write_ios < stats2.write_ios ||
+ stats1.write_merges < stats2.write_merges ||
+ stats1.write_sectors < stats2.write_sectors ||
+ stats1.write_ticks < stats2.write_ticks ||
+ stats1.io_ticks < stats2.io_ticks ||
+ stats1.io_in_queue < stats2.io_in_queue);
+}
+
TEST(storaged_test, disk_stats_monitor) {
+ using android::hardware::health::V2_0::get_health_service;
+
+ auto healthService = get_health_service();
+
// asserting that there is one file for diskstats
- ASSERT_TRUE(access(MMC_DISK_STATS_PATH, R_OK) >= 0 || access(SDA_DISK_STATS_PATH, R_OK) >= 0);
+ ASSERT_TRUE(healthService != nullptr || access(MMC_DISK_STATS_PATH, R_OK) >= 0 ||
+ access(SDA_DISK_STATS_PATH, R_OK) >= 0);
+
// testing if detect() will return the right value
- disk_stats_monitor dsm_detect;
+ disk_stats_monitor dsm_detect{healthService};
+ ASSERT_TRUE(dsm_detect.enabled());
// feed monitor with constant perf data for io perf baseline
// using constant perf is reasonable since the functionality of stream_stats
// has already been tested
@@ -257,7 +288,7 @@
}
// testing if stalled disk_stats can be correctly accumulated in the monitor
- disk_stats_monitor dsm_acc;
+ disk_stats_monitor dsm_acc{healthService};
struct disk_stats norm_inc = {
.read_ios = 200,
.read_merges = 0,
@@ -294,14 +325,12 @@
.io_avg = 0
};
- struct disk_stats stats_base;
- memset(&stats_base, 0, sizeof(stats_base));
-
+ struct disk_stats stats_base = {};
int loop_size = 100;
for (int i = 0; i < loop_size; ++i) {
stats_base = disk_stats_add(stats_base, norm_inc);
dsm_acc.update(&stats_base);
- EXPECT_EQ(dsm_acc.mValid, (uint32_t)(i + 1) >= dsm_acc.mWindow);
+ EXPECT_EQ(dsm_acc.mValid, (uint32_t)i >= dsm_acc.mWindow);
EXPECT_FALSE(dsm_acc.mStall);
}
@@ -316,36 +345,284 @@
EXPECT_TRUE(dsm_acc.mValid);
EXPECT_FALSE(dsm_acc.mStall);
}
-}
-static void expect_increasing(struct disk_stats stats1, struct disk_stats stats2) {
- EXPECT_LE(stats1.read_ios, stats2.read_ios);
- EXPECT_LE(stats1.read_merges, stats2.read_merges);
- EXPECT_LE(stats1.read_sectors, stats2.read_sectors);
- EXPECT_LE(stats1.read_ticks, stats2.read_ticks);
-
- EXPECT_LE(stats1.write_ios, stats2.write_ios);
- EXPECT_LE(stats1.write_merges, stats2.write_merges);
- EXPECT_LE(stats1.write_sectors, stats2.write_sectors);
- EXPECT_LE(stats1.write_ticks, stats2.write_ticks);
-
- EXPECT_LE(stats1.io_ticks, stats2.io_ticks);
- EXPECT_LE(stats1.io_in_queue, stats2.io_in_queue);
-}
-
-#define TEST_LOOPS 20
-TEST(storaged_test, disk_stats_publisher) {
- // asserting that there is one file for diskstats
- ASSERT_TRUE(access(MMC_DISK_STATS_PATH, R_OK) >= 0 || access(SDA_DISK_STATS_PATH, R_OK) >= 0);
- disk_stats_publisher dsp;
- struct disk_stats prev;
- memset(&prev, 0, sizeof(prev));
-
- for (int i = 0; i < TEST_LOOPS; ++i) {
- dsp.update();
- expect_increasing(prev, dsp.mPrevious);
- prev = dsp.mPrevious;
- pause(10);
+ struct disk_stats stats_prev = {};
+ loop_size = 10;
+ write_and_pause(5);
+ for (int i = 0; i < loop_size; ++i) {
+ dsm_detect.update();
+ expect_increasing(stats_prev, dsm_detect.mPrevious);
+ stats_prev = dsm_detect.mPrevious;
+ write_and_pause(5);
}
}
+TEST(storaged_test, storage_info_t) {
+ storage_info_t si;
+ time_point<steady_clock> tp;
+ time_point<system_clock> stp;
+
+ // generate perf history [least_recent ------> most recent]
+ // day 1: 5, 10, 15, 20 | daily average 12
+ // day 2: 25, 30, 35, 40, 45 | daily average 35
+ // day 3: 50, 55, 60, 65, 70 | daily average 60
+ // day 4: 75, 80, 85, 90, 95 | daily average 85
+ // day 5: 100, 105, 110, 115, | daily average 107
+ // day 6: 120, 125, 130, 135, 140 | daily average 130
+ // day 7: 145, 150, 155, 160, 165 | daily average 155
+ // end of week 1: | weekly average 83
+ // day 1: 170, 175, 180, 185, 190 | daily average 180
+ // day 2: 195, 200, 205, 210, 215 | daily average 205
+ // day 3: 220, 225, 230, 235 | daily average 227
+ // day 4: 240, 245, 250, 255, 260 | daily average 250
+ // day 5: 265, 270, 275, 280, 285 | daily average 275
+ // day 6: 290, 295, 300, 305, 310 | daily average 300
+ // day 7: 315, 320, 325, 330, 335 | daily average 325
+ // end of week 2: | weekly average 251
+ // day 1: 340, 345, 350, 355 | daily average 347
+ // day 2: 360, 365, 370, 375
+ si.day_start_tp = {};
+ for (int i = 0; i < 75; i++) {
+ tp += hours(5);
+ stp = {};
+ stp += duration_cast<chrono::seconds>(tp.time_since_epoch());
+ si.update_perf_history((i + 1) * 5, stp);
+ }
+
+ vector<int> history = si.get_perf_history();
+ EXPECT_EQ(history.size(), 66UL);
+ size_t i = 0;
+ EXPECT_EQ(history[i++], 4);
+ EXPECT_EQ(history[i++], 7); // 7 days
+ EXPECT_EQ(history[i++], 52); // 52 weeks
+ // last 24 hours
+ EXPECT_EQ(history[i++], 375);
+ EXPECT_EQ(history[i++], 370);
+ EXPECT_EQ(history[i++], 365);
+ EXPECT_EQ(history[i++], 360);
+ // daily average of last 7 days
+ EXPECT_EQ(history[i++], 347);
+ EXPECT_EQ(history[i++], 325);
+ EXPECT_EQ(history[i++], 300);
+ EXPECT_EQ(history[i++], 275);
+ EXPECT_EQ(history[i++], 250);
+ EXPECT_EQ(history[i++], 227);
+ EXPECT_EQ(history[i++], 205);
+ // weekly average of last 52 weeks
+ EXPECT_EQ(history[i++], 251);
+ EXPECT_EQ(history[i++], 83);
+ for (; i < history.size(); i++) {
+ EXPECT_EQ(history[i], 0);
+ }
+}
+
+TEST(storaged_test, storage_info_t_proto) {
+ storage_info_t si;
+ si.day_start_tp = {};
+
+ IOPerfHistory proto;
+ proto.set_nr_samples(10);
+ proto.set_day_start_sec(0);
+ si.load_perf_history_proto(proto);
+
+ // Skip ahead > 1 day, with no data points in the previous day.
+ time_point<system_clock> stp;
+ stp += hours(36);
+ si.update_perf_history(100, stp);
+
+ vector<int> history = si.get_perf_history();
+ EXPECT_EQ(history.size(), 63UL);
+ EXPECT_EQ(history[0], 1);
+ EXPECT_EQ(history[1], 7);
+ EXPECT_EQ(history[2], 52);
+ EXPECT_EQ(history[3], 100);
+ for (size_t i = 4; i < history.size(); i++) {
+ EXPECT_EQ(history[i], 0);
+ }
+}
+
+TEST(storaged_test, uid_monitor) {
+ uid_monitor uidm;
+
+ uidm.io_history[200] = {
+ .start_ts = 100,
+ .entries = {
+ { "app1", {
+ .user_id = 0,
+ .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON] = 1000,
+ }
+ },
+ { "app2", {
+ .user_id = 0,
+ .uid_ios.bytes[READ][FOREGROUND][CHARGER_OFF] = 1000,
+ }
+ },
+ { "app1", {
+ .user_id = 1,
+ .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON] = 1000,
+ .uid_ios.bytes[READ][FOREGROUND][CHARGER_ON] = 1000,
+ }
+ },
+ },
+ };
+
+ uidm.io_history[300] = {
+ .start_ts = 200,
+ .entries = {
+ { "app1", {
+ .user_id = 1,
+ .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_OFF] = 1000,
+ }
+ },
+ { "app3", {
+ .user_id = 0,
+ .uid_ios.bytes[READ][BACKGROUND][CHARGER_OFF] = 1000,
+ }
+ },
+ },
+ };
+
+ unordered_map<int, StoragedProto> protos;
+
+ uidm.update_uid_io_proto(&protos);
+
+ EXPECT_EQ(protos.size(), 2U);
+ EXPECT_EQ(protos.count(0), 1UL);
+ EXPECT_EQ(protos.count(1), 1UL);
+
+ EXPECT_EQ(protos[0].uid_io_usage().uid_io_items_size(), 2);
+ const UidIOItem& user_0_item_0 = protos[0].uid_io_usage().uid_io_items(0);
+ EXPECT_EQ(user_0_item_0.end_ts(), 200UL);
+ EXPECT_EQ(user_0_item_0.records().start_ts(), 100UL);
+ EXPECT_EQ(user_0_item_0.records().entries_size(), 2);
+ EXPECT_EQ(user_0_item_0.records().entries(0).uid_name(), "app1");
+ EXPECT_EQ(user_0_item_0.records().entries(0).user_id(), 0UL);
+ EXPECT_EQ(user_0_item_0.records().entries(0).uid_io().wr_fg_chg_on(), 1000UL);
+ EXPECT_EQ(user_0_item_0.records().entries(1).uid_name(), "app2");
+ EXPECT_EQ(user_0_item_0.records().entries(1).user_id(), 0UL);
+ EXPECT_EQ(user_0_item_0.records().entries(1).uid_io().rd_fg_chg_off(), 1000UL);
+ const UidIOItem& user_0_item_1 = protos[0].uid_io_usage().uid_io_items(1);
+ EXPECT_EQ(user_0_item_1.end_ts(), 300UL);
+ EXPECT_EQ(user_0_item_1.records().start_ts(), 200UL);
+ EXPECT_EQ(user_0_item_1.records().entries_size(), 1);
+ EXPECT_EQ(user_0_item_1.records().entries(0).uid_name(), "app3");
+ EXPECT_EQ(user_0_item_1.records().entries(0).user_id(), 0UL);
+ EXPECT_EQ(user_0_item_1.records().entries(0).uid_io().rd_bg_chg_off(), 1000UL);
+
+ EXPECT_EQ(protos[1].uid_io_usage().uid_io_items_size(), 2);
+ const UidIOItem& user_1_item_0 = protos[1].uid_io_usage().uid_io_items(0);
+ EXPECT_EQ(user_1_item_0.end_ts(), 200UL);
+ EXPECT_EQ(user_1_item_0.records().start_ts(), 100UL);
+ EXPECT_EQ(user_1_item_0.records().entries_size(), 1);
+ EXPECT_EQ(user_1_item_0.records().entries(0).uid_name(), "app1");
+ EXPECT_EQ(user_1_item_0.records().entries(0).user_id(), 1UL);
+ EXPECT_EQ(user_1_item_0.records().entries(0).uid_io().rd_fg_chg_on(), 1000UL);
+ EXPECT_EQ(user_1_item_0.records().entries(0).uid_io().wr_fg_chg_on(), 1000UL);
+ const UidIOItem& user_1_item_1 = protos[1].uid_io_usage().uid_io_items(1);
+ EXPECT_EQ(user_1_item_1.end_ts(), 300UL);
+ EXPECT_EQ(user_1_item_1.records().start_ts(), 200UL);
+ EXPECT_EQ(user_1_item_1.records().entries_size(), 1);
+ EXPECT_EQ(user_1_item_1.records().entries(0).uid_name(), "app1");
+ EXPECT_EQ(user_1_item_1.records().entries(0).user_id(), 1UL);
+ EXPECT_EQ(user_1_item_1.records().entries(0).uid_io().wr_fg_chg_off(), 1000UL);
+
+ uidm.io_history.clear();
+
+ uidm.io_history[300] = {
+ .start_ts = 200,
+ .entries = {
+ { "app1", {
+ .user_id = 0,
+ .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON] = 1000,
+ }
+ },
+ },
+ };
+
+ uidm.io_history[400] = {
+ .start_ts = 300,
+ .entries = {
+ { "app1", {
+ .user_id = 0,
+ .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON] = 1000,
+ }
+ },
+ },
+ };
+
+ uidm.load_uid_io_proto(protos[0].uid_io_usage());
+ uidm.load_uid_io_proto(protos[1].uid_io_usage());
+
+ EXPECT_EQ(uidm.io_history.size(), 3UL);
+ EXPECT_EQ(uidm.io_history.count(200), 1UL);
+ EXPECT_EQ(uidm.io_history.count(300), 1UL);
+ EXPECT_EQ(uidm.io_history.count(400), 1UL);
+
+ EXPECT_EQ(uidm.io_history[200].start_ts, 100UL);
+ const vector<struct uid_record>& entries_0 = uidm.io_history[200].entries;
+ EXPECT_EQ(entries_0.size(), 3UL);
+ EXPECT_EQ(entries_0[0].name, "app1");
+ EXPECT_EQ(entries_0[0].ios.user_id, 0UL);
+ EXPECT_EQ(entries_0[0].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL);
+ EXPECT_EQ(entries_0[1].name, "app2");
+ EXPECT_EQ(entries_0[1].ios.user_id, 0UL);
+ EXPECT_EQ(entries_0[1].ios.uid_ios.bytes[READ][FOREGROUND][CHARGER_OFF], 1000UL);
+ EXPECT_EQ(entries_0[2].name, "app1");
+ EXPECT_EQ(entries_0[2].ios.user_id, 1UL);
+ EXPECT_EQ(entries_0[2].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL);
+ EXPECT_EQ(entries_0[2].ios.uid_ios.bytes[READ][FOREGROUND][CHARGER_ON], 1000UL);
+
+ EXPECT_EQ(uidm.io_history[300].start_ts, 200UL);
+ const vector<struct uid_record>& entries_1 = uidm.io_history[300].entries;
+ EXPECT_EQ(entries_1.size(), 3UL);
+ EXPECT_EQ(entries_1[0].name, "app1");
+ EXPECT_EQ(entries_1[0].ios.user_id, 0UL);
+ EXPECT_EQ(entries_1[0].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL);
+ EXPECT_EQ(entries_1[1].name, "app3");
+ EXPECT_EQ(entries_1[1].ios.user_id, 0UL);
+ EXPECT_EQ(entries_1[1].ios.uid_ios.bytes[READ][BACKGROUND][CHARGER_OFF], 1000UL);
+ EXPECT_EQ(entries_1[2].name, "app1");
+ EXPECT_EQ(entries_1[2].ios.user_id, 1UL);
+ EXPECT_EQ(entries_1[2].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_OFF], 1000UL);
+
+ EXPECT_EQ(uidm.io_history[400].start_ts, 300UL);
+ const vector<struct uid_record>& entries_2 = uidm.io_history[400].entries;
+ EXPECT_EQ(entries_2.size(), 1UL);
+ EXPECT_EQ(entries_2[0].name, "app1");
+ EXPECT_EQ(entries_2[0].ios.user_id, 0UL);
+ EXPECT_EQ(entries_2[0].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL);
+
+ map<string, io_usage> merged_entries_0 = merge_io_usage(entries_0);
+ EXPECT_EQ(merged_entries_0.size(), 2UL);
+ EXPECT_EQ(merged_entries_0.count("app1"), 1UL);
+ EXPECT_EQ(merged_entries_0.count("app2"), 1UL);
+ EXPECT_EQ(merged_entries_0["app1"].bytes[READ][FOREGROUND][CHARGER_ON], 1000UL);
+ EXPECT_EQ(merged_entries_0["app1"].bytes[WRITE][FOREGROUND][CHARGER_ON], 2000UL);
+ EXPECT_EQ(merged_entries_0["app2"].bytes[READ][FOREGROUND][CHARGER_OFF], 1000UL);
+
+ map<string, io_usage> merged_entries_1 = merge_io_usage(entries_1);
+ EXPECT_EQ(merged_entries_1.size(), 2UL);
+ EXPECT_EQ(merged_entries_1.count("app1"), 1UL);
+ EXPECT_EQ(merged_entries_1.count("app3"), 1UL);
+ EXPECT_EQ(merged_entries_1["app1"].bytes[WRITE][FOREGROUND][CHARGER_OFF], 1000UL);
+ EXPECT_EQ(merged_entries_1["app1"].bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL);
+ EXPECT_EQ(merged_entries_1["app3"].bytes[READ][BACKGROUND][CHARGER_OFF], 1000UL);
+
+ map<string, io_usage> merged_entries_2 = merge_io_usage(entries_2);
+ EXPECT_EQ(merged_entries_2.size(), 1UL);
+ EXPECT_EQ(merged_entries_2.count("app1"), 1UL);
+ EXPECT_EQ(merged_entries_2["app1"].bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL);
+
+ uidm.clear_user_history(0);
+
+ EXPECT_EQ(uidm.io_history.size(), 2UL);
+ EXPECT_EQ(uidm.io_history.count(200), 1UL);
+ EXPECT_EQ(uidm.io_history.count(300), 1UL);
+
+ EXPECT_EQ(uidm.io_history[200].entries.size(), 1UL);
+ EXPECT_EQ(uidm.io_history[300].entries.size(), 1UL);
+
+ uidm.clear_user_history(1);
+
+ EXPECT_EQ(uidm.io_history.size(), 0UL);
+}
diff --git a/storaged/tools/ranker.py b/storaged/tools/ranker.py
new file mode 100644
index 0000000..d8096b7
--- /dev/null
+++ b/storaged/tools/ranker.py
@@ -0,0 +1,181 @@
+# Copyright 2017 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.
+
+"""Parser and ranker for dumpsys storaged output.
+
+This module parses output from dumpsys storaged by ranking uids based on
+their io usage measured in 8 different stats. It must be provided the input
+file through command line argument -i/--input.
+
+For more details, see:
+ $ python ranker.py -h
+
+Example:
+ $ python ranker.py -i io.txt -o output.txt -u 20 -cnt
+"""
+
+import argparse
+import sys
+
+IO_NAMES = ["[READ][FOREGROUND][CHARGER_OFF]",
+ "[WRITE][FOREGROUND][CHARGER_OFF]",
+ "[READ][BACKGROUND][CHARGER_OFF]",
+ "[WRITE][BACKGROUND][CHARGER_OFF]",
+ "[READ][FOREGROUND][CHARGER_ON]",
+ "[WRITE][FOREGROUND][CHARGER_ON]",
+ "[READ][BACKGROUND][CHARGER_ON]",
+ "[WRITE][BACKGROUND][CHARGER_ON]"]
+
+
+def get_args():
+ """Get arguments from command line.
+
+ The only required argument is input file.
+
+ Returns:
+ Args containing cmdline arguments
+ """
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-i", "--input", dest="input", required="true",
+ help="input io FILE, must provide", metavar="FILE")
+ parser.add_argument("-o", "--output", dest="output", default="stdout",
+ help="output FILE, default to stdout", metavar="FILE")
+ parser.add_argument("-u", "--uidcnt", dest="uidcnt", type=int, default=10,
+ help="set number of uids to display for each rank, "
+ "default 10")
+ parser.add_argument("-c", "--combine", dest="combine", default=False,
+ action="store_true", help="add io stats for same uids, "
+ "default to take io stats of last appearing uids")
+ parser.add_argument("-n", "--native", dest="native", default=False,
+ action="store_true", help="only include native apps in "
+ "ranking, default to include all apps")
+ parser.add_argument("-t", "--task", dest="task", default=False,
+ action="store_true", help="display task io under uids, "
+ "default to not display tasks")
+ return parser.parse_args()
+
+
+def is_number(word):
+ try:
+ int(word)
+ return True
+ except ValueError:
+ return False
+
+
+def combine_or_filter(args):
+ """Parser for io input.
+
+ Either args.combine io stats for the same uids
+ or take the io stats for the last uid and ignore
+ the same uids before it.
+
+ If task is required, store task ios along with uid
+ for later display.
+
+ Returns:
+ The structure for the return value uids is as follows:
+ uids: {uid -> [UID_STATS, TASK_STATS(optional)]}
+ UID_STATS: [io1, io2, ..., io8]
+ TASK_STATS: {task_name -> [io1, io2, ..., io8]}
+ """
+ fin = open(args.input, "r")
+ uids = {}
+ cur_uid = 0
+ task_enabled = args.task
+ for line in fin:
+ words = line.split()
+ if words[0] == "->":
+ # task io
+ if not task_enabled:
+ continue
+ # get task command line
+ i = len(words) - 8
+ task = " ".join(words[1:i])
+ if task in uids[cur_uid][1]:
+ task_io = uids[cur_uid][1][task]
+ for j in range(8):
+ task_io[j] += long(words[i+j])
+ else:
+ task_io = []
+ for j in range(8):
+ task_io.append(long(words[i+j]))
+ uids[cur_uid][1][task] = task_io
+
+ elif len(words) > 8:
+ if not is_number(words[0]) and args.native:
+ # uid not requested, ignore its tasks as well
+ task_enabled = False
+ continue
+ task_enabled = args.task
+ i = len(words) - 8
+ uid = " ".join(words[:i])
+ if uid in uids and args.combine:
+ uid_io = uids[uid][0]
+ for j in range(8):
+ uid_io[j] += long(words[i+j])
+ uids[uid][0] = uid_io
+ else:
+ uid_io = [long(words[i+j]) for j in range(8)]
+ uids[uid] = [uid_io]
+ if task_enabled:
+ uids[uid].append({})
+ cur_uid = uid
+
+ return uids
+
+
+def rank_uids(uids):
+ """Sort uids based on eight different io stats.
+
+ Returns:
+ uid_rank is a 2d list of tuples:
+ The first dimension represent the 8 different io stats.
+ The second dimension is a sorted list of tuples by tup[0],
+ each tuple is a uid's perticular stat at the first dimension and the uid.
+ """
+ uid_rank = [[(uids[uid][0][i], uid) for uid in uids] for i in range(8)]
+ for i in range(8):
+ uid_rank[i].sort(key=lambda tup: tup[0], reverse=True)
+ return uid_rank
+
+
+def display_uids(uid_rank, uids, args):
+ """Display ranked uid io, along with task io if specified."""
+ fout = sys.stdout
+ if args.output != "stdout":
+ fout = open(args.output, "w")
+
+ for i in range(8):
+ fout.write("RANKING BY " + IO_NAMES[i] + "\n")
+ for j in range(min(args.uidcnt, len(uid_rank[0]))):
+ uid = uid_rank[i][j][1]
+ uid_stat = " ".join([str(uid_io) for uid_io in uids[uid][0]])
+ fout.write(uid + " " + uid_stat + "\n")
+ if args.task:
+ for task in uids[uid][1]:
+ task_stat = " ".join([str(task_io) for task_io in uids[uid][1][task]])
+ fout.write("-> " + task + " " + task_stat + "\n")
+ fout.write("\n")
+
+
+def main():
+ args = get_args()
+ uids = combine_or_filter(args)
+ uid_rank = rank_uids(uids)
+ display_uids(uid_rank, uids, args)
+
+if __name__ == "__main__":
+ main()
diff --git a/storaged/uid_info.cpp b/storaged/uid_info.cpp
new file mode 100644
index 0000000..58e3fd2
--- /dev/null
+++ b/storaged/uid_info.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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 <binder/Parcel.h>
+
+#include "uid_info.h"
+
+using namespace android;
+using namespace android::os::storaged;
+
+status_t UidInfo::writeToParcel(Parcel* parcel) const {
+ parcel->writeInt32(uid);
+ parcel->writeCString(name.c_str());
+ parcel->write(&io, sizeof(io));
+
+ parcel->writeInt32(tasks.size());
+ for (const auto& task_it : tasks) {
+ parcel->writeInt32(task_it.first);
+ parcel->writeCString(task_it.second.comm.c_str());
+ parcel->write(&task_it.second.io, sizeof(task_it.second.io));
+ }
+ return NO_ERROR;
+}
+
+status_t UidInfo::readFromParcel(const Parcel* parcel) {
+ uid = parcel->readInt32();
+ name = parcel->readCString();
+ parcel->read(&io, sizeof(io));
+
+ uint32_t tasks_size = parcel->readInt32();
+ for (uint32_t i = 0; i < tasks_size; i++) {
+ task_info task;
+ task.pid = parcel->readInt32();
+ task.comm = parcel->readCString();
+ parcel->read(&task.io, sizeof(task.io));
+ tasks[task.pid] = task;
+ }
+ return NO_ERROR;
+}
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index e75e4af..f08cf93 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -62,8 +62,8 @@
}
// We build BSD grep separately (but see http://b/111849261).
-cc_binary {
- name: "grep",
+cc_defaults {
+ name: "grep_common",
defaults: ["toolbox_defaults"],
srcs: [
"upstream-netbsd/usr.bin/grep/fastgrep.c",
@@ -72,8 +72,27 @@
"upstream-netbsd/usr.bin/grep/queue.c",
"upstream-netbsd/usr.bin/grep/util.c",
],
-
+ symlinks: [
+ "egrep",
+ "fgrep",
+ ],
sanitize: {
integer_overflow: false,
},
}
+
+cc_binary {
+ name: "grep",
+ defaults: ["grep_common"],
+ recovery_available: true,
+}
+
+// Build vendor grep.
+// TODO: Add vendor_available to "grep" module and remove "grep_vendor" module
+// when vendor_available is fully supported.
+cc_binary {
+ name: "grep_vendor",
+ stem: "grep",
+ vendor: true,
+ defaults: ["grep_common"],
+}
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 5428e73..52a879e 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -27,19 +27,21 @@
name: "trusty_keymaster_tipc",
vendor: true,
srcs: [
- "trusty_keymaster_device.cpp",
- "trusty_keymaster_ipc.cpp",
- "trusty_keymaster_main.cpp",
+ "ipc/trusty_keymaster_ipc.cpp",
+ "legacy/trusty_keymaster_device.cpp",
+ "legacy/trusty_keymaster_main.cpp",
],
cflags: [
"-Wall",
"-Werror",
],
+
+ local_include_dirs: ["include"],
+
shared_libs: [
"libcrypto",
"libcutils",
"libkeymaster_portable",
- "libkeymaster_staging",
"libtrusty",
"libkeymaster_messages",
"libsoftkeymasterdevice",
@@ -53,9 +55,9 @@
vendor: true,
relative_install_path: "hw",
srcs: [
- "module.cpp",
- "trusty_keymaster_ipc.cpp",
- "trusty_keymaster_device.cpp",
+ "ipc/trusty_keymaster_ipc.cpp",
+ "legacy/module.cpp",
+ "legacy/trusty_keymaster_device.cpp",
],
cflags: [
@@ -64,6 +66,8 @@
"-Werror",
],
+ local_include_dirs: ["include"],
+
shared_libs: [
"libcrypto",
"libkeymaster_messages",
diff --git a/trusty/keymaster/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
similarity index 100%
rename from trusty/keymaster/keymaster_ipc.h
rename to trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
diff --git a/trusty/keymaster/trusty_keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h
similarity index 66%
rename from trusty/keymaster/trusty_keymaster_ipc.h
rename to trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h
index c15f7c1..16207e6 100644
--- a/trusty/keymaster/trusty_keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h
@@ -17,13 +17,24 @@
#ifndef TRUSTY_KEYMASTER_TRUSTY_KEYMASTER_IPC_H_
#define TRUSTY_KEYMASTER_TRUSTY_KEYMASTER_IPC_H_
+#include <keymaster/android_keymaster_messages.h>
+#include <trusty_keymaster/ipc/keymaster_ipc.h>
+
__BEGIN_DECLS
+const uint32_t TRUSTY_KEYMASTER_RECV_BUF_SIZE = 2 * PAGE_SIZE;
+const uint32_t TRUSTY_KEYMASTER_SEND_BUF_SIZE =
+ (PAGE_SIZE - sizeof(struct keymaster_message) - 16 /* tipc header */);
+
int trusty_keymaster_connect(void);
int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
uint32_t* out_size);
void trusty_keymaster_disconnect(void);
+keymaster_error_t translate_error(int err);
+keymaster_error_t trusty_keymaster_send(uint32_t command, const keymaster::Serializable& req,
+ keymaster::KeymasterResponse* rsp);
+
__END_DECLS
#endif // TRUSTY_KEYMASTER_TRUSTY_KEYMASTER_IPC_H_
diff --git a/trusty/keymaster/trusty_keymaster_device.h b/trusty/keymaster/include/trusty_keymaster/legacy/trusty_keymaster_device.h
similarity index 96%
rename from trusty/keymaster/trusty_keymaster_device.h
rename to trusty/keymaster/include/trusty_keymaster/legacy/trusty_keymaster_device.h
index cfada1b..5a80795 100644
--- a/trusty/keymaster/trusty_keymaster_device.h
+++ b/trusty/keymaster/include/trusty_keymaster/legacy/trusty_keymaster_device.h
@@ -36,7 +36,8 @@
* These are the only symbols that will be exported by libtrustykeymaster. All functionality
* can be reached via the function pointers in device_.
*/
- __attribute__((visibility("default"))) explicit TrustyKeymasterDevice(const hw_module_t* module);
+ __attribute__((visibility("default"))) explicit TrustyKeymasterDevice(
+ const hw_module_t* module);
__attribute__((visibility("default"))) hw_device_t* hw_device();
~TrustyKeymasterDevice();
@@ -134,12 +135,15 @@
keymaster_operation_handle_t operation_handle,
const keymaster_key_param_set_t* in_params,
const keymaster_blob_t* input, size_t* input_consumed,
- keymaster_key_param_set_t* out_params, keymaster_blob_t* output);
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output);
static keymaster_error_t finish(const keymaster2_device_t* dev,
keymaster_operation_handle_t operation_handle,
const keymaster_key_param_set_t* in_params,
- const keymaster_blob_t* input, const keymaster_blob_t* signature,
- keymaster_key_param_set_t* out_params, keymaster_blob_t* output);
+ const keymaster_blob_t* input,
+ const keymaster_blob_t* signature,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output);
static keymaster_error_t abort(const keymaster2_device_t* dev,
keymaster_operation_handle_t operation_handle);
diff --git a/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp b/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
new file mode 100644
index 0000000..8c5cff6
--- /dev/null
+++ b/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TrustyKeymaster"
+
+// TODO: make this generic in libtrusty
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include <log/log.h>
+#include <trusty/tipc.h>
+
+#include <trusty_keymaster/ipc/keymaster_ipc.h>
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+static int handle_ = -1;
+
+int trusty_keymaster_connect() {
+ int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
+ if (rc < 0) {
+ return rc;
+ }
+
+ handle_ = rc;
+ return 0;
+}
+
+int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
+ uint32_t* out_size) {
+ if (handle_ < 0) {
+ ALOGE("not connected\n");
+ return -EINVAL;
+ }
+
+ size_t msg_size = in_size + sizeof(struct keymaster_message);
+ struct keymaster_message* msg = reinterpret_cast<struct keymaster_message*>(malloc(msg_size));
+ if (!msg) {
+ ALOGE("failed to allocate msg buffer\n");
+ return -EINVAL;
+ }
+
+ msg->cmd = cmd;
+ memcpy(msg->payload, in, in_size);
+
+ ssize_t rc = write(handle_, msg, msg_size);
+ free(msg);
+
+ if (rc < 0) {
+ ALOGE("failed to send cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT, strerror(errno));
+ return -errno;
+ }
+ size_t out_max_size = *out_size;
+ *out_size = 0;
+ struct iovec iov[2];
+ struct keymaster_message header;
+ iov[0] = {.iov_base = &header, .iov_len = sizeof(struct keymaster_message)};
+ while (true) {
+ iov[1] = {.iov_base = out + *out_size,
+ .iov_len = std::min<uint32_t>(KEYMASTER_MAX_BUFFER_LENGTH,
+ out_max_size - *out_size)};
+ rc = readv(handle_, iov, 2);
+ if (rc < 0) {
+ ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT,
+ strerror(errno));
+ return -errno;
+ }
+
+ if ((size_t)rc < sizeof(struct keymaster_message)) {
+ ALOGE("invalid response size (%d)\n", (int)rc);
+ return -EINVAL;
+ }
+
+ if ((cmd | KEYMASTER_RESP_BIT) != (header.cmd & ~(KEYMASTER_STOP_BIT))) {
+ ALOGE("invalid command (%d)", header.cmd);
+ return -EINVAL;
+ }
+ *out_size += ((size_t)rc - sizeof(struct keymaster_message));
+ if (header.cmd & KEYMASTER_STOP_BIT) {
+ break;
+ }
+ }
+
+ return rc;
+}
+
+void trusty_keymaster_disconnect() {
+ if (handle_ >= 0) {
+ tipc_close(handle_);
+ }
+ handle_ = -1;
+}
+
+keymaster_error_t translate_error(int err) {
+ switch (err) {
+ case 0:
+ return KM_ERROR_OK;
+ case -EPERM:
+ case -EACCES:
+ return KM_ERROR_SECURE_HW_ACCESS_DENIED;
+
+ case -ECANCELED:
+ return KM_ERROR_OPERATION_CANCELLED;
+
+ case -ENODEV:
+ return KM_ERROR_UNIMPLEMENTED;
+
+ case -ENOMEM:
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ case -EBUSY:
+ return KM_ERROR_SECURE_HW_BUSY;
+
+ case -EIO:
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+
+ case -EOVERFLOW:
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+
+ default:
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+}
+
+keymaster_error_t trusty_keymaster_send(uint32_t command, const keymaster::Serializable& req,
+ keymaster::KeymasterResponse* rsp) {
+ uint32_t req_size = req.SerializedSize();
+ if (req_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
+ ALOGE("Request too big: %u Max size: %u", req_size, TRUSTY_KEYMASTER_SEND_BUF_SIZE);
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ }
+
+ uint8_t send_buf[TRUSTY_KEYMASTER_SEND_BUF_SIZE];
+ keymaster::Eraser send_buf_eraser(send_buf, TRUSTY_KEYMASTER_SEND_BUF_SIZE);
+ req.Serialize(send_buf, send_buf + req_size);
+
+ // Send it
+ uint8_t recv_buf[TRUSTY_KEYMASTER_RECV_BUF_SIZE];
+ keymaster::Eraser recv_buf_eraser(recv_buf, TRUSTY_KEYMASTER_RECV_BUF_SIZE);
+ uint32_t rsp_size = TRUSTY_KEYMASTER_RECV_BUF_SIZE;
+ int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
+ if (rc < 0) {
+ // Reset the connection on tipc error
+ trusty_keymaster_disconnect();
+ trusty_keymaster_connect();
+ ALOGE("tipc error: %d\n", rc);
+ // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
+ return translate_error(rc);
+ } else {
+ ALOGE("Received %d byte response\n", rsp_size);
+ }
+
+ const uint8_t* p = recv_buf;
+ if (!rsp->Deserialize(&p, p + rsp_size)) {
+ ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
+ return KM_ERROR_UNKNOWN_ERROR;
+ } else if (rsp->error != KM_ERROR_OK) {
+ ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
+ return rsp->error;
+ }
+ return rsp->error;
+}
diff --git a/trusty/keymaster/Makefile b/trusty/keymaster/legacy/Makefile
similarity index 100%
rename from trusty/keymaster/Makefile
rename to trusty/keymaster/legacy/Makefile
diff --git a/trusty/keymaster/module.cpp b/trusty/keymaster/legacy/module.cpp
similarity index 65%
rename from trusty/keymaster/module.cpp
rename to trusty/keymaster/legacy/module.cpp
index b472680..7aa1a4e 100644
--- a/trusty/keymaster/module.cpp
+++ b/trusty/keymaster/legacy/module.cpp
@@ -19,14 +19,15 @@
#include <hardware/hardware.h>
#include <hardware/keymaster0.h>
-#include "trusty_keymaster_device.h"
+#include <trusty_keymaster/legacy/trusty_keymaster_device.h>
using keymaster::TrustyKeymasterDevice;
/*
* Generic device handling
*/
-static int trusty_keymaster_open(const hw_module_t* module, const char* name, hw_device_t** device) {
+static int trusty_keymaster_open(const hw_module_t* module, const char* name,
+ hw_device_t** device) {
if (strcmp(name, KEYSTORE_KEYMASTER) != 0) {
return -EINVAL;
}
@@ -42,20 +43,20 @@
}
static struct hw_module_methods_t keystore_module_methods = {
- .open = trusty_keymaster_open,
+ .open = trusty_keymaster_open,
};
struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
- .common =
- {
- .tag = HARDWARE_MODULE_TAG,
- .module_api_version = KEYMASTER_MODULE_API_VERSION_2_0,
- .hal_api_version = HARDWARE_HAL_API_VERSION,
- .id = KEYSTORE_HARDWARE_MODULE_ID,
- .name = "Trusty Keymaster HAL",
- .author = "The Android Open Source Project",
- .methods = &keystore_module_methods,
- .dso = 0,
- .reserved = {},
- },
+ .common =
+ {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = KEYMASTER_MODULE_API_VERSION_2_0,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = KEYSTORE_HARDWARE_MODULE_ID,
+ .name = "Trusty Keymaster HAL",
+ .author = "The Android Open Source Project",
+ .methods = &keystore_module_methods,
+ .dso = 0,
+ .reserved = {},
+ },
};
diff --git a/trusty/keymaster/trusty_keymaster_device.cpp b/trusty/keymaster/legacy/trusty_keymaster_device.cpp
similarity index 79%
rename from trusty/keymaster/trusty_keymaster_device.cpp
rename to trusty/keymaster/legacy/trusty_keymaster_device.cpp
index b8c2032..ea00a92 100644
--- a/trusty/keymaster/trusty_keymaster_device.cpp
+++ b/trusty/keymaster/legacy/trusty_keymaster_device.cpp
@@ -33,50 +33,15 @@
#include <keymaster/authorization_set.h>
#include <log/log.h>
-#include "keymaster_ipc.h"
-#include "trusty_keymaster_device.h"
-#include "trusty_keymaster_ipc.h"
-
-// Maximum size of message from Trusty is 8K (for RSA attestation key and chain)
-const uint32_t RECV_BUF_SIZE = 2*PAGE_SIZE;
-const uint32_t SEND_BUF_SIZE = (PAGE_SIZE - sizeof(struct keymaster_message) - 16 /* tipc header */);
+#include <trusty_keymaster/ipc/keymaster_ipc.h>
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
+#include <trusty_keymaster/legacy/trusty_keymaster_device.h>
const size_t kMaximumAttestationChallengeLength = 128;
const size_t kMaximumFinishInputLength = 2048;
namespace keymaster {
-static keymaster_error_t translate_error(int err) {
- switch (err) {
- case 0:
- return KM_ERROR_OK;
- case -EPERM:
- case -EACCES:
- return KM_ERROR_SECURE_HW_ACCESS_DENIED;
-
- case -ECANCELED:
- return KM_ERROR_OPERATION_CANCELLED;
-
- case -ENODEV:
- return KM_ERROR_UNIMPLEMENTED;
-
- case -ENOMEM:
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- case -EBUSY:
- return KM_ERROR_SECURE_HW_BUSY;
-
- case -EIO:
- return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
-
- case -EOVERFLOW:
- return KM_ERROR_INVALID_INPUT_LENGTH;
-
- default:
- return KM_ERROR_UNKNOWN_ERROR;
- }
-}
-
TrustyKeymasterDevice::TrustyKeymasterDevice(const hw_module_t* module) {
static_assert(std::is_standard_layout<TrustyKeymasterDevice>::value,
"TrustyKeymasterDevice must be standard layout");
@@ -121,7 +86,7 @@
GetVersionRequest version_request;
GetVersionResponse version_response;
- error_ = Send(KM_GET_VERSION, version_request, &version_response);
+ error_ = trusty_keymaster_send(KM_GET_VERSION, version_request, &version_response);
if (error_ == KM_ERROR_INVALID_ARGUMENT || error_ == KM_ERROR_UNIMPLEMENTED) {
ALOGE("\"Bad parameters\" error on GetVersion call. Version 0 is not supported.");
error_ = KM_ERROR_VERSION_MISMATCH;
@@ -186,7 +151,7 @@
}
ConfigureResponse response(message_version_);
- keymaster_error_t err = Send(KM_CONFIGURE, request, &response);
+ keymaster_error_t err = trusty_keymaster_send(KM_CONFIGURE, request, &response);
if (err != KM_ERROR_OK) {
return err;
}
@@ -204,12 +169,12 @@
AddEntropyRequest request(message_version_);
request.random_data.Reinitialize(data, data_length);
AddEntropyResponse response(message_version_);
- return Send(KM_ADD_RNG_ENTROPY, request, &response);
+ return trusty_keymaster_send(KM_ADD_RNG_ENTROPY, request, &response);
}
keymaster_error_t TrustyKeymasterDevice::generate_key(
- const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob,
- keymaster_key_characteristics_t* characteristics) {
+ const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob,
+ keymaster_key_characteristics_t* characteristics) {
ALOGD("Device received generate_key");
if (error_ != KM_ERROR_OK) {
@@ -227,14 +192,14 @@
request.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
GenerateKeyResponse response(message_version_);
- keymaster_error_t err = Send(KM_GENERATE_KEY, request, &response);
+ keymaster_error_t err = trusty_keymaster_send(KM_GENERATE_KEY, request, &response);
if (err != KM_ERROR_OK) {
return err;
}
key_blob->key_material_size = response.key_blob.key_material_size;
key_blob->key_material =
- DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size);
+ DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size);
if (!key_blob->key_material) {
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
}
@@ -248,8 +213,8 @@
}
keymaster_error_t TrustyKeymasterDevice::get_key_characteristics(
- const keymaster_key_blob_t* key_blob, const keymaster_blob_t* client_id,
- const keymaster_blob_t* app_data, keymaster_key_characteristics_t* characteristics) {
+ const keymaster_key_blob_t* key_blob, const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data, keymaster_key_characteristics_t* characteristics) {
ALOGD("Device received get_key_characteristics");
if (error_ != KM_ERROR_OK) {
@@ -267,7 +232,7 @@
AddClientAndAppData(client_id, app_data, &request);
GetKeyCharacteristicsResponse response(message_version_);
- keymaster_error_t err = Send(KM_GET_KEY_CHARACTERISTICS, request, &response);
+ keymaster_error_t err = trusty_keymaster_send(KM_GET_KEY_CHARACTERISTICS, request, &response);
if (err != KM_ERROR_OK) {
return err;
}
@@ -279,9 +244,9 @@
}
keymaster_error_t TrustyKeymasterDevice::import_key(
- const keymaster_key_param_set_t* params, keymaster_key_format_t key_format,
- const keymaster_blob_t* key_data, keymaster_key_blob_t* key_blob,
- keymaster_key_characteristics_t* characteristics) {
+ const keymaster_key_param_set_t* params, keymaster_key_format_t key_format,
+ const keymaster_blob_t* key_data, keymaster_key_blob_t* key_blob,
+ keymaster_key_characteristics_t* characteristics) {
ALOGD("Device received import_key");
if (error_ != KM_ERROR_OK) {
@@ -302,14 +267,14 @@
request.SetKeyMaterial(key_data->data, key_data->data_length);
ImportKeyResponse response(message_version_);
- keymaster_error_t err = Send(KM_IMPORT_KEY, request, &response);
+ keymaster_error_t err = trusty_keymaster_send(KM_IMPORT_KEY, request, &response);
if (err != KM_ERROR_OK) {
return err;
}
key_blob->key_material_size = response.key_blob.key_material_size;
key_blob->key_material =
- DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size);
+ DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size);
if (!key_blob->key_material) {
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
}
@@ -348,7 +313,7 @@
AddClientAndAppData(client_id, app_data, &request);
ExportKeyResponse response(message_version_);
- keymaster_error_t err = Send(KM_EXPORT_KEY, request, &response);
+ keymaster_error_t err = trusty_keymaster_send(KM_EXPORT_KEY, request, &response);
if (err != KM_ERROR_OK) {
return err;
}
@@ -393,7 +358,7 @@
}
AttestKeyResponse response(message_version_);
- keymaster_error_t err = Send(KM_ATTEST_KEY, request, &response);
+ keymaster_error_t err = trusty_keymaster_send(KM_ATTEST_KEY, request, &response);
if (err != KM_ERROR_OK) {
return err;
}
@@ -401,7 +366,7 @@
// Allocate and clear storage for cert_chain.
keymaster_cert_chain_t& rsp_chain = response.certificate_chain;
cert_chain->entries = reinterpret_cast<keymaster_blob_t*>(
- malloc(rsp_chain.entry_count * sizeof(*cert_chain->entries)));
+ malloc(rsp_chain.entry_count * sizeof(*cert_chain->entries)));
if (!cert_chain->entries) {
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
}
@@ -425,9 +390,9 @@
return KM_ERROR_OK;
}
-keymaster_error_t TrustyKeymasterDevice::upgrade_key(const keymaster_key_blob_t* key_to_upgrade,
- const keymaster_key_param_set_t* upgrade_params,
- keymaster_key_blob_t* upgraded_key) {
+keymaster_error_t TrustyKeymasterDevice::upgrade_key(
+ const keymaster_key_blob_t* key_to_upgrade, const keymaster_key_param_set_t* upgrade_params,
+ keymaster_key_blob_t* upgraded_key) {
ALOGD("Device received upgrade_key");
if (error_ != KM_ERROR_OK) {
@@ -445,7 +410,7 @@
request.upgrade_params.Reinitialize(*upgrade_params);
UpgradeKeyResponse response(message_version_);
- keymaster_error_t err = Send(KM_UPGRADE_KEY, request, &response);
+ keymaster_error_t err = trusty_keymaster_send(KM_UPGRADE_KEY, request, &response);
if (err != KM_ERROR_OK) {
return err;
}
@@ -487,7 +452,7 @@
request.additional_params.Reinitialize(*in_params);
BeginOperationResponse response(message_version_);
- keymaster_error_t err = Send(KM_BEGIN_OPERATION, request, &response);
+ keymaster_error_t err = trusty_keymaster_send(KM_BEGIN_OPERATION, request, &response);
if (err != KM_ERROR_OK) {
return err;
}
@@ -535,12 +500,12 @@
request.additional_params.Reinitialize(*in_params);
}
if (input && input->data_length > 0) {
- size_t max_input_size = SEND_BUF_SIZE - request.SerializedSize();
+ size_t max_input_size = TRUSTY_KEYMASTER_SEND_BUF_SIZE - request.SerializedSize();
request.input.Reinitialize(input->data, std::min(input->data_length, max_input_size));
}
UpdateOperationResponse response(message_version_);
- keymaster_error_t err = Send(KM_UPDATE_OPERATION, request, &response);
+ keymaster_error_t err = trusty_keymaster_send(KM_UPDATE_OPERATION, request, &response);
if (err != KM_ERROR_OK) {
return err;
}
@@ -578,8 +543,8 @@
return error_;
}
if (input && input->data_length > kMaximumFinishInputLength) {
- ALOGE("%zu-byte input to finish; only %zu bytes allowed",
- input->data_length, kMaximumFinishInputLength);
+ ALOGE("%zu-byte input to finish; only %zu bytes allowed", input->data_length,
+ kMaximumFinishInputLength);
return KM_ERROR_INVALID_INPUT_LENGTH;
}
@@ -603,7 +568,7 @@
}
FinishOperationResponse response(message_version_);
- keymaster_error_t err = Send(KM_FINISH_OPERATION, request, &response);
+ keymaster_error_t err = trusty_keymaster_send(KM_FINISH_OPERATION, request, &response);
if (err != KM_ERROR_OK) {
return err;
}
@@ -638,7 +603,7 @@
AbortOperationRequest request(message_version_);
request.op_handle = operation_handle;
AbortOperationResponse response(message_version_);
- return Send(KM_ABORT_OPERATION, request, &response);
+ return trusty_keymaster_send(KM_ABORT_OPERATION, request, &response);
}
hw_device_t* TrustyKeymasterDevice::hw_device() {
@@ -669,25 +634,25 @@
/* static */
keymaster_error_t TrustyKeymasterDevice::generate_key(
- const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
- keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
+ const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
+ keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
return convert_device(dev)->generate_key(params, key_blob, characteristics);
}
/* static */
keymaster_error_t TrustyKeymasterDevice::get_key_characteristics(
- const keymaster2_device_t* dev, const keymaster_key_blob_t* key_blob,
- const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
- keymaster_key_characteristics_t* characteristics) {
+ const keymaster2_device_t* dev, const keymaster_key_blob_t* key_blob,
+ const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
+ keymaster_key_characteristics_t* characteristics) {
return convert_device(dev)->get_key_characteristics(key_blob, client_id, app_data,
characteristics);
}
/* static */
keymaster_error_t TrustyKeymasterDevice::import_key(
- const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
- keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
- keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
+ const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
+ keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
+ keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
return convert_device(dev)->import_key(params, key_format, key_data, key_blob, characteristics);
}
@@ -711,10 +676,9 @@
}
/* static */
-keymaster_error_t TrustyKeymasterDevice::upgrade_key(const keymaster2_device_t* dev,
- const keymaster_key_blob_t* key_to_upgrade,
- const keymaster_key_param_set_t* upgrade_params,
- keymaster_key_blob_t* upgraded_key) {
+keymaster_error_t TrustyKeymasterDevice::upgrade_key(
+ const keymaster2_device_t* dev, const keymaster_key_blob_t* key_to_upgrade,
+ const keymaster_key_param_set_t* upgrade_params, keymaster_key_blob_t* upgraded_key) {
return convert_device(dev)->upgrade_key(key_to_upgrade, upgrade_params, upgraded_key);
}
@@ -730,9 +694,9 @@
/* static */
keymaster_error_t TrustyKeymasterDevice::update(
- const keymaster2_device_t* dev, keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params, const keymaster_blob_t* input,
- size_t* input_consumed, keymaster_key_param_set_t* out_params, keymaster_blob_t* output) {
+ const keymaster2_device_t* dev, keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params, const keymaster_blob_t* input,
+ size_t* input_consumed, keymaster_key_param_set_t* out_params, keymaster_blob_t* output) {
return convert_device(dev)->update(operation_handle, in_params, input, input_consumed,
out_params, output);
}
@@ -755,42 +719,4 @@
return convert_device(dev)->abort(operation_handle);
}
-keymaster_error_t TrustyKeymasterDevice::Send(uint32_t command, const Serializable& req,
- KeymasterResponse* rsp) {
- uint32_t req_size = req.SerializedSize();
- if (req_size > SEND_BUF_SIZE) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
- uint8_t send_buf[SEND_BUF_SIZE];
- Eraser send_buf_eraser(send_buf, SEND_BUF_SIZE);
- req.Serialize(send_buf, send_buf + req_size);
-
- // Send it
- uint8_t recv_buf[RECV_BUF_SIZE];
- Eraser recv_buf_eraser(recv_buf, RECV_BUF_SIZE);
- uint32_t rsp_size = RECV_BUF_SIZE;
- ALOGV("Sending %d byte request\n", (int)req.SerializedSize());
- int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
- if (rc < 0) {
- // Reset the connection on tipc error
- trusty_keymaster_disconnect();
- trusty_keymaster_connect();
- ALOGE("tipc error: %d\n", rc);
- // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
- return translate_error(rc);
- } else {
- ALOGV("Received %d byte response\n", rsp_size);
- }
-
- const uint8_t* p = recv_buf;
- if (!rsp->Deserialize(&p, p + rsp_size)) {
- ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
- return KM_ERROR_UNKNOWN_ERROR;
- } else if (rsp->error != KM_ERROR_OK) {
- ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
- return rsp->error;
- }
- return rsp->error;
-}
-
} // namespace keymaster
diff --git a/trusty/keymaster/trusty_keymaster_device_test.cpp b/trusty/keymaster/legacy/trusty_keymaster_device_test.cpp
similarity index 90%
rename from trusty/keymaster/trusty_keymaster_device_test.cpp
rename to trusty/keymaster/legacy/trusty_keymaster_device_test.cpp
index 9227964..68def58 100644
--- a/trusty/keymaster/trusty_keymaster_device_test.cpp
+++ b/trusty/keymaster/legacy/trusty_keymaster_device_test.cpp
@@ -28,15 +28,15 @@
#include <keymaster/keymaster_tags.h>
#include <keymaster/soft_keymaster_context.h>
+#include <trusty_keymaster/legacy/trusty_keymaster_device.h>
#include "android_keymaster_test_utils.h"
-#include "trusty_keymaster_device.h"
#include "openssl_utils.h"
-using std::string;
using std::ifstream;
using std::istreambuf_iterator;
+using std::string;
-static keymaster::AndroidKeymaster *impl_ = nullptr;
+static keymaster::AndroidKeymaster* impl_ = nullptr;
extern "C" {
int __android_log_print();
@@ -65,8 +65,8 @@
template <typename Req, typename Rsp>
static int fake_call(keymaster::AndroidKeymaster* device,
- void (keymaster::AndroidKeymaster::*method)(const Req&, Rsp*), void* in_buf,
- uint32_t in_size, void* out_buf, uint32_t* out_size) {
+ void (keymaster::AndroidKeymaster::*method)(const Req&, Rsp*), void* in_buf,
+ uint32_t in_size, void* out_buf, uint32_t* out_size) {
Req req;
const uint8_t* in = static_cast<uint8_t*>(in_buf);
req.Deserialize(&in, in + in_size);
@@ -80,29 +80,28 @@
}
int trusty_keymaster_call(uint32_t cmd, void* in_buf, uint32_t in_size, void* out_buf,
- uint32_t* out_size) {
+ uint32_t* out_size) {
switch (cmd) {
- case KM_GENERATE_KEY:
- return fake_call(impl_, &keymaster::AndroidKeymaster::GenerateKey, in_buf, in_size,
- out_buf, out_size);
- case KM_BEGIN_OPERATION:
- return fake_call(impl_, &keymaster::AndroidKeymaster::BeginOperation, in_buf, in_size,
- out_buf, out_size);
- case KM_UPDATE_OPERATION:
- return fake_call(impl_, &keymaster::AndroidKeymaster::UpdateOperation, in_buf, in_size,
- out_buf, out_size);
- case KM_FINISH_OPERATION:
- return fake_call(impl_, &keymaster::AndroidKeymaster::FinishOperation, in_buf, in_size,
- out_buf, out_size);
- case KM_IMPORT_KEY:
- return fake_call(impl_, &keymaster::AndroidKeymaster::ImportKey, in_buf, in_size, out_buf,
- out_size);
- case KM_EXPORT_KEY:
- return fake_call(impl_, &keymaster::AndroidKeymaster::ExportKey, in_buf, in_size, out_buf,
- out_size);
+ case KM_GENERATE_KEY:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::GenerateKey, in_buf, in_size,
+ out_buf, out_size);
+ case KM_BEGIN_OPERATION:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::BeginOperation, in_buf, in_size,
+ out_buf, out_size);
+ case KM_UPDATE_OPERATION:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::UpdateOperation, in_buf, in_size,
+ out_buf, out_size);
+ case KM_FINISH_OPERATION:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::FinishOperation, in_buf, in_size,
+ out_buf, out_size);
+ case KM_IMPORT_KEY:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::ImportKey, in_buf, in_size,
+ out_buf, out_size);
+ case KM_EXPORT_KEY:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::ExportKey, in_buf, in_size,
+ out_buf, out_size);
}
return -EINVAL;
-
}
namespace keymaster {
@@ -127,15 +126,15 @@
size_t dsa_message_len(const keymaster_dsa_keygen_params_t& params) {
switch (params.key_size) {
- case 256:
- case 1024:
- return 48;
- case 2048:
- case 4096:
- return 72;
- default:
- // Oops.
- return 0;
+ case 256:
+ case 1024:
+ return 48;
+ case 2048:
+ case 4096:
+ return 72;
+ default:
+ // Oops.
+ return 0;
}
}
@@ -323,9 +322,9 @@
Malloc_Delete sig_deleter(signature);
signature[siglen / 2]++;
- EXPECT_EQ(
- KM_ERROR_VERIFICATION_FAILED,
- device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature, siglen));
+ EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED,
+ device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature,
+ siglen));
}
TEST_F(VerificationTest, RsaBadMessage) {
@@ -345,9 +344,9 @@
&signature, &siglen));
Malloc_Delete sig_deleter(signature);
message[0]++;
- EXPECT_EQ(
- KM_ERROR_VERIFICATION_FAILED,
- device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature, siglen));
+ EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED,
+ device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature,
+ siglen));
}
TEST_F(VerificationTest, RsaShortMessage) {
diff --git a/trusty/keymaster/legacy/trusty_keymaster_main.cpp b/trusty/keymaster/legacy/trusty_keymaster_main.cpp
new file mode 100644
index 0000000..e3e70e6
--- /dev/null
+++ b/trusty/keymaster/legacy/trusty_keymaster_main.cpp
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymaster/keymaster_configuration.h>
+
+#include <stdio.h>
+#include <memory>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <trusty_keymaster/legacy/trusty_keymaster_device.h>
+
+using keymaster::TrustyKeymasterDevice;
+
+unsigned char rsa_privkey_pk8_der[] = {
+ 0x30, 0x82, 0x02, 0x75, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5f, 0x30, 0x82, 0x02, 0x5b,
+ 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xc6, 0x09, 0x54, 0x09, 0x04, 0x7d, 0x86, 0x34,
+ 0x81, 0x2d, 0x5a, 0x21, 0x81, 0x76, 0xe4, 0x5c, 0x41, 0xd6, 0x0a, 0x75, 0xb1, 0x39, 0x01,
+ 0xf2, 0x34, 0x22, 0x6c, 0xff, 0xe7, 0x76, 0x52, 0x1c, 0x5a, 0x77, 0xb9, 0xe3, 0x89, 0x41,
+ 0x7b, 0x71, 0xc0, 0xb6, 0xa4, 0x4d, 0x13, 0xaf, 0xe4, 0xe4, 0xa2, 0x80, 0x5d, 0x46, 0xc9,
+ 0xda, 0x29, 0x35, 0xad, 0xb1, 0xff, 0x0c, 0x1f, 0x24, 0xea, 0x06, 0xe6, 0x2b, 0x20, 0xd7,
+ 0x76, 0x43, 0x0a, 0x4d, 0x43, 0x51, 0x57, 0x23, 0x3c, 0x6f, 0x91, 0x67, 0x83, 0xc3, 0x0e,
+ 0x31, 0x0f, 0xcb, 0xd8, 0x9b, 0x85, 0xc2, 0xd5, 0x67, 0x71, 0x16, 0x97, 0x85, 0xac, 0x12,
+ 0xbc, 0xa2, 0x44, 0xab, 0xda, 0x72, 0xbf, 0xb1, 0x9f, 0xc4, 0x4d, 0x27, 0xc8, 0x1e, 0x1d,
+ 0x92, 0xde, 0x28, 0x4f, 0x40, 0x61, 0xed, 0xfd, 0x99, 0x28, 0x07, 0x45, 0xea, 0x6d, 0x25,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x1b, 0xe0, 0xf0, 0x4d, 0x9c, 0xae, 0x37,
+ 0x18, 0x69, 0x1f, 0x03, 0x53, 0x38, 0x30, 0x8e, 0x91, 0x56, 0x4b, 0x55, 0x89, 0x9f, 0xfb,
+ 0x50, 0x84, 0xd2, 0x46, 0x0e, 0x66, 0x30, 0x25, 0x7e, 0x05, 0xb3, 0xce, 0xab, 0x02, 0x97,
+ 0x2d, 0xfa, 0xbc, 0xd6, 0xce, 0x5f, 0x6e, 0xe2, 0x58, 0x9e, 0xb6, 0x79, 0x11, 0xed, 0x0f,
+ 0xac, 0x16, 0xe4, 0x3a, 0x44, 0x4b, 0x8c, 0x86, 0x1e, 0x54, 0x4a, 0x05, 0x93, 0x36, 0x57,
+ 0x72, 0xf8, 0xba, 0xf6, 0xb2, 0x2f, 0xc9, 0xe3, 0xc5, 0xf1, 0x02, 0x4b, 0x06, 0x3a, 0xc0,
+ 0x80, 0xa7, 0xb2, 0x23, 0x4c, 0xf8, 0xae, 0xe8, 0xf6, 0xc4, 0x7b, 0xbf, 0x4f, 0xd3, 0xac,
+ 0xe7, 0x24, 0x02, 0x90, 0xbe, 0xf1, 0x6c, 0x0b, 0x3f, 0x7f, 0x3c, 0xdd, 0x64, 0xce, 0x3a,
+ 0xb5, 0x91, 0x2c, 0xf6, 0xe3, 0x2f, 0x39, 0xab, 0x18, 0x83, 0x58, 0xaf, 0xcc, 0xcd, 0x80,
+ 0x81, 0x02, 0x41, 0x00, 0xe4, 0xb4, 0x9e, 0xf5, 0x0f, 0x76, 0x5d, 0x3b, 0x24, 0xdd, 0xe0,
+ 0x1a, 0xce, 0xaa, 0xf1, 0x30, 0xf2, 0xc7, 0x66, 0x70, 0xa9, 0x1a, 0x61, 0xae, 0x08, 0xaf,
+ 0x49, 0x7b, 0x4a, 0x82, 0xbe, 0x6d, 0xee, 0x8f, 0xcd, 0xd5, 0xe3, 0xf7, 0xba, 0x1c, 0xfb,
+ 0x1f, 0x0c, 0x92, 0x6b, 0x88, 0xf8, 0x8c, 0x92, 0xbf, 0xab, 0x13, 0x7f, 0xba, 0x22, 0x85,
+ 0x22, 0x7b, 0x83, 0xc3, 0x42, 0xff, 0x7c, 0x55, 0x02, 0x41, 0x00, 0xdd, 0xab, 0xb5, 0x83,
+ 0x9c, 0x4c, 0x7f, 0x6b, 0xf3, 0xd4, 0x18, 0x32, 0x31, 0xf0, 0x05, 0xb3, 0x1a, 0xa5, 0x8a,
+ 0xff, 0xdd, 0xa5, 0xc7, 0x9e, 0x4c, 0xce, 0x21, 0x7f, 0x6b, 0xc9, 0x30, 0xdb, 0xe5, 0x63,
+ 0xd4, 0x80, 0x70, 0x6c, 0x24, 0xe9, 0xeb, 0xfc, 0xab, 0x28, 0xa6, 0xcd, 0xef, 0xd3, 0x24,
+ 0xb7, 0x7e, 0x1b, 0xf7, 0x25, 0x1b, 0x70, 0x90, 0x92, 0xc2, 0x4f, 0xf5, 0x01, 0xfd, 0x91,
+ 0x02, 0x40, 0x23, 0xd4, 0x34, 0x0e, 0xda, 0x34, 0x45, 0xd8, 0xcd, 0x26, 0xc1, 0x44, 0x11,
+ 0xda, 0x6f, 0xdc, 0xa6, 0x3c, 0x1c, 0xcd, 0x4b, 0x80, 0xa9, 0x8a, 0xd5, 0x2b, 0x78, 0xcc,
+ 0x8a, 0xd8, 0xbe, 0xb2, 0x84, 0x2c, 0x1d, 0x28, 0x04, 0x05, 0xbc, 0x2f, 0x6c, 0x1b, 0xea,
+ 0x21, 0x4a, 0x1d, 0x74, 0x2a, 0xb9, 0x96, 0xb3, 0x5b, 0x63, 0xa8, 0x2a, 0x5e, 0x47, 0x0f,
+ 0xa8, 0x8d, 0xbf, 0x82, 0x3c, 0xdd, 0x02, 0x40, 0x1b, 0x7b, 0x57, 0x44, 0x9a, 0xd3, 0x0d,
+ 0x15, 0x18, 0x24, 0x9a, 0x5f, 0x56, 0xbb, 0x98, 0x29, 0x4d, 0x4b, 0x6a, 0xc1, 0x2f, 0xfc,
+ 0x86, 0x94, 0x04, 0x97, 0xa5, 0xa5, 0x83, 0x7a, 0x6c, 0xf9, 0x46, 0x26, 0x2b, 0x49, 0x45,
+ 0x26, 0xd3, 0x28, 0xc1, 0x1e, 0x11, 0x26, 0x38, 0x0f, 0xde, 0x04, 0xc2, 0x4f, 0x91, 0x6d,
+ 0xec, 0x25, 0x08, 0x92, 0xdb, 0x09, 0xa6, 0xd7, 0x7c, 0xdb, 0xa3, 0x51, 0x02, 0x40, 0x77,
+ 0x62, 0xcd, 0x8f, 0x4d, 0x05, 0x0d, 0xa5, 0x6b, 0xd5, 0x91, 0xad, 0xb5, 0x15, 0xd2, 0x4d,
+ 0x7c, 0xcd, 0x32, 0xcc, 0xa0, 0xd0, 0x5f, 0x86, 0x6d, 0x58, 0x35, 0x14, 0xbd, 0x73, 0x24,
+ 0xd5, 0xf3, 0x36, 0x45, 0xe8, 0xed, 0x8b, 0x4a, 0x1c, 0xb3, 0xcc, 0x4a, 0x1d, 0x67, 0x98,
+ 0x73, 0x99, 0xf2, 0xa0, 0x9f, 0x5b, 0x3f, 0xb6, 0x8c, 0x88, 0xd5, 0xe5, 0xd9, 0x0a, 0xc3,
+ 0x34, 0x92, 0xd6};
+unsigned int rsa_privkey_pk8_der_len = 633;
+
+unsigned char dsa_privkey_pk8_der[] = {
+ 0x30, 0x82, 0x01, 0x4b, 0x02, 0x01, 0x00, 0x30, 0x82, 0x01, 0x2b, 0x06, 0x07, 0x2a, 0x86,
+ 0x48, 0xce, 0x38, 0x04, 0x01, 0x30, 0x82, 0x01, 0x1e, 0x02, 0x81, 0x81, 0x00, 0xa3, 0xf3,
+ 0xe9, 0xb6, 0x7e, 0x7d, 0x88, 0xf6, 0xb7, 0xe5, 0xf5, 0x1f, 0x3b, 0xee, 0xac, 0xd7, 0xad,
+ 0xbc, 0xc9, 0xd1, 0x5a, 0xf8, 0x88, 0xc4, 0xef, 0x6e, 0x3d, 0x74, 0x19, 0x74, 0xe7, 0xd8,
+ 0xe0, 0x26, 0x44, 0x19, 0x86, 0xaf, 0x19, 0xdb, 0x05, 0xe9, 0x3b, 0x8b, 0x58, 0x58, 0xde,
+ 0xe5, 0x4f, 0x48, 0x15, 0x01, 0xea, 0xe6, 0x83, 0x52, 0xd7, 0xc1, 0x21, 0xdf, 0xb9, 0xb8,
+ 0x07, 0x66, 0x50, 0xfb, 0x3a, 0x0c, 0xb3, 0x85, 0xee, 0xbb, 0x04, 0x5f, 0xc2, 0x6d, 0x6d,
+ 0x95, 0xfa, 0x11, 0x93, 0x1e, 0x59, 0x5b, 0xb1, 0x45, 0x8d, 0xe0, 0x3d, 0x73, 0xaa, 0xf2,
+ 0x41, 0x14, 0x51, 0x07, 0x72, 0x3d, 0xa2, 0xf7, 0x58, 0xcd, 0x11, 0xa1, 0x32, 0xcf, 0xda,
+ 0x42, 0xb7, 0xcc, 0x32, 0x80, 0xdb, 0x87, 0x82, 0xec, 0x42, 0xdb, 0x5a, 0x55, 0x24, 0x24,
+ 0xa2, 0xd1, 0x55, 0x29, 0xad, 0xeb, 0x02, 0x15, 0x00, 0xeb, 0xea, 0x17, 0xd2, 0x09, 0xb3,
+ 0xd7, 0x21, 0x9a, 0x21, 0x07, 0x82, 0x8f, 0xab, 0xfe, 0x88, 0x71, 0x68, 0xf7, 0xe3, 0x02,
+ 0x81, 0x80, 0x19, 0x1c, 0x71, 0xfd, 0xe0, 0x03, 0x0c, 0x43, 0xd9, 0x0b, 0xf6, 0xcd, 0xd6,
+ 0xa9, 0x70, 0xe7, 0x37, 0x86, 0x3a, 0x78, 0xe9, 0xa7, 0x47, 0xa7, 0x47, 0x06, 0x88, 0xb1,
+ 0xaf, 0xd7, 0xf3, 0xf1, 0xa1, 0xd7, 0x00, 0x61, 0x28, 0x88, 0x31, 0x48, 0x60, 0xd8, 0x11,
+ 0xef, 0xa5, 0x24, 0x1a, 0x81, 0xc4, 0x2a, 0xe2, 0xea, 0x0e, 0x36, 0xd2, 0xd2, 0x05, 0x84,
+ 0x37, 0xcf, 0x32, 0x7d, 0x09, 0xe6, 0x0f, 0x8b, 0x0c, 0xc8, 0xc2, 0xa4, 0xb1, 0xdc, 0x80,
+ 0xca, 0x68, 0xdf, 0xaf, 0xd2, 0x90, 0xc0, 0x37, 0x58, 0x54, 0x36, 0x8f, 0x49, 0xb8, 0x62,
+ 0x75, 0x8b, 0x48, 0x47, 0xc0, 0xbe, 0xf7, 0x9a, 0x92, 0xa6, 0x68, 0x05, 0xda, 0x9d, 0xaf,
+ 0x72, 0x9a, 0x67, 0xb3, 0xb4, 0x14, 0x03, 0xae, 0x4f, 0x4c, 0x76, 0xb9, 0xd8, 0x64, 0x0a,
+ 0xba, 0x3b, 0xa8, 0x00, 0x60, 0x4d, 0xae, 0x81, 0xc3, 0xc5, 0x04, 0x17, 0x02, 0x15, 0x00,
+ 0x81, 0x9d, 0xfd, 0x53, 0x0c, 0xc1, 0x8f, 0xbe, 0x8b, 0xea, 0x00, 0x26, 0x19, 0x29, 0x33,
+ 0x91, 0x84, 0xbe, 0xad, 0x81};
+unsigned int dsa_privkey_pk8_der_len = 335;
+
+unsigned char ec_privkey_pk8_der[] = {
+ 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce,
+ 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04,
+ 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, 0x73, 0x7c, 0x2e, 0xcd, 0x7b, 0x8d,
+ 0x19, 0x40, 0xbf, 0x29, 0x30, 0xaa, 0x9b, 0x4e, 0xd3, 0xff, 0x94, 0x1e, 0xed, 0x09,
+ 0x36, 0x6b, 0xc0, 0x32, 0x99, 0x98, 0x64, 0x81, 0xf3, 0xa4, 0xd8, 0x59, 0xa1, 0x44,
+ 0x03, 0x42, 0x00, 0x04, 0xbf, 0x85, 0xd7, 0x72, 0x0d, 0x07, 0xc2, 0x54, 0x61, 0x68,
+ 0x3b, 0xc6, 0x48, 0xb4, 0x77, 0x8a, 0x9a, 0x14, 0xdd, 0x8a, 0x02, 0x4e, 0x3b, 0xdd,
+ 0x8c, 0x7d, 0xdd, 0x9a, 0xb2, 0xb5, 0x28, 0xbb, 0xc7, 0xaa, 0x1b, 0x51, 0xf1, 0x4e,
+ 0xbb, 0xbb, 0x0b, 0xd0, 0xce, 0x21, 0xbc, 0xc4, 0x1c, 0x6e, 0xb0, 0x00, 0x83, 0xcf,
+ 0x33, 0x76, 0xd1, 0x1f, 0xd4, 0x49, 0x49, 0xe0, 0xb2, 0x18, 0x3b, 0xfe};
+unsigned int ec_privkey_pk8_der_len = 138;
+
+keymaster_key_param_t ec_params[] = {
+ keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_EC),
+ keymaster_param_long(KM_TAG_EC_CURVE, KM_EC_CURVE_P_521),
+ keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
+ keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
+ keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
+};
+keymaster_key_param_set_t ec_param_set = {ec_params, sizeof(ec_params) / sizeof(*ec_params)};
+
+keymaster_key_param_t rsa_params[] = {
+ keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA),
+ keymaster_param_int(KM_TAG_KEY_SIZE, 1024),
+ keymaster_param_long(KM_TAG_RSA_PUBLIC_EXPONENT, 65537),
+ keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
+ keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
+ keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
+ keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
+};
+keymaster_key_param_set_t rsa_param_set = {rsa_params, sizeof(rsa_params) / sizeof(*rsa_params)};
+
+struct EVP_PKEY_Delete {
+ void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
+};
+
+struct EVP_PKEY_CTX_Delete {
+ void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
+};
+
+static bool do_operation(TrustyKeymasterDevice* device, keymaster_purpose_t purpose,
+ keymaster_key_blob_t* key, keymaster_blob_t* input,
+ keymaster_blob_t* signature, keymaster_blob_t* output) {
+ keymaster_key_param_t params[] = {
+ keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
+ keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
+ };
+ keymaster_key_param_set_t param_set = {params, sizeof(params) / sizeof(*params)};
+ keymaster_operation_handle_t op_handle;
+ keymaster_error_t error = device->begin(purpose, key, ¶m_set, nullptr, &op_handle);
+ if (error != KM_ERROR_OK) {
+ printf("Keymaster begin() failed: %d\n", error);
+ return false;
+ }
+ size_t input_consumed;
+ error = device->update(op_handle, nullptr, input, &input_consumed, nullptr, nullptr);
+ if (error != KM_ERROR_OK) {
+ printf("Keymaster update() failed: %d\n", error);
+ return false;
+ }
+ if (input_consumed != input->data_length) {
+ // This should never happen. If it does, it's a bug in the keymaster implementation.
+ printf("Keymaster update() did not consume all data.\n");
+ device->abort(op_handle);
+ return false;
+ }
+ error = device->finish(op_handle, nullptr, nullptr, signature, nullptr, output);
+ if (error != KM_ERROR_OK) {
+ printf("Keymaster finish() failed: %d\n", error);
+ return false;
+ }
+ return true;
+}
+
+static bool test_import_rsa(TrustyKeymasterDevice* device) {
+ printf("===================\n");
+ printf("= RSA Import Test =\n");
+ printf("===================\n\n");
+
+ printf("=== Importing RSA keypair === \n");
+ keymaster_key_blob_t key;
+ keymaster_blob_t private_key = {rsa_privkey_pk8_der, rsa_privkey_pk8_der_len};
+ int error =
+ device->import_key(&rsa_param_set, KM_KEY_FORMAT_PKCS8, &private_key, &key, nullptr);
+ if (error != KM_ERROR_OK) {
+ printf("Error importing RSA key: %d\n\n", error);
+ return false;
+ }
+ std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
+
+ printf("=== Signing with imported RSA key ===\n");
+ size_t message_len = 1024 / 8;
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
+ memset(message.get(), 'a', message_len);
+ keymaster_blob_t input = {message.get(), message_len}, signature;
+
+ if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
+ printf("Error signing data with imported RSA key\n\n");
+ return false;
+ }
+ std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
+
+ printf("=== Verifying with imported RSA key === \n");
+ if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
+ printf("Error verifying data with imported RSA key\n\n");
+ return false;
+ }
+
+ printf("\n");
+ return true;
+}
+
+static bool test_rsa(TrustyKeymasterDevice* device) {
+ printf("============\n");
+ printf("= RSA Test =\n");
+ printf("============\n\n");
+
+ printf("=== Generating RSA key pair ===\n");
+ keymaster_key_blob_t key;
+ int error = device->generate_key(&rsa_param_set, &key, nullptr);
+ if (error != KM_ERROR_OK) {
+ printf("Error generating RSA key pair: %d\n\n", error);
+ return false;
+ }
+ std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
+
+ printf("=== Signing with RSA key === \n");
+ size_t message_len = 1024 / 8;
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
+ memset(message.get(), 'a', message_len);
+ keymaster_blob_t input = {message.get(), message_len}, signature;
+
+ if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
+ printf("Error signing data with RSA key\n\n");
+ return false;
+ }
+ std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
+
+ printf("=== Verifying with RSA key === \n");
+ if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
+ printf("Error verifying data with RSA key\n\n");
+ return false;
+ }
+
+ printf("=== Exporting RSA public key ===\n");
+ keymaster_blob_t exported_key;
+ error = device->export_key(KM_KEY_FORMAT_X509, &key, nullptr, nullptr, &exported_key);
+ if (error != KM_ERROR_OK) {
+ printf("Error exporting RSA public key: %d\n\n", error);
+ return false;
+ }
+
+ printf("=== Verifying with exported key ===\n");
+ const uint8_t* tmp = exported_key.data;
+ std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+ d2i_PUBKEY(NULL, &tmp, exported_key.data_length));
+ std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+ if (EVP_PKEY_verify_init(ctx.get()) != 1) {
+ printf("Error initializing openss EVP context\n\n");
+ return false;
+ }
+ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
+ printf("Exported key was the wrong type?!?\n\n");
+ return false;
+ }
+
+ EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
+ if (EVP_PKEY_verify(ctx.get(), signature.data, signature.data_length, message.get(),
+ message_len) != 1) {
+ printf("Verification with exported pubkey failed.\n\n");
+ return false;
+ } else {
+ printf("Verification succeeded\n");
+ }
+
+ printf("\n");
+ return true;
+}
+
+static bool test_import_ecdsa(TrustyKeymasterDevice* device) {
+ printf("=====================\n");
+ printf("= ECDSA Import Test =\n");
+ printf("=====================\n\n");
+
+ printf("=== Importing ECDSA keypair === \n");
+ keymaster_key_blob_t key;
+ keymaster_blob_t private_key = {ec_privkey_pk8_der, ec_privkey_pk8_der_len};
+ int error = device->import_key(&ec_param_set, KM_KEY_FORMAT_PKCS8, &private_key, &key, nullptr);
+ if (error != KM_ERROR_OK) {
+ printf("Error importing ECDSA key: %d\n\n", error);
+ return false;
+ }
+ std::unique_ptr<const uint8_t[]> deleter(key.key_material);
+
+ printf("=== Signing with imported ECDSA key ===\n");
+ size_t message_len = 30 /* arbitrary */;
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
+ memset(message.get(), 'a', message_len);
+ keymaster_blob_t input = {message.get(), message_len}, signature;
+
+ if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
+ printf("Error signing data with imported ECDSA key\n\n");
+ return false;
+ }
+ std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
+
+ printf("=== Verifying with imported ECDSA key === \n");
+ if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
+ printf("Error verifying data with imported ECDSA key\n\n");
+ return false;
+ }
+
+ printf("\n");
+ return true;
+}
+
+static bool test_ecdsa(TrustyKeymasterDevice* device) {
+ printf("==============\n");
+ printf("= ECDSA Test =\n");
+ printf("==============\n\n");
+
+ printf("=== Generating ECDSA key pair ===\n");
+ keymaster_key_blob_t key;
+ int error = device->generate_key(&ec_param_set, &key, nullptr);
+ if (error != KM_ERROR_OK) {
+ printf("Error generating ECDSA key pair: %d\n\n", error);
+ return false;
+ }
+ std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
+
+ printf("=== Signing with ECDSA key === \n");
+ size_t message_len = 30 /* arbitrary */;
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
+ memset(message.get(), 'a', message_len);
+ keymaster_blob_t input = {message.get(), message_len}, signature;
+
+ if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
+ printf("Error signing data with ECDSA key\n\n");
+ return false;
+ }
+ std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
+
+ printf("=== Verifying with ECDSA key === \n");
+ if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
+ printf("Error verifying data with ECDSA key\n\n");
+ return false;
+ }
+
+ printf("=== Exporting ECDSA public key ===\n");
+ keymaster_blob_t exported_key;
+ error = device->export_key(KM_KEY_FORMAT_X509, &key, nullptr, nullptr, &exported_key);
+ if (error != KM_ERROR_OK) {
+ printf("Error exporting ECDSA public key: %d\n\n", error);
+ return false;
+ }
+
+ printf("=== Verifying with exported key ===\n");
+ const uint8_t* tmp = exported_key.data;
+ std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+ d2i_PUBKEY(NULL, &tmp, exported_key.data_length));
+ std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+ if (EVP_PKEY_verify_init(ctx.get()) != 1) {
+ printf("Error initializing openssl EVP context\n\n");
+ return false;
+ }
+ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
+ printf("Exported key was the wrong type?!?\n\n");
+ return false;
+ }
+
+ if (EVP_PKEY_verify(ctx.get(), signature.data, signature.data_length, message.get(),
+ message_len) != 1) {
+ printf("Verification with exported pubkey failed.\n\n");
+ return false;
+ } else {
+ printf("Verification succeeded\n");
+ }
+
+ printf("\n");
+ return true;
+}
+
+int main(void) {
+ TrustyKeymasterDevice device(NULL);
+ keymaster::ConfigureDevice(reinterpret_cast<keymaster2_device_t*>(&device));
+ if (device.session_error() != KM_ERROR_OK) {
+ printf("Failed to initialize Trusty session: %d\n", device.session_error());
+ return 1;
+ }
+ printf("Trusty session initialized\n");
+
+ bool success = true;
+ success &= test_rsa(&device);
+ success &= test_import_rsa(&device);
+ success &= test_ecdsa(&device);
+ success &= test_import_ecdsa(&device);
+
+ if (success) {
+ printf("\nTESTS PASSED!\n");
+ } else {
+ printf("\n!!!!TESTS FAILED!!!\n");
+ }
+
+ return success ? 0 : 1;
+}
diff --git a/trusty/keymaster/trusty_keymaster_ipc.cpp b/trusty/keymaster/trusty_keymaster_ipc.cpp
deleted file mode 100644
index 686e7ae..0000000
--- a/trusty/keymaster/trusty_keymaster_ipc.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "TrustyKeymaster"
-
-// TODO: make this generic in libtrusty
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <algorithm>
-
-#include <log/log.h>
-#include <trusty/tipc.h>
-
-#include "keymaster_ipc.h"
-#include "trusty_keymaster_ipc.h"
-
-#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
-
-static int handle_ = -1;
-
-int trusty_keymaster_connect() {
- int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
- if (rc < 0) {
- return rc;
- }
-
- handle_ = rc;
- return 0;
-}
-
-int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
- uint32_t* out_size) {
- if (handle_ < 0) {
- ALOGE("not connected\n");
- return -EINVAL;
- }
-
- size_t msg_size = in_size + sizeof(struct keymaster_message);
- struct keymaster_message* msg = reinterpret_cast<struct keymaster_message*>(malloc(msg_size));
- if (!msg) {
- ALOGE("failed to allocate msg buffer\n");
- return -EINVAL;
- }
-
- msg->cmd = cmd;
- memcpy(msg->payload, in, in_size);
-
- ssize_t rc = write(handle_, msg, msg_size);
- free(msg);
-
- if (rc < 0) {
- ALOGE("failed to send cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT, strerror(errno));
- return -errno;
- }
- size_t out_max_size = *out_size;
- *out_size = 0;
- struct iovec iov[2];
- struct keymaster_message header;
- iov[0] = {.iov_base = &header, .iov_len = sizeof(struct keymaster_message)};
- while (true) {
- iov[1] = {
- .iov_base = out + *out_size,
- .iov_len = std::min<uint32_t>(KEYMASTER_MAX_BUFFER_LENGTH, out_max_size - *out_size)};
- rc = readv(handle_, iov, 2);
- if (rc < 0) {
- ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT,
- strerror(errno));
- return -errno;
- }
-
- if ((size_t)rc < sizeof(struct keymaster_message)) {
- ALOGE("invalid response size (%d)\n", (int)rc);
- return -EINVAL;
- }
-
- if ((cmd | KEYMASTER_RESP_BIT) != (header.cmd & ~(KEYMASTER_STOP_BIT))) {
- ALOGE("invalid command (%d)", header.cmd);
- return -EINVAL;
- }
- *out_size += ((size_t)rc - sizeof(struct keymaster_message));
- if (header.cmd & KEYMASTER_STOP_BIT) {
- break;
- }
- }
-
- return rc;
-}
-
-void trusty_keymaster_disconnect() {
- if (handle_ >= 0) {
- tipc_close(handle_);
- }
- handle_ = -1;
-}
diff --git a/trusty/keymaster/trusty_keymaster_main.cpp b/trusty/keymaster/trusty_keymaster_main.cpp
deleted file mode 100644
index ed78b7f..0000000
--- a/trusty/keymaster/trusty_keymaster_main.cpp
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * Copyright 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <keymaster/keymaster_configuration.h>
-
-#include <stdio.h>
-#include <memory>
-
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-
-#include "trusty_keymaster_device.h"
-
-using keymaster::TrustyKeymasterDevice;
-
-unsigned char rsa_privkey_pk8_der[] = {
- 0x30, 0x82, 0x02, 0x75, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5f, 0x30, 0x82, 0x02, 0x5b, 0x02, 0x01,
- 0x00, 0x02, 0x81, 0x81, 0x00, 0xc6, 0x09, 0x54, 0x09, 0x04, 0x7d, 0x86, 0x34, 0x81, 0x2d, 0x5a,
- 0x21, 0x81, 0x76, 0xe4, 0x5c, 0x41, 0xd6, 0x0a, 0x75, 0xb1, 0x39, 0x01, 0xf2, 0x34, 0x22, 0x6c,
- 0xff, 0xe7, 0x76, 0x52, 0x1c, 0x5a, 0x77, 0xb9, 0xe3, 0x89, 0x41, 0x7b, 0x71, 0xc0, 0xb6, 0xa4,
- 0x4d, 0x13, 0xaf, 0xe4, 0xe4, 0xa2, 0x80, 0x5d, 0x46, 0xc9, 0xda, 0x29, 0x35, 0xad, 0xb1, 0xff,
- 0x0c, 0x1f, 0x24, 0xea, 0x06, 0xe6, 0x2b, 0x20, 0xd7, 0x76, 0x43, 0x0a, 0x4d, 0x43, 0x51, 0x57,
- 0x23, 0x3c, 0x6f, 0x91, 0x67, 0x83, 0xc3, 0x0e, 0x31, 0x0f, 0xcb, 0xd8, 0x9b, 0x85, 0xc2, 0xd5,
- 0x67, 0x71, 0x16, 0x97, 0x85, 0xac, 0x12, 0xbc, 0xa2, 0x44, 0xab, 0xda, 0x72, 0xbf, 0xb1, 0x9f,
- 0xc4, 0x4d, 0x27, 0xc8, 0x1e, 0x1d, 0x92, 0xde, 0x28, 0x4f, 0x40, 0x61, 0xed, 0xfd, 0x99, 0x28,
- 0x07, 0x45, 0xea, 0x6d, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x1b, 0xe0, 0xf0,
- 0x4d, 0x9c, 0xae, 0x37, 0x18, 0x69, 0x1f, 0x03, 0x53, 0x38, 0x30, 0x8e, 0x91, 0x56, 0x4b, 0x55,
- 0x89, 0x9f, 0xfb, 0x50, 0x84, 0xd2, 0x46, 0x0e, 0x66, 0x30, 0x25, 0x7e, 0x05, 0xb3, 0xce, 0xab,
- 0x02, 0x97, 0x2d, 0xfa, 0xbc, 0xd6, 0xce, 0x5f, 0x6e, 0xe2, 0x58, 0x9e, 0xb6, 0x79, 0x11, 0xed,
- 0x0f, 0xac, 0x16, 0xe4, 0x3a, 0x44, 0x4b, 0x8c, 0x86, 0x1e, 0x54, 0x4a, 0x05, 0x93, 0x36, 0x57,
- 0x72, 0xf8, 0xba, 0xf6, 0xb2, 0x2f, 0xc9, 0xe3, 0xc5, 0xf1, 0x02, 0x4b, 0x06, 0x3a, 0xc0, 0x80,
- 0xa7, 0xb2, 0x23, 0x4c, 0xf8, 0xae, 0xe8, 0xf6, 0xc4, 0x7b, 0xbf, 0x4f, 0xd3, 0xac, 0xe7, 0x24,
- 0x02, 0x90, 0xbe, 0xf1, 0x6c, 0x0b, 0x3f, 0x7f, 0x3c, 0xdd, 0x64, 0xce, 0x3a, 0xb5, 0x91, 0x2c,
- 0xf6, 0xe3, 0x2f, 0x39, 0xab, 0x18, 0x83, 0x58, 0xaf, 0xcc, 0xcd, 0x80, 0x81, 0x02, 0x41, 0x00,
- 0xe4, 0xb4, 0x9e, 0xf5, 0x0f, 0x76, 0x5d, 0x3b, 0x24, 0xdd, 0xe0, 0x1a, 0xce, 0xaa, 0xf1, 0x30,
- 0xf2, 0xc7, 0x66, 0x70, 0xa9, 0x1a, 0x61, 0xae, 0x08, 0xaf, 0x49, 0x7b, 0x4a, 0x82, 0xbe, 0x6d,
- 0xee, 0x8f, 0xcd, 0xd5, 0xe3, 0xf7, 0xba, 0x1c, 0xfb, 0x1f, 0x0c, 0x92, 0x6b, 0x88, 0xf8, 0x8c,
- 0x92, 0xbf, 0xab, 0x13, 0x7f, 0xba, 0x22, 0x85, 0x22, 0x7b, 0x83, 0xc3, 0x42, 0xff, 0x7c, 0x55,
- 0x02, 0x41, 0x00, 0xdd, 0xab, 0xb5, 0x83, 0x9c, 0x4c, 0x7f, 0x6b, 0xf3, 0xd4, 0x18, 0x32, 0x31,
- 0xf0, 0x05, 0xb3, 0x1a, 0xa5, 0x8a, 0xff, 0xdd, 0xa5, 0xc7, 0x9e, 0x4c, 0xce, 0x21, 0x7f, 0x6b,
- 0xc9, 0x30, 0xdb, 0xe5, 0x63, 0xd4, 0x80, 0x70, 0x6c, 0x24, 0xe9, 0xeb, 0xfc, 0xab, 0x28, 0xa6,
- 0xcd, 0xef, 0xd3, 0x24, 0xb7, 0x7e, 0x1b, 0xf7, 0x25, 0x1b, 0x70, 0x90, 0x92, 0xc2, 0x4f, 0xf5,
- 0x01, 0xfd, 0x91, 0x02, 0x40, 0x23, 0xd4, 0x34, 0x0e, 0xda, 0x34, 0x45, 0xd8, 0xcd, 0x26, 0xc1,
- 0x44, 0x11, 0xda, 0x6f, 0xdc, 0xa6, 0x3c, 0x1c, 0xcd, 0x4b, 0x80, 0xa9, 0x8a, 0xd5, 0x2b, 0x78,
- 0xcc, 0x8a, 0xd8, 0xbe, 0xb2, 0x84, 0x2c, 0x1d, 0x28, 0x04, 0x05, 0xbc, 0x2f, 0x6c, 0x1b, 0xea,
- 0x21, 0x4a, 0x1d, 0x74, 0x2a, 0xb9, 0x96, 0xb3, 0x5b, 0x63, 0xa8, 0x2a, 0x5e, 0x47, 0x0f, 0xa8,
- 0x8d, 0xbf, 0x82, 0x3c, 0xdd, 0x02, 0x40, 0x1b, 0x7b, 0x57, 0x44, 0x9a, 0xd3, 0x0d, 0x15, 0x18,
- 0x24, 0x9a, 0x5f, 0x56, 0xbb, 0x98, 0x29, 0x4d, 0x4b, 0x6a, 0xc1, 0x2f, 0xfc, 0x86, 0x94, 0x04,
- 0x97, 0xa5, 0xa5, 0x83, 0x7a, 0x6c, 0xf9, 0x46, 0x26, 0x2b, 0x49, 0x45, 0x26, 0xd3, 0x28, 0xc1,
- 0x1e, 0x11, 0x26, 0x38, 0x0f, 0xde, 0x04, 0xc2, 0x4f, 0x91, 0x6d, 0xec, 0x25, 0x08, 0x92, 0xdb,
- 0x09, 0xa6, 0xd7, 0x7c, 0xdb, 0xa3, 0x51, 0x02, 0x40, 0x77, 0x62, 0xcd, 0x8f, 0x4d, 0x05, 0x0d,
- 0xa5, 0x6b, 0xd5, 0x91, 0xad, 0xb5, 0x15, 0xd2, 0x4d, 0x7c, 0xcd, 0x32, 0xcc, 0xa0, 0xd0, 0x5f,
- 0x86, 0x6d, 0x58, 0x35, 0x14, 0xbd, 0x73, 0x24, 0xd5, 0xf3, 0x36, 0x45, 0xe8, 0xed, 0x8b, 0x4a,
- 0x1c, 0xb3, 0xcc, 0x4a, 0x1d, 0x67, 0x98, 0x73, 0x99, 0xf2, 0xa0, 0x9f, 0x5b, 0x3f, 0xb6, 0x8c,
- 0x88, 0xd5, 0xe5, 0xd9, 0x0a, 0xc3, 0x34, 0x92, 0xd6};
-unsigned int rsa_privkey_pk8_der_len = 633;
-
-unsigned char dsa_privkey_pk8_der[] = {
- 0x30, 0x82, 0x01, 0x4b, 0x02, 0x01, 0x00, 0x30, 0x82, 0x01, 0x2b, 0x06, 0x07, 0x2a, 0x86, 0x48,
- 0xce, 0x38, 0x04, 0x01, 0x30, 0x82, 0x01, 0x1e, 0x02, 0x81, 0x81, 0x00, 0xa3, 0xf3, 0xe9, 0xb6,
- 0x7e, 0x7d, 0x88, 0xf6, 0xb7, 0xe5, 0xf5, 0x1f, 0x3b, 0xee, 0xac, 0xd7, 0xad, 0xbc, 0xc9, 0xd1,
- 0x5a, 0xf8, 0x88, 0xc4, 0xef, 0x6e, 0x3d, 0x74, 0x19, 0x74, 0xe7, 0xd8, 0xe0, 0x26, 0x44, 0x19,
- 0x86, 0xaf, 0x19, 0xdb, 0x05, 0xe9, 0x3b, 0x8b, 0x58, 0x58, 0xde, 0xe5, 0x4f, 0x48, 0x15, 0x01,
- 0xea, 0xe6, 0x83, 0x52, 0xd7, 0xc1, 0x21, 0xdf, 0xb9, 0xb8, 0x07, 0x66, 0x50, 0xfb, 0x3a, 0x0c,
- 0xb3, 0x85, 0xee, 0xbb, 0x04, 0x5f, 0xc2, 0x6d, 0x6d, 0x95, 0xfa, 0x11, 0x93, 0x1e, 0x59, 0x5b,
- 0xb1, 0x45, 0x8d, 0xe0, 0x3d, 0x73, 0xaa, 0xf2, 0x41, 0x14, 0x51, 0x07, 0x72, 0x3d, 0xa2, 0xf7,
- 0x58, 0xcd, 0x11, 0xa1, 0x32, 0xcf, 0xda, 0x42, 0xb7, 0xcc, 0x32, 0x80, 0xdb, 0x87, 0x82, 0xec,
- 0x42, 0xdb, 0x5a, 0x55, 0x24, 0x24, 0xa2, 0xd1, 0x55, 0x29, 0xad, 0xeb, 0x02, 0x15, 0x00, 0xeb,
- 0xea, 0x17, 0xd2, 0x09, 0xb3, 0xd7, 0x21, 0x9a, 0x21, 0x07, 0x82, 0x8f, 0xab, 0xfe, 0x88, 0x71,
- 0x68, 0xf7, 0xe3, 0x02, 0x81, 0x80, 0x19, 0x1c, 0x71, 0xfd, 0xe0, 0x03, 0x0c, 0x43, 0xd9, 0x0b,
- 0xf6, 0xcd, 0xd6, 0xa9, 0x70, 0xe7, 0x37, 0x86, 0x3a, 0x78, 0xe9, 0xa7, 0x47, 0xa7, 0x47, 0x06,
- 0x88, 0xb1, 0xaf, 0xd7, 0xf3, 0xf1, 0xa1, 0xd7, 0x00, 0x61, 0x28, 0x88, 0x31, 0x48, 0x60, 0xd8,
- 0x11, 0xef, 0xa5, 0x24, 0x1a, 0x81, 0xc4, 0x2a, 0xe2, 0xea, 0x0e, 0x36, 0xd2, 0xd2, 0x05, 0x84,
- 0x37, 0xcf, 0x32, 0x7d, 0x09, 0xe6, 0x0f, 0x8b, 0x0c, 0xc8, 0xc2, 0xa4, 0xb1, 0xdc, 0x80, 0xca,
- 0x68, 0xdf, 0xaf, 0xd2, 0x90, 0xc0, 0x37, 0x58, 0x54, 0x36, 0x8f, 0x49, 0xb8, 0x62, 0x75, 0x8b,
- 0x48, 0x47, 0xc0, 0xbe, 0xf7, 0x9a, 0x92, 0xa6, 0x68, 0x05, 0xda, 0x9d, 0xaf, 0x72, 0x9a, 0x67,
- 0xb3, 0xb4, 0x14, 0x03, 0xae, 0x4f, 0x4c, 0x76, 0xb9, 0xd8, 0x64, 0x0a, 0xba, 0x3b, 0xa8, 0x00,
- 0x60, 0x4d, 0xae, 0x81, 0xc3, 0xc5, 0x04, 0x17, 0x02, 0x15, 0x00, 0x81, 0x9d, 0xfd, 0x53, 0x0c,
- 0xc1, 0x8f, 0xbe, 0x8b, 0xea, 0x00, 0x26, 0x19, 0x29, 0x33, 0x91, 0x84, 0xbe, 0xad, 0x81};
-unsigned int dsa_privkey_pk8_der_len = 335;
-
-unsigned char ec_privkey_pk8_der[] = {
- 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
- 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02,
- 0x01, 0x01, 0x04, 0x20, 0x73, 0x7c, 0x2e, 0xcd, 0x7b, 0x8d, 0x19, 0x40, 0xbf, 0x29, 0x30, 0xaa,
- 0x9b, 0x4e, 0xd3, 0xff, 0x94, 0x1e, 0xed, 0x09, 0x36, 0x6b, 0xc0, 0x32, 0x99, 0x98, 0x64, 0x81,
- 0xf3, 0xa4, 0xd8, 0x59, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xbf, 0x85, 0xd7, 0x72, 0x0d, 0x07,
- 0xc2, 0x54, 0x61, 0x68, 0x3b, 0xc6, 0x48, 0xb4, 0x77, 0x8a, 0x9a, 0x14, 0xdd, 0x8a, 0x02, 0x4e,
- 0x3b, 0xdd, 0x8c, 0x7d, 0xdd, 0x9a, 0xb2, 0xb5, 0x28, 0xbb, 0xc7, 0xaa, 0x1b, 0x51, 0xf1, 0x4e,
- 0xbb, 0xbb, 0x0b, 0xd0, 0xce, 0x21, 0xbc, 0xc4, 0x1c, 0x6e, 0xb0, 0x00, 0x83, 0xcf, 0x33, 0x76,
- 0xd1, 0x1f, 0xd4, 0x49, 0x49, 0xe0, 0xb2, 0x18, 0x3b, 0xfe};
-unsigned int ec_privkey_pk8_der_len = 138;
-
-keymaster_key_param_t ec_params[] = {
- keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_EC),
- keymaster_param_long(KM_TAG_EC_CURVE, KM_EC_CURVE_P_521),
- keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
- keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_VERIFY),
- keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
- keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
-};
-keymaster_key_param_set_t ec_param_set = {ec_params, sizeof(ec_params) / sizeof(*ec_params)};
-
-keymaster_key_param_t rsa_params[] = {
- keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA),
- keymaster_param_int(KM_TAG_KEY_SIZE, 1024),
- keymaster_param_long(KM_TAG_RSA_PUBLIC_EXPONENT, 65537),
- keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
- keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_VERIFY),
- keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
- keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
- keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
-};
-keymaster_key_param_set_t rsa_param_set = {rsa_params, sizeof(rsa_params) / sizeof(*rsa_params)};
-
-struct EVP_PKEY_Delete {
- void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
-};
-
-struct EVP_PKEY_CTX_Delete {
- void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
-};
-
-static bool do_operation(TrustyKeymasterDevice* device, keymaster_purpose_t purpose,
- keymaster_key_blob_t* key, keymaster_blob_t* input,
- keymaster_blob_t* signature, keymaster_blob_t* output) {
- keymaster_key_param_t params[] = {
- keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
- keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
- };
- keymaster_key_param_set_t param_set = {params, sizeof(params) / sizeof(*params)};
- keymaster_operation_handle_t op_handle;
- keymaster_error_t error = device->begin(purpose, key, ¶m_set, nullptr, &op_handle);
- if (error != KM_ERROR_OK) {
- printf("Keymaster begin() failed: %d\n", error);
- return false;
- }
- size_t input_consumed;
- error = device->update(op_handle, nullptr, input, &input_consumed, nullptr, nullptr);
- if (error != KM_ERROR_OK) {
- printf("Keymaster update() failed: %d\n", error);
- return false;
- }
- if (input_consumed != input->data_length) {
- // This should never happen. If it does, it's a bug in the keymaster implementation.
- printf("Keymaster update() did not consume all data.\n");
- device->abort(op_handle);
- return false;
- }
- error = device->finish(op_handle, nullptr, nullptr, signature, nullptr, output);
- if (error != KM_ERROR_OK) {
- printf("Keymaster finish() failed: %d\n", error);
- return false;
- }
- return true;
-}
-
-static bool test_import_rsa(TrustyKeymasterDevice* device) {
- printf("===================\n");
- printf("= RSA Import Test =\n");
- printf("===================\n\n");
-
- printf("=== Importing RSA keypair === \n");
- keymaster_key_blob_t key;
- keymaster_blob_t private_key = {rsa_privkey_pk8_der, rsa_privkey_pk8_der_len};
- int error = device->import_key(&rsa_param_set, KM_KEY_FORMAT_PKCS8, &private_key, &key, nullptr);
- if (error != KM_ERROR_OK) {
- printf("Error importing RSA key: %d\n\n", error);
- return false;
- }
- std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
-
- printf("=== Signing with imported RSA key ===\n");
- size_t message_len = 1024 / 8;
- std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
- memset(message.get(), 'a', message_len);
- keymaster_blob_t input = {message.get(), message_len}, signature;
-
- if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
- printf("Error signing data with imported RSA key\n\n");
- return false;
- }
- std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
-
- printf("=== Verifying with imported RSA key === \n");
- if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
- printf("Error verifying data with imported RSA key\n\n");
- return false;
- }
-
- printf("\n");
- return true;
-}
-
-static bool test_rsa(TrustyKeymasterDevice* device) {
- printf("============\n");
- printf("= RSA Test =\n");
- printf("============\n\n");
-
- printf("=== Generating RSA key pair ===\n");
- keymaster_key_blob_t key;
- int error = device->generate_key(&rsa_param_set, &key, nullptr);
- if (error != KM_ERROR_OK) {
- printf("Error generating RSA key pair: %d\n\n", error);
- return false;
- }
- std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
-
- printf("=== Signing with RSA key === \n");
- size_t message_len = 1024 / 8;
- std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
- memset(message.get(), 'a', message_len);
- keymaster_blob_t input = {message.get(), message_len}, signature;
-
- if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
- printf("Error signing data with RSA key\n\n");
- return false;
- }
- std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
-
- printf("=== Verifying with RSA key === \n");
- if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
- printf("Error verifying data with RSA key\n\n");
- return false;
- }
-
- printf("=== Exporting RSA public key ===\n");
- keymaster_blob_t exported_key;
- error = device->export_key(KM_KEY_FORMAT_X509, &key, nullptr, nullptr, &exported_key);
- if (error != KM_ERROR_OK) {
- printf("Error exporting RSA public key: %d\n\n", error);
- return false;
- }
-
- printf("=== Verifying with exported key ===\n");
- const uint8_t* tmp = exported_key.data;
- std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
- d2i_PUBKEY(NULL, &tmp, exported_key.data_length));
- std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
- if (EVP_PKEY_verify_init(ctx.get()) != 1) {
- printf("Error initializing openss EVP context\n\n");
- return false;
- }
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
- printf("Exported key was the wrong type?!?\n\n");
- return false;
- }
-
- EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
- if (EVP_PKEY_verify(ctx.get(), signature.data, signature.data_length, message.get(),
- message_len) != 1) {
- printf("Verification with exported pubkey failed.\n\n");
- return false;
- } else {
- printf("Verification succeeded\n");
- }
-
- printf("\n");
- return true;
-}
-
-static bool test_import_ecdsa(TrustyKeymasterDevice* device) {
- printf("=====================\n");
- printf("= ECDSA Import Test =\n");
- printf("=====================\n\n");
-
- printf("=== Importing ECDSA keypair === \n");
- keymaster_key_blob_t key;
- keymaster_blob_t private_key = {ec_privkey_pk8_der, ec_privkey_pk8_der_len};
- int error = device->import_key(&ec_param_set, KM_KEY_FORMAT_PKCS8, &private_key, &key, nullptr);
- if (error != KM_ERROR_OK) {
- printf("Error importing ECDSA key: %d\n\n", error);
- return false;
- }
- std::unique_ptr<const uint8_t[]> deleter(key.key_material);
-
- printf("=== Signing with imported ECDSA key ===\n");
- size_t message_len = 30 /* arbitrary */;
- std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
- memset(message.get(), 'a', message_len);
- keymaster_blob_t input = {message.get(), message_len}, signature;
-
- if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
- printf("Error signing data with imported ECDSA key\n\n");
- return false;
- }
- std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
-
- printf("=== Verifying with imported ECDSA key === \n");
- if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
- printf("Error verifying data with imported ECDSA key\n\n");
- return false;
- }
-
- printf("\n");
- return true;
-}
-
-static bool test_ecdsa(TrustyKeymasterDevice* device) {
- printf("==============\n");
- printf("= ECDSA Test =\n");
- printf("==============\n\n");
-
- printf("=== Generating ECDSA key pair ===\n");
- keymaster_key_blob_t key;
- int error = device->generate_key(&ec_param_set, &key, nullptr);
- if (error != KM_ERROR_OK) {
- printf("Error generating ECDSA key pair: %d\n\n", error);
- return false;
- }
- std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
-
- printf("=== Signing with ECDSA key === \n");
- size_t message_len = 30 /* arbitrary */;
- std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
- memset(message.get(), 'a', message_len);
- keymaster_blob_t input = {message.get(), message_len}, signature;
-
- if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
- printf("Error signing data with ECDSA key\n\n");
- return false;
- }
- std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
-
- printf("=== Verifying with ECDSA key === \n");
- if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
- printf("Error verifying data with ECDSA key\n\n");
- return false;
- }
-
- printf("=== Exporting ECDSA public key ===\n");
- keymaster_blob_t exported_key;
- error = device->export_key(KM_KEY_FORMAT_X509, &key, nullptr, nullptr, &exported_key);
- if (error != KM_ERROR_OK) {
- printf("Error exporting ECDSA public key: %d\n\n", error);
- return false;
- }
-
- printf("=== Verifying with exported key ===\n");
- const uint8_t* tmp = exported_key.data;
- std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
- d2i_PUBKEY(NULL, &tmp, exported_key.data_length));
- std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
- if (EVP_PKEY_verify_init(ctx.get()) != 1) {
- printf("Error initializing openssl EVP context\n\n");
- return false;
- }
- if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
- printf("Exported key was the wrong type?!?\n\n");
- return false;
- }
-
- if (EVP_PKEY_verify(ctx.get(), signature.data, signature.data_length, message.get(),
- message_len) != 1) {
- printf("Verification with exported pubkey failed.\n\n");
- return false;
- } else {
- printf("Verification succeeded\n");
- }
-
- printf("\n");
- return true;
-}
-
-int main(void) {
- TrustyKeymasterDevice device(NULL);
- keymaster::ConfigureDevice(reinterpret_cast<keymaster2_device_t*>(&device));
- if (device.session_error() != KM_ERROR_OK) {
- printf("Failed to initialize Trusty session: %d\n", device.session_error());
- return 1;
- }
- printf("Trusty session initialized\n");
-
- bool success = true;
- success &= test_rsa(&device);
- success &= test_import_rsa(&device);
- success &= test_ecdsa(&device);
- success &= test_import_ecdsa(&device);
-
- if (success) {
- printf("\nTESTS PASSED!\n");
- } else {
- printf("\n!!!!TESTS FAILED!!!\n");
- }
-
- return success ? 0 : 1;
-}
diff --git a/watchdogd/Android.bp b/watchdogd/Android.bp
new file mode 100644
index 0000000..0fbc33c
--- /dev/null
+++ b/watchdogd/Android.bp
@@ -0,0 +1,14 @@
+cc_binary {
+ name: "watchdogd",
+ recovery_available: true,
+ srcs: ["watchdogd.cpp"],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ shared_libs: ["libbase"],
+ sanitize: {
+ misc_undefined: ["signed-integer-overflow"],
+ },
+}
diff --git a/init/watchdogd.cpp b/watchdogd/watchdogd.cpp
similarity index 79%
rename from init/watchdogd.cpp
rename to watchdogd/watchdogd.cpp
index e03a2c3..5dc41e6 100644
--- a/init/watchdogd.cpp
+++ b/watchdogd/watchdogd.cpp
@@ -23,16 +23,9 @@
#include <android-base/logging.h>
-#ifdef _INIT_INIT_H
-#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
-#endif
-
#define DEV_NAME "/dev/watchdog"
-namespace android {
-namespace init {
-
-int watchdogd_main(int argc, char **argv) {
+int main(int argc, char** argv) {
android::base::InitLogging(argv, &android::base::KernelLogger);
int interval = 10;
@@ -43,7 +36,7 @@
LOG(INFO) << "watchdogd started (interval " << interval << ", margin " << margin << ")!";
- int fd = open(DEV_NAME, O_RDWR|O_CLOEXEC);
+ int fd = open(DEV_NAME, O_RDWR | O_CLOEXEC);
if (fd == -1) {
PLOG(ERROR) << "Failed to open " << DEV_NAME;
return 1;
@@ -63,9 +56,8 @@
interval = 1;
}
LOG(WARNING) << "Adjusted interval to timeout returned by driver: "
- << "timeout " << timeout
- << ", interval " << interval
- << ", margin " << margin;
+ << "timeout " << timeout << ", interval " << interval << ", margin "
+ << margin;
}
}
@@ -74,6 +66,3 @@
sleep(interval);
}
}
-
-} // namespace init
-} // namespace android