Merge "Remove the mount points defined in skip_mount.cfg from ReadDefaultFstab()"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index ebe5f4a..6f6481f 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -80,3 +80,5 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/sbin/charger)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/sbin/charger)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/sbin)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/sbin)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index e417f05..2dd22b3 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -280,6 +280,9 @@
} else if (type == "sideload") {
D("setting connection_state to kCsSideload");
t->SetConnectionState(kCsSideload);
+ } else if (type == "rescue") {
+ D("setting connection_state to kCsRescue");
+ t->SetConnectionState(kCsRescue);
} else {
D("setting connection_state to kCsHost");
t->SetConnectionState(kCsHost);
diff --git a/adb/adb.h b/adb/adb.h
index c60dcbc..3a6f059 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -107,6 +107,7 @@
kCsHost,
kCsRecovery,
kCsSideload,
+ kCsRescue,
};
inline bool ConnectionStateIsOnline(ConnectionState state) {
@@ -116,6 +117,7 @@
case kCsHost:
case kCsRecovery:
case kCsSideload:
+ case kCsRescue:
return true;
default:
return false;
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 43a3e5e..552df41 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -190,7 +190,7 @@
"scripting:\n"
" wait-for[-TRANSPORT]-STATE\n"
" wait for device to be in the given state\n"
- " STATE: device, recovery, sideload, bootloader, or disconnect\n"
+ " STATE: device, recovery, rescue, sideload, bootloader, or disconnect\n"
" TRANSPORT: usb, local, or any [default=any]\n"
" get-state print offline | bootloader | device\n"
" get-serialno print <serial-number>\n"
@@ -838,26 +838,25 @@
#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
-/*
- * The sideload-host protocol serves the data in a file (given on the
- * command line) to the client, using a simple protocol:
- *
- * - The connect message includes the total number of bytes in the
- * file and a block size chosen by us.
- *
- * - The other side sends the desired block number as eight decimal
- * digits (eg "00000023" for block 23). Blocks are numbered from
- * zero.
- *
- * - We send back the data of the requested block. The last block is
- * likely to be partial; when the last block is requested we only
- * send the part of the block that exists, it's not padded up to the
- * block size.
- *
- * - When the other side sends "DONEDONE" instead of a block number,
- * we hang up.
- */
-static int adb_sideload_host(const char* filename) {
+// Connects to the sideload / rescue service on the device (served by minadbd) and sends over the
+// data in an OTA package.
+//
+// It uses a simple protocol as follows.
+//
+// - The connect message includes the total number of bytes in the file and a block size chosen by
+// us.
+//
+// - The other side sends the desired block number as eight decimal digits (e.g. "00000023" for
+// block 23). Blocks are numbered from zero.
+//
+// - We send back the data of the requested block. The last block is likely to be partial; when the
+// last block is requested we only send the part of the block that exists, it's not padded up to
+// the block size.
+//
+// - When the other side sends "DONEDONE" or "FAILFAIL" instead of a block number, we have done all
+// the data transfer.
+//
+static int adb_sideload_install(const char* filename, bool rescue_mode) {
// TODO: use a LinePrinter instead...
struct stat sb;
if (stat(filename, &sb) == -1) {
@@ -870,14 +869,18 @@
return -1;
}
- std::string service =
- android::base::StringPrintf("sideload-host:%" PRId64 ":%d",
- static_cast<int64_t>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
+ std::string service = android::base::StringPrintf(
+ "%s:%" PRId64 ":%d", rescue_mode ? "rescue-install" : "sideload-host",
+ static_cast<int64_t>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
std::string error;
unique_fd device_fd(adb_connect(service, &error));
if (device_fd < 0) {
fprintf(stderr, "adb: sideload connection failed: %s\n", error.c_str());
+ if (rescue_mode) {
+ return -1;
+ }
+
// If this is a small enough package, maybe this is an older device that doesn't
// support sideload-host. Try falling back to the older (<= K) sideload method.
if (sb.st_size > INT_MAX) {
@@ -901,10 +904,14 @@
}
buf[8] = '\0';
- if (strcmp("DONEDONE", buf) == 0) {
+ if (strcmp(kSideloadServiceExitSuccess, buf) == 0 ||
+ strcmp(kSideloadServiceExitFailure, buf) == 0) {
printf("\rTotal xfer: %.2fx%*s\n",
static_cast<double>(xfer) / (sb.st_size ? sb.st_size : 1),
static_cast<int>(strlen(filename) + 10), "");
+ if (strcmp(kSideloadServiceExitFailure, buf) == 0) {
+ return 1;
+ }
return 0;
}
@@ -1037,11 +1044,12 @@
}
if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" &&
- components[3] != "recovery" && components[3] != "sideload" &&
+ components[3] != "recovery" && components[3] != "rescue" && components[3] != "sideload" &&
components[3] != "disconnect") {
fprintf(stderr,
"adb: unknown state %s; "
- "expected 'any', 'bootloader', 'device', 'recovery', 'sideload', or 'disconnect'\n",
+ "expected 'any', 'bootloader', 'device', 'recovery', 'rescue', 'sideload', or "
+ "'disconnect'\n",
components[3].c_str());
return false;
}
@@ -1627,11 +1635,25 @@
return adb_kill_server() ? 0 : 1;
} else if (!strcmp(argv[0], "sideload")) {
if (argc != 2) error_exit("sideload requires an argument");
- if (adb_sideload_host(argv[1])) {
+ if (adb_sideload_install(argv[1], false /* rescue_mode */)) {
return 1;
} else {
return 0;
}
+ } else if (!strcmp(argv[0], "rescue")) {
+ // adb rescue getprop <prop>
+ // adb rescue install <filename>
+ if (argc != 3) error_exit("rescue requires two arguments");
+ if (!strcmp(argv[1], "getprop")) {
+ return adb_connect_command(android::base::StringPrintf("rescue-getprop:%s", argv[2]));
+ } else if (!strcmp(argv[1], "install")) {
+ if (adb_sideload_install(argv[2], true /* rescue_mode */) != 0) {
+ return 1;
+ }
+ } else {
+ error_exit("invalid rescue argument");
+ }
+ return 0;
} else if (!strcmp(argv[0], "tcpip")) {
if (argc != 2) error_exit("tcpip requires an argument");
int port;
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index e9d9c63..3c8f393 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -406,11 +406,16 @@
strerror(errno));
return false;
}
- // Raw subprocess + shell protocol allows for splitting stderr.
- if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) {
- *error = android::base::StringPrintf("failed to create socketpair for stderr: %s",
- strerror(errno));
- return false;
+ if (protocol_ == SubprocessProtocol::kShell) {
+ // Shell protocol allows for splitting stderr.
+ if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) {
+ *error = android::base::StringPrintf("failed to create socketpair for stderr: %s",
+ strerror(errno));
+ return false;
+ }
+ } else {
+ // Raw protocol doesn't support multiple output streams, so combine stdout and stderr.
+ child_stderr_sfd.reset(dup(child_stdinout_sfd));
}
D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(),
diff --git a/adb/daemon/shell_service_test.cpp b/adb/daemon/shell_service_test.cpp
index 323bcec..dc79d12 100644
--- a/adb/daemon/shell_service_test.cpp
+++ b/adb/daemon/shell_service_test.cpp
@@ -35,7 +35,6 @@
static void SetUpTestCase() {
// This is normally done in main.cpp.
saved_sigpipe_handler_ = signal(SIGPIPE, SIG_IGN);
-
}
static void TearDownTestCase() {
@@ -49,26 +48,32 @@
SubprocessProtocol protocol);
void CleanupTestSubprocess();
- virtual void TearDown() override {
- void CleanupTestSubprocess();
- }
+ void StartTestCommandInProcess(std::string name, Command command, SubprocessProtocol protocol);
+
+ virtual void TearDown() override { CleanupTestSubprocess(); }
static sighandler_t saved_sigpipe_handler_;
- unique_fd subprocess_fd_;
+ unique_fd command_fd_;
};
sighandler_t ShellServiceTest::saved_sigpipe_handler_ = nullptr;
void ShellServiceTest::StartTestSubprocess(
const char* command, SubprocessType type, SubprocessProtocol protocol) {
- subprocess_fd_ = StartSubprocess(command, nullptr, type, protocol);
- ASSERT_TRUE(subprocess_fd_ >= 0);
+ command_fd_ = StartSubprocess(command, nullptr, type, protocol);
+ ASSERT_TRUE(command_fd_ >= 0);
}
void ShellServiceTest::CleanupTestSubprocess() {
}
+void ShellServiceTest::StartTestCommandInProcess(std::string name, Command command,
+ SubprocessProtocol protocol) {
+ command_fd_ = StartCommandInProcess(std::move(name), std::move(command), protocol);
+ ASSERT_TRUE(command_fd_ >= 0);
+}
+
namespace {
// Reads raw data from |fd| until it closes or errors.
@@ -93,7 +98,7 @@
stdout->clear();
stderr->clear();
- ShellProtocol* protocol = new ShellProtocol(fd);
+ auto protocol = std::make_unique<ShellProtocol>(fd);
while (protocol->Read()) {
switch (protocol->id()) {
case ShellProtocol::kIdStdout:
@@ -111,7 +116,6 @@
ADD_FAILURE() << "Unidentified packet ID: " << protocol->id();
}
}
- delete protocol;
return exit_code;
}
@@ -154,7 +158,7 @@
// [ -t 0 ] == 0 means we have a terminal (PTY). Even when requesting a raw subprocess, without
// the shell protocol we should always force a PTY to ensure proper cleanup.
- ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"});
+ ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"});
}
// Tests a PTY subprocess with no protocol.
@@ -165,7 +169,7 @@
SubprocessType::kPty, SubprocessProtocol::kNone));
// [ -t 0 ] == 0 means we have a terminal (PTY).
- ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"});
+ ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"});
}
// Tests a raw subprocess with the shell protocol.
@@ -175,7 +179,7 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string stdout, stderr;
- EXPECT_EQ(24, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(24, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo", "baz"});
ExpectLinesEqual(stderr, {"bar"});
}
@@ -189,7 +193,7 @@
// PTY always combines stdout and stderr but the shell protocol should
// still give us an exit code.
std::string stdout, stderr;
- EXPECT_EQ(50, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(50, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo", "bar", "baz"});
ExpectLinesEqual(stderr, {});
}
@@ -204,7 +208,7 @@
"echo --${TEST_STR}--",
"exit"};
- ShellProtocol* protocol = new ShellProtocol(subprocess_fd_);
+ ShellProtocol* protocol = new ShellProtocol(command_fd_);
for (std::string command : commands) {
// Interactive shell requires a newline to complete each command.
command.push_back('\n');
@@ -214,7 +218,7 @@
delete protocol;
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
// An unpredictable command prompt makes parsing exact output difficult but
// it should at least contain echoed input and the expected output.
for (const char* command : commands) {
@@ -230,14 +234,14 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string input = "foo\nbar";
- ShellProtocol* protocol = new ShellProtocol(subprocess_fd_);
+ ShellProtocol* protocol = new ShellProtocol(command_fd_);
memcpy(protocol->data(), input.data(), input.length());
ASSERT_TRUE(protocol->Write(ShellProtocol::kIdStdin, input.length()));
ASSERT_TRUE(protocol->Write(ShellProtocol::kIdCloseStdin, 0));
delete protocol;
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo", "barTEST_DONE"});
ExpectLinesEqual(stderr, {});
}
@@ -249,7 +253,7 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {});
ExpectLinesEqual(stderr, {"bar"});
}
@@ -261,7 +265,56 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo"});
ExpectLinesEqual(stderr, {});
}
+
+// Tests an inprocess command with no protocol.
+TEST_F(ShellServiceTest, RawNoProtocolInprocess) {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestCommandInProcess("123",
+ [](auto args, auto in, auto out, auto err) -> int {
+ EXPECT_EQ("123", args);
+ char input[10];
+ EXPECT_TRUE(ReadFdExactly(in, input, 2));
+ input[2] = 0;
+ EXPECT_STREQ("in", input);
+ WriteFdExactly(out, "out\n");
+ WriteFdExactly(err, "err\n");
+ return 0;
+ },
+ SubprocessProtocol::kNone));
+
+ WriteFdExactly(command_fd_, "in");
+ ExpectLinesEqual(ReadRaw(command_fd_), {"out", "err"});
+}
+
+// Tests an inprocess command with the shell protocol.
+TEST_F(ShellServiceTest, RawShellProtocolInprocess) {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestCommandInProcess("321",
+ [](auto args, auto in, auto out, auto err) -> int {
+ EXPECT_EQ("321", args);
+ char input[10];
+ EXPECT_TRUE(ReadFdExactly(in, input, 2));
+ input[2] = 0;
+ EXPECT_STREQ("in", input);
+ WriteFdExactly(out, "out\n");
+ WriteFdExactly(err, "err\n");
+ return 0;
+ },
+ SubprocessProtocol::kShell));
+
+ {
+ auto write_protocol = std::make_unique<ShellProtocol>(command_fd_);
+ memcpy(write_protocol->data(), "in", 2);
+ write_protocol->Write(ShellProtocol::kIdStdin, 2);
+ }
+
+ std::string stdout, stderr;
+ // For in-process commands the exit code is always the default (1).
+ EXPECT_EQ(1, ReadShellProtocol(command_fd_, &stdout, &stderr));
+ ExpectLinesEqual(stdout, {"out"});
+ ExpectLinesEqual(stderr, {"err"});
+}
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 8c33ca5..3b29ab5 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -57,11 +57,12 @@
// We can't find out whether we have support for AIO on ffs endpoints until we submit a read.
static std::optional<bool> gFfsAioSupported;
+// Not all USB controllers support operations larger than 16k, so don't go above that.
static constexpr size_t kUsbReadQueueDepth = 32;
-static constexpr size_t kUsbReadSize = 8 * PAGE_SIZE;
+static constexpr size_t kUsbReadSize = 4 * PAGE_SIZE;
static constexpr size_t kUsbWriteQueueDepth = 32;
-static constexpr size_t kUsbWriteSize = 8 * PAGE_SIZE;
+static constexpr size_t kUsbWriteSize = 4 * PAGE_SIZE;
static const char* to_string(enum usb_functionfs_event_type type) {
switch (type) {
diff --git a/adb/services.cpp b/adb/services.cpp
index cf346ba..335ffc4 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -227,6 +227,8 @@
sinfo->state = kCsDevice;
} else if (name == "-recovery") {
sinfo->state = kCsRecovery;
+ } else if (name == "-rescue") {
+ sinfo->state = kCsRescue;
} else if (name == "-sideload") {
sinfo->state = kCsSideload;
} else if (name == "-bootloader") {
diff --git a/adb/services.h b/adb/services.h
index 0ce25ba..8f3919b 100644
--- a/adb/services.h
+++ b/adb/services.h
@@ -23,5 +23,9 @@
constexpr char kShellServiceArgPty[] = "pty";
constexpr char kShellServiceArgShellProtocol[] = "v2";
+// Special flags sent by minadbd that indicate the end of sideload transfer and install result.
+constexpr char kSideloadServiceExitSuccess[] = "DONEDONE";
+constexpr char kSideloadServiceExitFailure[] = "FAILFAIL";
+
unique_fd create_service_thread(const char* service_name, std::function<void(unique_fd)> func);
#endif // SERVICES_H_
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 15c3a9a..841865a 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -1012,6 +1012,8 @@
return "host";
case kCsRecovery:
return "recovery";
+ case kCsRescue:
+ return "rescue";
case kCsNoPerm:
return UsbNoPermissionsShortHelpText();
case kCsSideload:
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 71d3ecb..cb09433 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -25,6 +25,8 @@
# Best guess to an average device's reboot time, refined as tests return
DURATION_DEFAULT=45
STOP_ON_FAILURE=false
+progname="${0##*/}"
+progpath="${0%${progname}}"
# Helper functions
@@ -42,11 +44,40 @@
adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
}
+[ "USAGE: adb_sh <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
+
+Returns: true if the command succeeded" ]
+adb_sh() {
+ local args=
+ for i in "${@}"; do
+ [ -z "${args}" ] || args="${args} "
+ if [ X"${i}" != X"${i#\'}" ]; then
+ args="${args}${i}"
+ elif [ X"${i}" != X"${i#*\\}" ]; then
+ args="${args}`echo ${i} | sed 's/\\\\/\\\\\\\\/g'`"
+ elif [ X"${i}" != X"${i#* }" ]; then
+ args="${args}'${i}'"
+ elif [ X"${i}" != X"${i#*${TAB}}" ]; then
+ args="${args}'${i}'"
+ else
+ args="${args}${i}"
+ fi
+ done
+ adb shell "${args}"
+}
+
+[ "USAGE: adb_su <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
+
+Returns: true if the command running as root succeeded" ]
+adb_su() {
+ adb_sh su root "${@}"
+}
+
[ "USAGE: hasPstore
Returns: true if device (likely) has pstore data" ]
hasPstore() {
- if inAdb && [ 0 -eq `adb shell su root ls /sys/fs/pstore | wc -l` ]; then
+ if inAdb && [ 0 -eq `adb_su ls /sys/fs/pstore </dev/null | wc -l` ]; then
false
fi
}
@@ -55,7 +86,7 @@
Returns the property value" ]
get_property() {
- adb shell getprop ${1} 2>&1 </dev/null
+ adb_sh getprop ${1} 2>&1 </dev/null
}
[ "USAGE: isDebuggable
@@ -89,18 +120,18 @@
Returns: true if device supports and set boot reason injection" ]
setBootloaderBootReason() {
inAdb || ( echo "ERROR: device not in adb mode." >&2 ; false ) || return 1
- if [ -z "`adb shell ls /etc/init/bootstat-debug.rc 2>/dev/null`" ]; then
+ if [ -z "`adb_sh ls /etc/init/bootstat-debug.rc 2>/dev/null </dev/null`" ]; then
echo "ERROR: '${TEST}' test requires /etc/init/bootstat-debug.rc" >&2
return 1
fi
checkDebugBuild || return 1
- if adb shell su root "cat /proc/cmdline | tr '\\0 ' '\\n\\n'" |
+ if adb_su "cat /proc/cmdline | tr '\\0 ' '\\n\\n'" </dev/null |
grep '^androidboot[.]bootreason=[^ ]' >/dev/null; then
echo "ERROR: '${TEST}' test requires a device with a bootloader that" >&2
echo " does not set androidboot.bootreason kernel parameter." >&2
return 1
fi
- adb shell su root setprop persist.test.boot.reason "'${1}'" 2>/dev/null
+ adb_su setprop persist.test.boot.reason "'${1}'" 2>/dev/null </dev/null
test_reason="`get_property persist.test.boot.reason`"
if [ X"${test_reason}" != X"${1}" ]; then
echo "ERROR: can not set persist.test.boot.reason to '${1}'." >&2
@@ -299,7 +330,14 @@
return ${save_ret}
}
-[ "USAGE: report_bootstat_logs <expected> ...
+[ "USAGE: adb_date >/dev/stdout
+
+Returns: report device epoch time (suitable for logcat -t)" ]
+adb_date() {
+ adb_sh date +%s.%N </dev/null
+}
+
+[ "USAGE: report_bootstat_logs [-t<timestamp>] <expected> ...
if not prefixed with a minus (-), <expected> will become a series of expected
matches:
@@ -314,8 +352,11 @@
report_bootstat_logs() {
save_ret=${?}
match=
+ timestamp=-d
for i in "${@}"; do
- if [ X"${i}" != X"${i#-}" ] ; then
+ if [ X"${i}" != X"${i#-t}" ]; then
+ timestamp="${i}"
+ elif [ X"${i}" != X"${i#-}" ]; then
match="${match}
${i#-}"
else
@@ -323,12 +364,13 @@
bootstat: Canonical boot reason: ${i}"
fi
done
- adb logcat -b all -d |
+ adb logcat -b all ${timestamp} |
grep bootstat[^e] |
grep -v -F "bootstat: Service started: /system/bin/bootstat --record_boot_complete${match}
bootstat: Failed to read /data/misc/bootstat/post_decrypt_time_elapsed: No such file or directory
bootstat: Failed to parse boot time record: /data/misc/bootstat/post_decrypt_time_elapsed
bootstat: Service started: /system/bin/bootstat --record_boot_reason
+bootstat: Service started: /system/bin/bootstat --set_system_boot_reason
bootstat: Service started: /system/bin/bootstat --record_time_since_factory_reset
bootstat: Service started: /system/bin/bootstat -l
bootstat: Service started: /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
@@ -341,6 +383,8 @@
init : processing action (post-fs-data) from (/system/etc/init/bootstat.rc
init : processing action (boot) from (/system/etc/init/bootstat.rc
init : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc
+init : processing action (ro.boot.bootreason=* && post-fs) from (/system/etc/init/bootstat.rc
+init : processing action (zygote-start) from (/system/etc/init/bootstat.rc
init : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from (/system/etc/init/bootstat.rc
(/system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
(/system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
@@ -355,6 +399,8 @@
(/system/bin/bootstat --record_boot_reason)' (pid${SPACE}
(/system/bin/bootstat --record_time_since_factory_reset)'...
(/system/bin/bootstat --record_time_since_factory_reset)' (pid${SPACE}
+ (/system/bin/bootstat --set_system_boot_reason)'...
+ (/system/bin/bootstat --set_system_boot_reason)' (pid${SPACE}
(/system/bin/bootstat -l)'...
(/system/bin/bootstat -l)' (pid " |
grep -v 'bootstat: Unknown boot reason: $' # Hikey Special
@@ -613,7 +659,7 @@
test_optional_ota() {
checkDebugBuild || return
duration_test
- adb shell su root touch /data/misc/bootstat/build_date >&2
+ adb_su touch /data/misc/bootstat/build_date >&2 </dev/null
adb reboot ota
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,ota
@@ -679,7 +725,7 @@
test_factory_reset() {
checkDebugBuild || return
duration_test
- adb shell su root rm /data/misc/bootstat/build_date >&2
+ adb_su rm /data/misc/bootstat/build_date >&2 </dev/null
adb reboot >&2
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
@@ -715,7 +761,7 @@
wait_for_screen
( exit ${save_ret} ) # because one can not just do ?=${save_ret}
EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
- EXPECT_PROPERTY sys.boot.reason.last ""
+ EXPECT_PROPERTY sys.boot.reason.last "\(\|bootloader\)"
check_boilerplate_properties
report_bootstat_logs reboot,factory_reset bootloader \
"-bootstat: Failed to read /data/misc/bootstat/last_boot_time_utc: No such file or directory" \
@@ -766,12 +812,12 @@
enterPstore
# Send it _many_ times to combat devices with flakey pstore
for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
- echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null
+ echo 'healthd: battery l=2 ' | adb_su tee /dev/kmsg >/dev/null
done
adb reboot cold >&2
adb wait-for-device
wait_for_screen
- adb shell su root \
+ adb_su </dev/null \
cat /proc/fs/pstore/console-ramoops \
/proc/fs/pstore/console-ramoops-0 2>/dev/null |
grep 'healthd: battery l=' |
@@ -780,7 +826,7 @@
if ! EXPECT_PROPERTY sys.boot.reason reboot,battery >/dev/null 2>/dev/null; then
# retry
for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
- echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null
+ echo 'healthd: battery l=2 ' | adb_su tee /dev/kmsg >/dev/null
done
adb reboot cold >&2
adb wait-for-device
@@ -806,7 +852,7 @@
test_optional_battery() {
duration_test ">60"
echo " power on request" >&2
- adb shell setprop sys.powerctl shutdown,battery
+ adb_sh setprop sys.powerctl shutdown,battery </dev/null
sleep 5
echo -n "WARNING: Please power device back up, waiting ... " >&2
wait_for_screen -n >&2
@@ -827,7 +873,7 @@
test_optional_battery_thermal() {
duration_test ">60"
echo " power on request" >&2
- adb shell setprop sys.powerctl shutdown,thermal,battery
+ adb_sh setprop sys.powerctl shutdown,thermal,battery </dev/null
sleep 5
echo -n "WARNING: Please power device back up, waiting ... " >&2
wait_for_screen -n >&2
@@ -866,7 +912,7 @@
panic_msg="\(kernel_panic,sysrq\|kernel_panic\)"
pstore_ok=true
fi
- echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
+ echo c | adb_su tee /proc/sysrq-trigger >/dev/null
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
@@ -893,8 +939,8 @@
panic_msg="\(kernel_panic,sysrq,test\|kernel_panic\)"
pstore_ok=true
fi
- echo "SysRq : Trigger a crash : 'test'" | adb shell su root tee /dev/kmsg
- echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
+ echo "SysRq : Trigger a crash : 'test'" | adb_su tee /dev/kmsg
+ echo c | adb_su tee /proc/sysrq-trigger >/dev/null
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
@@ -924,7 +970,7 @@
pstore_ok=true
fi
echo "Kernel panic - not syncing: hung_task: blocked tasks" |
- adb shell su root tee /dev/kmsg
+ adb_su tee /dev/kmsg
adb reboot warm
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
@@ -956,7 +1002,7 @@
test_thermal_shutdown() {
duration_test ">60"
echo " power on request" >&2
- adb shell setprop sys.powerctl shutdown,thermal
+ adb_sh setprop sys.powerctl shutdown,thermal </dev/null
sleep 5
echo -n "WARNING: Please power device back up, waiting ... " >&2
wait_for_screen -n >&2
@@ -977,7 +1023,7 @@
test_userrequested_shutdown() {
duration_test ">60"
echo " power on request" >&2
- adb shell setprop sys.powerctl shutdown,userrequested
+ adb_sh setprop sys.powerctl shutdown,userrequested </dev/null
sleep 5
echo -n "WARNING: Please power device back up, waiting ... " >&2
wait_for_screen -n >&2
@@ -996,7 +1042,7 @@
- NB: should report reboot,shell" ]
test_shell_reboot() {
duration_test
- adb shell reboot
+ adb_sh reboot </dev/null
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,shell
EXPECT_PROPERTY sys.boot.reason.last reboot,shell
@@ -1032,7 +1078,7 @@
test_optional_rescueparty() {
blind_reboot_test
echo "WARNING: legacy devices are allowed to fail following ro.boot.bootreason result" >&2
- EXPECT_PROPERTY ro.boot.bootreason reboot,rescueparty
+ EXPECT_PROPERTY ro.boot.bootreason '\(reboot\|reboot,rescueparty\)'
}
[ "USAGE: test_Its_Just_So_Hard_reboot
@@ -1049,7 +1095,7 @@
else
duration_test `expr ${DURATION_DEFAULT} + ${DURATION_DEFAULT}`
fi
- adb shell 'reboot "Its Just So Hard"'
+ adb_sh 'reboot "Its Just So Hard"' </dev/null
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
EXPECT_PROPERTY sys.boot.reason.last reboot,its_just_so_hard
@@ -1146,7 +1192,113 @@
run_bootloader
}
-[ "USAGE: ${0##*/} [-s SERIAL] [tests]
+[ "USAGE: run_kBootReasonMap [--boot_reason_enum] value expected
+
+bootloader boot reason injection tests:
+- if --boot_reason_enum run bootstat executable for result instead.
+- inject boot reason into sys.boot.reason
+- run bootstat --set_system_boot_reason
+- check for expected enum
+- " ]
+run_kBootReasonMap() {
+ if [ X"--boot_reason_enum" = X"${1}" ]; then
+ shift
+ local sys_expected="${1}"
+ shift
+ local enum_expected="${1}"
+ adb_su bootstat --boot_reason_enum="${sys_expected}" |
+ (
+ local retval=-1
+ while read -r id match; do
+ if [ ${retval} = -1 -a ${enum_expected} = ${id} ]; then
+ retval=0
+ fi
+ if [ ${enum_expected} != ${id} ]; then
+ echo "ERROR: ${enum_expected} ${sys_expected} got ${id} ${match}" >&2
+ retval=1
+ fi
+ done
+ exit ${retval}
+ )
+ return
+ fi
+ local sys_expected="${1}"
+ shift
+ local enum_expected="${1}"
+ adb_su setprop sys.boot.reason "${sys_expected}" </dev/null
+ adb_su bootstat --record_boot_reason </dev/null
+ # Check values
+ EXPECT_PROPERTY sys.boot.reason "${sys_expected}"
+ local retval=${?}
+ local result=`adb_su stat -c %Y /data/misc/bootstat/system_boot_reason </dev/null 2>/dev/null`
+ [ "${enum_expected}" = "${result}" ] ||
+ (
+ [ -n "${result}" ] || result="<nothing>"
+ echo "ERROR: ${enum_expected} ${sys_expected} got ${result}" >&2
+ false
+ ) ||
+ retval=${?}
+ return ${retval}
+}
+
+[ "USAGE: filter_kBootReasonMap </dev/stdin >/dev/stdout
+
+convert any regex expressions into a series of non-regex test strings" ]
+filter_kBootReasonMap() {
+ while read -r id match; do
+ case ${match} in
+ 'reboot,[empty]')
+ echo ${id} # matches b/c of special case
+ echo ${id} reboot,y # matches b/c of regex
+ echo 1 reboot,empty # negative test (ID for unknown is 1)
+ ;;
+ reboot)
+ echo 1 reboo # negative test (ID for unknown is 1)
+ ;;
+ esac
+ echo ${id} "${match}" # matches b/c of exact
+ done
+}
+
+[ "USAGE: test_kBootReasonMap
+
+kBootReasonMap test
+- (wait until screen is up, boot has completed)
+- read bootstat for kBootReasonMap entries and test them all" ]
+test_kBootReasonMap() {
+ local tempfile="`mktemp`"
+ local arg=--boot_reason_enum
+ adb_su bootstat ${arg} </dev/null 2>/dev/null |
+ filter_kBootReasonMap >${tempfile}
+ if [ ! -s "${tempfile}" ]; then
+ wait_for_screen
+ arg=
+ sed -n <${progpath}bootstat.cpp \
+ '/kBootReasonMap = {/,/^};/s/.*{"\([^"]*\)", *\([0-9][0-9]*\)},.*/\2 \1/p' |
+ sed 's/\\\\/\\/g' |
+ filter_kBootReasonMap >${tempfile}
+ fi
+ T=`adb_date`
+ retval=0
+ while read -r enum string; do
+ if [ X"${string}" != X"${string#*[[].[]]}" -o X"${string}" != X"${string#*\\.}" ]; then
+ if [ 'reboot\.empty' != "${string}" ]; then
+ echo "WARNING: regex snuck through filter_kBootReasonMap ${enum} ${string}" >&2
+ enum=1
+ fi
+ fi
+ run_kBootReasonMap ${arg} "${string}" "${enum}" </dev/null || retval=${?}
+ done <${tempfile}
+ rm ${tempfile}
+ ( exit ${retval} )
+ # See filter_kBootReasonMap() for negative tests and add them here too
+ report_bootstat_logs -t${T} \
+ '-bootstat: Service started: bootstat --boot_reason_enum=' \
+ '-bootstat: Unknown boot reason: reboot,empty' \
+ '-bootstat: Unknown boot reason: reboo'
+}
+
+[ "USAGE: ${progname} [-s SERIAL] [tests]...
Mainline executive to run the above tests" ]
@@ -1161,7 +1313,7 @@
if [ X"--macros" != X"${1}" ]; then
if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then
- echo "USAGE: ${0##*/} [-s SERIAL] [tests]"
+ echo "USAGE: ${progname} [-s SERIAL] [tests]..."
echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
exit 0
fi
@@ -1210,7 +1362,7 @@
Its_Just_So_Hard_reboot bootloader_normal bootloader_watchdog \
bootloader_kernel_panic bootloader_oem_powerkey \
bootloader_wdog_reset bootloader_cold bootloader_warm \
- bootloader_hard bootloader_recovery
+ bootloader_hard bootloader_recovery kBootReasonMap
fi
if [ X"nothing" = X"${1}" ]; then
shift 1
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 1ce0ec4..617ea4f 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -89,7 +89,7 @@
}
void ShowHelp(const char* cmd) {
- fprintf(stderr, "Usage: %s [options]\n", cmd);
+ fprintf(stderr, "Usage: %s [options]...\n", cmd);
fprintf(stderr,
"options include:\n"
" -h, --help Show this help\n"
@@ -99,7 +99,8 @@
" --value Optional value to associate with the boot event\n"
" --record_boot_complete Record metrics related to the time for the device boot\n"
" --record_boot_reason Record the reason why the device booted\n"
- " --record_time_since_factory_reset Record the time since the device was reset\n");
+ " --record_time_since_factory_reset Record the time since the device was reset\n"
+ " --boot_reason_enum=<reason> Report the match to the kBootReasonMap table\n");
}
// Constructs a readable, printable string from the givencommand line
@@ -120,9 +121,10 @@
// A mapping from boot reason string, as read from the ro.boot.bootreason
// system property, to a unique integer ID. Viewers of log data dashboards for
// the boot_reason metric may refer to this mapping to discern the histogram
-// values.
+// values. Regex matching, to manage the scale, as a minimum require either
+// [, \ or * to be present in the string to switch to checking.
const std::map<std::string, int32_t> kBootReasonMap = {
- {"empty", kEmptyBootReason},
+ {"reboot,[empty]", kEmptyBootReason},
{"__BOOTSTAT_UNKNOWN__", kUnknownBootReason},
{"normal", 2},
{"recovery", 3},
@@ -314,6 +316,16 @@
return kEmptyBootReason;
}
+ for (const auto& [match, id] : kBootReasonMap) {
+ // Regex matches as a minimum require either [, \ or * to be present.
+ if (match.find_first_of("[\\*") == match.npos) continue;
+ // enforce match from beginning to end
+ auto exact = match;
+ if (exact[0] != '^') exact = "^" + exact;
+ if (exact[exact.size() - 1] != '$') exact = exact + "$";
+ if (std::regex_search(boot_reason, std::regex(exact))) return id;
+ }
+
LOG(INFO) << "Unknown boot reason: " << boot_reason;
return kUnknownBootReason;
}
@@ -1266,6 +1278,19 @@
boot_event_store.AddBootEventWithValue("time_since_factory_reset", time_since_factory_reset);
}
+// List the associated boot reason(s), if arg is nullptr then all.
+void PrintBootReasonEnum(const char* arg) {
+ int value = -1;
+ if (arg != nullptr) {
+ value = BootReasonStrToEnum(arg);
+ }
+ for (const auto& [match, id] : kBootReasonMap) {
+ if ((value < 0) || (value == id)) {
+ printf("%u\t%s\n", id, match.c_str());
+ }
+ }
+}
+
} // namespace
int main(int argc, char** argv) {
@@ -1280,6 +1305,7 @@
static const char boot_complete_str[] = "record_boot_complete";
static const char boot_reason_str[] = "record_boot_reason";
static const char factory_reset_str[] = "record_time_since_factory_reset";
+ static const char boot_reason_enum_str[] = "boot_reason_enum";
static const struct option long_options[] = {
// clang-format off
{ "help", no_argument, NULL, 'h' },
@@ -1291,6 +1317,7 @@
{ boot_complete_str, no_argument, NULL, 0 },
{ boot_reason_str, no_argument, NULL, 0 },
{ factory_reset_str, no_argument, NULL, 0 },
+ { boot_reason_enum_str, optional_argument, NULL, 0 },
{ NULL, 0, NULL, 0 }
// clang-format on
};
@@ -1315,6 +1342,8 @@
RecordBootReason();
} else if (option_name == factory_reset_str) {
RecordFactoryReset();
+ } else if (option_name == boot_reason_enum_str) {
+ PrintBootReasonEnum(optarg);
} else {
LOG(ERROR) << "Invalid option: " << option_name;
}
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 0cf3378..2e226da 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -183,6 +183,12 @@
],
},
},
+
+ product_variables: {
+ debuggable: {
+ cflags: ["-DROOT_POSSIBLE"],
+ },
+ },
}
cc_test {
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 82ba0a1..c608a8c 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -363,6 +363,12 @@
DefuseSignalHandlers();
InstallSigPipeHandler();
+ // There appears to be a bug in the kernel where our death causes SIGHUP to
+ // be sent to our process group if we exit while it has stopped jobs (e.g.
+ // because of wait_for_gdb). Use setsid to create a new process group to
+ // avoid hitting this.
+ setsid();
+
atrace_begin(ATRACE_TAG, "before reparent");
pid_t target_process = getppid();
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index f0bdfbf..3041664 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -193,6 +193,7 @@
fprintf(stderr, " kuser_memory_barrier call kuser_memory_barrier\n");
fprintf(stderr, " kuser_cmpxchg64 call kuser_cmpxchg64\n");
#endif
+ fprintf(stderr, " xom read execute-only memory\n");
fprintf(stderr, "\n");
fprintf(stderr, " LOG_ALWAYS_FATAL call liblog LOG_ALWAYS_FATAL\n");
fprintf(stderr, " LOG_ALWAYS_FATAL_IF call liblog LOG_ALWAYS_FATAL_IF\n");
@@ -314,6 +315,11 @@
} else if (!strcasecmp(arg, "seccomp")) {
set_system_seccomp_filter();
syscall(99999);
+#if defined(__LP64__)
+ } else if (!strcasecmp(arg, "xom")) {
+ // Try to read part of our code, which will fail if XOM is active.
+ printf("*%lx = %lx\n", reinterpret_cast<long>(usage), *reinterpret_cast<long*>(usage));
+#endif
#if defined(__arm__)
} else if (!strcasecmp(arg, "kuser_helper_version")) {
return __kuser_helper_version;
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index bca5e36..598ea85 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -268,8 +268,15 @@
_exit(errno);
}
- // Exit immediately on both sides of the fork.
- // crash_dump is ptracing us, so it'll get to do whatever it wants in between.
+ // crash_dump is ptracing both sides of the fork; it'll let the parent exit,
+ // but keep the orphan stopped to peek at its memory.
+
+ // There appears to be a bug in the kernel where our death causes SIGHUP to
+ // be sent to our process group if we exit while it has stopped jobs (e.g.
+ // because of wait_for_gdb). Use setsid to create a new process group to
+ // avoid hitting this.
+ setsid();
+
_exit(0);
}
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index 94fcfb2..c606970 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -74,10 +74,7 @@
return;
}
- unwinder->SetDisplayBuildID(true);
- for (size_t i = 0; i < unwinder->NumFrames(); i++) {
- _LOG(&log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(i).c_str());
- }
+ log_backtrace(&log, unwinder, " ");
}
void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 7c5304e..f189c45 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -18,6 +18,7 @@
#ifndef _DEBUGGERD_UTILITY_H
#define _DEBUGGERD_UTILITY_H
+#include <inttypes.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/types.h>
@@ -25,7 +26,6 @@
#include <string>
#include <android-base/macros.h>
-#include <backtrace/Backtrace.h>
struct log_t {
// Tombstone file descriptor.
@@ -61,13 +61,24 @@
OPEN_FILES
};
+#if defined(__LP64__)
+#define PRIPTR "016" PRIx64
+typedef uint64_t word_t;
+#else
+#define PRIPTR "08" PRIx64
+typedef uint32_t word_t;
+#endif
+
// Log information onto the tombstone.
void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
namespace unwindstack {
+class Unwinder;
class Memory;
}
+void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix);
+
void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const std::string&);
void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index eed5bd3..3196ce8 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -15,6 +15,7 @@
*/
#include <stdlib.h>
+#include <sys/mman.h>
#include <time.h>
#include <memory>
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 47a7a8f..d1726cd 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <time.h>
@@ -370,13 +371,6 @@
}
}
-void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
- unwinder->SetDisplayBuildID(true);
- for (size_t i = 0; i < unwinder->NumFrames(); i++) {
- _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
- }
-}
-
static void print_register_row(log_t* log,
const std::vector<std::pair<std::string, uint64_t>>& registers) {
std::string output;
@@ -469,7 +463,7 @@
_LOG(log, logtype::THREAD, "Failed to unwind");
} else {
_LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
- dump_backtrace(log, unwinder, " ");
+ log_backtrace(log, unwinder, " ");
_LOG(log, logtype::STACK, "\nstack:\n");
dump_stack(log, unwinder->frames(), unwinder->GetMaps(), unwinder->GetProcessMemory().get());
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index d0c5234..9b2779a 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -35,10 +35,10 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <backtrace/Backtrace.h>
#include <debuggerd/handler.h>
#include <log/log.h>
#include <unwindstack/Memory.h>
+#include <unwindstack/Unwinder.h>
using android::base::unique_fd;
@@ -423,3 +423,22 @@
// Then give up...
return "?";
}
+
+void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
+ if (unwinder->elf_from_memory_not_file()) {
+ _LOG(log, logtype::BACKTRACE,
+ "%sNOTE: Function names and BuildId information is missing for some frames due\n", prefix);
+ _LOG(log, logtype::BACKTRACE,
+ "%sNOTE: to unreadable libraries. For unwinds of apps, only shared libraries\n", prefix);
+ _LOG(log, logtype::BACKTRACE, "%sNOTE: found under the lib/ directory are readable.\n", prefix);
+#if defined(ROOT_POSSIBLE)
+ _LOG(log, logtype::BACKTRACE,
+ "%sNOTE: On this device, run setenforce 0 to make the libraries readable.\n", prefix);
+#endif
+ }
+
+ unwinder->SetDisplayBuildID(true);
+ for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+ _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
+ }
+}
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
index fb51a90..511bd5c 100644
--- a/fastboot/device/usb_client.cpp
+++ b/fastboot/device/usb_client.cpp
@@ -257,7 +257,7 @@
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;
+ return bytes_read_total == 0 ? -1 : bytes_read_total;
}
bytes_read_total += bytes_read_now;
char_data += bytes_read_now;
@@ -278,7 +278,7 @@
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;
+ return bytes_written_total == 0 ? -1 : bytes_written_total;
}
bytes_written_total += bytes_written_now;
char_data += bytes_written_now;
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index c23da01..bc13a8c 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -59,7 +59,7 @@
namespace fastboot {
-int FastBootTest::MatchFastboot(usb_ifc_info* info, const char* local_serial) {
+int FastBootTest::MatchFastboot(usb_ifc_info* info, const std::string& local_serial) {
if (info->ifc_class != 0xff || info->ifc_subclass != 0x42 || info->ifc_protocol != 0x03) {
return -1;
}
@@ -68,8 +68,8 @@
// require matching serial number or device path if requested
// at the command line with the -s option.
- if (local_serial && (strcmp(local_serial, info->serial_number) != 0 &&
- strcmp(local_serial, info->device_path) != 0))
+ if (!local_serial.empty() && local_serial != info->serial_number &&
+ local_serial != info->device_path)
return -1;
return 0;
}
@@ -113,7 +113,9 @@
ASSERT_TRUE(UsbStillAvailible()); // The device disconnected
}
- const auto matcher = [](usb_ifc_info* info) -> int { return MatchFastboot(info, nullptr); };
+ const auto matcher = [](usb_ifc_info* info) -> int {
+ return MatchFastboot(info, device_serial);
+ };
for (int i = 0; i < MAX_USB_TRIES && !transport; i++) {
std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
if (usb)
@@ -172,7 +174,9 @@
;
printf("WAITING FOR DEVICE\n");
// Need to wait for device
- const auto matcher = [](usb_ifc_info* info) -> int { return MatchFastboot(info, nullptr); };
+ const auto matcher = [](usb_ifc_info* info) -> int {
+ return MatchFastboot(info, device_serial);
+ };
while (!transport) {
std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
if (usb) {
@@ -238,6 +242,7 @@
std::string FastBootTest::cb_scratch = "";
std::string FastBootTest::initial_slot = "";
int FastBootTest::serial_port = 0;
+std::string FastBootTest::device_serial = "";
template <bool UNLOCKED>
void ModeTest<UNLOCKED>::SetUp() {
diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h
index 7c8d54d..c71c897 100644
--- a/fastboot/fuzzy_fastboot/fixtures.h
+++ b/fastboot/fuzzy_fastboot/fixtures.h
@@ -43,9 +43,10 @@
class FastBootTest : public testing::Test {
public:
static int serial_port;
+ static std::string device_serial;
static constexpr int MAX_USB_TRIES = 10;
- static int MatchFastboot(usb_ifc_info* info, const char* local_serial = nullptr);
+ static int MatchFastboot(usb_ifc_info* info, const std::string& local_serial = "");
bool UsbStillAvailible();
bool UserSpaceFastboot();
void ReconnectFastbootDevice();
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index a40bc27..ff918a7 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -162,7 +162,7 @@
// Test that USB even works
TEST(USBFunctionality, USBConnect) {
const auto matcher = [](usb_ifc_info* info) -> int {
- return FastBootTest::MatchFastboot(info, nullptr);
+ return FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial);
};
Transport* transport = nullptr;
for (int i = 0; i < FastBootTest::MAX_USB_TRIES && !transport; i++) {
@@ -1738,10 +1738,14 @@
fastboot::GenerateXmlTests(fastboot::config);
}
+ if (args.find("serial") != args.end()) {
+ fastboot::FastBootTest::device_serial = args.at("serial");
+ }
+
setbuf(stdout, NULL); // no buffering
printf("<Waiting for Device>\n");
const auto matcher = [](usb_ifc_info* info) -> int {
- return fastboot::FastBootTest::MatchFastboot(info, nullptr);
+ return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial);
};
Transport* transport = nullptr;
while (!transport) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 045bb48..c1aafda 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1268,6 +1268,46 @@
}
}
+int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab) {
+ AvbUniquePtr avb_handle(nullptr);
+ int ret = FsMgrUmountStatus::SUCCESS;
+ for (auto& current_entry : *fstab) {
+ if (!IsMountPointMounted(current_entry.mount_point)) {
+ continue;
+ }
+
+ if (umount(current_entry.mount_point.c_str()) == -1) {
+ PERROR << "Failed to umount " << current_entry.mount_point;
+ ret |= FsMgrUmountStatus::ERROR_UMOUNT;
+ continue;
+ }
+
+ if (current_entry.fs_mgr_flags.logical) {
+ if (!fs_mgr_update_logical_partition(¤t_entry)) {
+ LERROR << "Could not get logical partition blk_device, skipping!";
+ ret |= FsMgrUmountStatus::ERROR_DEVICE_MAPPER;
+ continue;
+ }
+ }
+
+ if (current_entry.fs_mgr_flags.avb || !current_entry.avb_keys.empty()) {
+ if (!AvbHandle::TearDownAvbHashtree(¤t_entry, true /* wait */)) {
+ LERROR << "Failed to tear down AVB on mount point: " << current_entry.mount_point;
+ ret |= FsMgrUmountStatus::ERROR_VERITY;
+ continue;
+ }
+ } else if ((current_entry.fs_mgr_flags.verify)) {
+ if (!fs_mgr_teardown_verity(¤t_entry, true /* wait */)) {
+ LERROR << "Failed to tear down verified partition on mount point: "
+ << current_entry.mount_point;
+ ret |= FsMgrUmountStatus::ERROR_VERITY;
+ continue;
+ }
+ }
+ }
+ return ret;
+}
+
// wrapper to __mount() and expects a fully prepared fstab_rec,
// unlike fs_mgr_do_mount which does more things with avb / verity etc.
int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point) {
@@ -1655,11 +1695,12 @@
std::string fs_mgr_get_super_partition_name(int slot) {
// Devices upgrading to dynamic partitions are allowed to specify a super
- // partition name, assumed to be A/B (non-A/B retrofit is not supported).
- // For devices launching with dynamic partition support, the partition
- // name must be "super".
+ // partition name. This includes cuttlefish, which is a non-A/B device.
std::string super_partition;
if (fs_mgr_get_boot_config_from_kernel_cmdline("super_partition", &super_partition)) {
+ if (fs_mgr_get_slot_suffix().empty()) {
+ return super_partition;
+ }
std::string suffix;
if (slot == 0) {
suffix = "_a";
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 45cbff3..ee6ffdb 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -193,7 +193,7 @@
timeout_ms, path);
}
-bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
+bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
DeviceMapper& dm = DeviceMapper::Instance();
std::string path;
if (timeout_ms > std::chrono::milliseconds::zero()) {
@@ -206,6 +206,13 @@
LERROR << "Timed out waiting for device path to unlink: " << path;
return false;
}
+ return true;
+}
+
+bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
+ if (!UnmapDevice(name, timeout_ms)) {
+ return false;
+ }
LINFO << "Unmapped logical partition " << name;
return true;
}
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index dea4844..e46e497 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -159,6 +159,9 @@
auto save_errno = errno;
errno = 0;
auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device);
+ if (!has_shared_blocks && (entry->mount_point == "/system")) {
+ has_shared_blocks = fs_mgr_has_shared_blocks("/", entry->blk_device);
+ }
// special case for first stage init for system as root (taimen)
if (!has_shared_blocks && (errno == ENOENT) && (entry->blk_device == "/dev/root")) {
has_shared_blocks = true;
@@ -612,7 +615,9 @@
if (!dm.GetDmDevicePathByName(partition_name, &path)) {
// non-DAP A/B device?
if (fs_mgr_access(super_device)) return "";
- path = kPhysicalDevice + "system" + (slot_number ? "_a" : "_b");
+ auto other_slot = fs_mgr_get_other_slot_suffix();
+ if (other_slot.empty()) return "";
+ path = kPhysicalDevice + "system" + other_slot;
}
}
return scratch_device_cache = path;
@@ -631,7 +636,7 @@
LERROR << mnt_type << " has no mkfs cookbook";
return false;
}
- command += " " + scratch_device;
+ command += " " + scratch_device + " >/dev/null 2>/dev/null </dev/null";
fs_mgr_set_blk_ro(scratch_device, false);
auto ret = system(command.c_str());
if (ret) {
@@ -715,7 +720,7 @@
}
if (changed || partition_create) {
- if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
+ if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 10s,
scratch_device))
return false;
@@ -940,7 +945,7 @@
auto slot_number = fs_mgr_overlayfs_slot_number();
auto super_device = fs_mgr_overlayfs_super_device(slot_number);
const auto partition_name = android::base::Basename(kScratchMountPoint);
- CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
+ CreateLogicalPartition(super_device, slot_number, partition_name, true, 10s,
&scratch_device);
}
mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device,
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 11602ea..70abf5b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -103,3 +103,11 @@
bool fs_mgr_is_ext4(const std::string& blk_device);
bool fs_mgr_is_f2fs(const std::string& blk_device);
+
+bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab, bool wait);
+
+namespace android {
+namespace fs_mgr {
+bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 093d44d..cbe2008 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -371,17 +371,13 @@
continue;
}
}
- PLOG(WARNING) << "failed to remount partition dev:" << blk_device << " mnt:" << mount_point;
- // If errno = EROFS at this point, we are dealing with r/o
+ PLOG(ERROR) << "failed to remount partition dev:" << blk_device << " mnt:" << mount_point;
+ // If errno is EROFS at this point, we are dealing with r/o
// filesystem types like squashfs, erofs or ext4 dedupe. We will
// consider such a device that does not have CONFIG_OVERLAY_FS
- // in the kernel as a misconfigured; except for ext4 dedupe.
- if ((errno == EROFS) && can_reboot) {
- const std::vector<std::string> msg = {"--fsck_unshare_blocks"};
- std::string err;
- if (write_bootloader_message(msg, &err)) reboot(true);
- LOG(ERROR) << "Failed to set bootloader message: " << err;
- errno = EROFS;
+ // in the kernel as a misconfigured.
+ if (errno == EROFS) {
+ LOG(ERROR) << "Consider providing all the dependencies to enable overlayfs";
}
retval = REMOUNT_FAILED;
}
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index c53e866..3f09157 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -44,6 +44,7 @@
#include "fec/io.h"
#include "fs_mgr.h"
+#include "fs_mgr_dm_linear.h"
#include "fs_mgr_priv.h"
// Realistically, this file should be part of the android::fs_mgr namespace;
@@ -882,3 +883,12 @@
return retval;
}
+
+bool fs_mgr_teardown_verity(FstabEntry* entry, bool wait) {
+ const std::string mount_point(basename(entry->mount_point.c_str()));
+ if (!android::fs_mgr::UnmapDevice(mount_point, wait ? 1000ms : 0ms)) {
+ return false;
+ }
+ LINFO << "Unmapped verity device " << mount_point;
+ return true;
+}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 8abe609..88b2f8f 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -93,3 +93,14 @@
// specified, the super partition for the corresponding metadata slot will be
// returned. Otherwise, it will use the current slot.
std::string fs_mgr_get_super_partition_name(int slot = -1);
+
+enum FsMgrUmountStatus : int {
+ SUCCESS = 0,
+ ERROR_UNKNOWN = 1 << 0,
+ ERROR_UMOUNT = 1 << 1,
+ ERROR_VERITY = 1 << 2,
+ ERROR_DEVICE_MAPPER = 1 << 3,
+};
+// fs_mgr_umount_all() is the reverse of fs_mgr_mount_all. In particular,
+// it destroys verity devices from device mapper after the device is unmounted.
+int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);
diff --git a/fs_mgr/libfiemap_writer/Android.mk b/fs_mgr/libfiemap_writer/Android.mk
new file mode 100644
index 0000000..3c07b8e
--- /dev/null
+++ b/fs_mgr/libfiemap_writer/Android.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsFiemapWriterTest
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libfiemap_writer/AndroidTest.xml b/fs_mgr/libfiemap_writer/AndroidTest.xml
new file mode 100644
index 0000000..08cff0e
--- /dev/null
+++ b/fs_mgr/libfiemap_writer/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for VTS VtsFiemapWriterTest">
+ <option name="config-descriptor:metadata" key="plan" value="vts-kernel" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HostDrivenTest.push"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsFiemapWriterTest"/>
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/fiemap_writer_test/fiemap_writer_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/fiemap_writer_test/fiemap_writer_test" />
+ <option name="binary-test-type" value="gtest"/>
+ <option name="test-timeout" value="1m"/>
+ </test>
+</configuration>
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
index ca51689..dda7dfd 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
@@ -498,17 +498,22 @@
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- if (argc <= 1) {
- cerr << "Usage: <test_dir> [file_size]\n";
+ if (argc > 1 && argv[1] == "-h"s) {
+ cerr << "Usage: [test_dir] [file_size]\n";
cerr << "\n";
cerr << "Note: test_dir must be a writable, unencrypted directory.\n";
exit(EXIT_FAILURE);
}
::android::base::InitLogging(argv, ::android::base::StderrLogger);
- std::string tempdir = argv[1] + "/XXXXXX"s;
+ std::string root_dir = "/data/local/unencrypted";
+ if (access(root_dir.c_str(), F_OK)) {
+ root_dir = "/data";
+ }
+
+ std::string tempdir = root_dir + "/XXXXXX"s;
if (!mkdtemp(tempdir.data())) {
- cerr << "unable to create tempdir on " << argv[1] << "\n";
+ cerr << "unable to create tempdir on " << root_dir << "\n";
exit(EXIT_FAILURE);
}
if (!android::base::Realpath(tempdir, &gTestDir)) {
diff --git a/fs_mgr/libfs_avb/avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp
index 6a3e2c0..c192bf5 100644
--- a/fs_mgr/libfs_avb/avb_ops.cpp
+++ b/fs_mgr/libfs_avb/avb_ops.cpp
@@ -36,6 +36,7 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <libavb/libavb.h>
+#include <libdm/dm.h>
#include <utils/Compat.h>
#include "util.h"
@@ -104,6 +105,20 @@
return AVB_IO_RESULT_OK;
}
+// Converts a partition name (with ab_suffix) to the corresponding mount point.
+// e.g., "system_a" => "/system",
+// e.g., "vendor_a" => "/vendor",
+static std::string DeriveMountPoint(const std::string& partition_name) {
+ const std::string ab_suffix = fs_mgr_get_slot_suffix();
+ std::string mount_point(partition_name);
+ auto found = partition_name.rfind(ab_suffix);
+ if (found != std::string::npos) {
+ mount_point.erase(found); // converts system_a => system
+ }
+
+ return "/" + mount_point;
+}
+
FsManagerAvbOps::FsManagerAvbOps() {
// We only need to provide the implementation of read_from_partition()
// operation since that's all what is being used by the avb_slot_verify().
@@ -122,14 +137,53 @@
avb_ops_.user_data = this;
}
+// Given a partition name (with ab_suffix), e.g., system_a, returns the corresponding
+// dm-linear path for it. e.g., /dev/block/dm-0. If not found, returns an empty string.
+// This assumes that the prefix of the partition name and the mount point are the same.
+// e.g., partition vendor_a is mounted under /vendor, product_a is mounted under /product, etc.
+// This might not be true for some special fstab files, e.g., fstab.postinstall.
+// But it's good enough for the default fstab. Also note that the logical path is a
+// fallback solution when the physical path (/dev/block/by-name/<partition>) cannot be found.
+std::string FsManagerAvbOps::GetLogicalPath(const std::string& partition_name) {
+ if (fstab_.empty() && !ReadDefaultFstab(&fstab_)) {
+ return "";
+ }
+
+ const auto mount_point = DeriveMountPoint(partition_name);
+ if (mount_point.empty()) return "";
+
+ auto fstab_entry = GetEntryForMountPoint(&fstab_, mount_point);
+ if (!fstab_entry) return "";
+
+ std::string device_path;
+ if (fstab_entry->fs_mgr_flags.logical) {
+ dm::DeviceMapper& dm = dm::DeviceMapper::Instance();
+ if (!dm.GetDmDevicePathByName(fstab_entry->blk_device, &device_path)) {
+ LERROR << "Failed to resolve logical device path for: " << fstab_entry->blk_device;
+ return "";
+ }
+ return device_path;
+ }
+
+ return "";
+}
+
AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
size_t num_bytes, void* buffer,
size_t* out_num_read) {
- const std::string path = "/dev/block/by-name/"s + partition;
+ std::string path = "/dev/block/by-name/"s + partition;
// Ensures the device path (a symlink created by init) is ready to access.
if (!WaitForFile(path, 1s)) {
- return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+ LERROR << "Device path not found: " << path;
+ // Falls back to logical path if the physical path is not found.
+ // This mostly only works for emulator (no bootloader). Because in normal
+ // device, bootloader is unable to read logical partitions. So if libavb in
+ // the bootloader failed to read a physical partition, it will failed to boot
+ // the HLOS and we won't reach the code here.
+ path = GetLogicalPath(partition);
+ if (path.empty() || !WaitForFile(path, 1s)) return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+ LINFO << "Fallback to use logical device path: " << path;
}
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
diff --git a/fs_mgr/libfs_avb/avb_ops.h b/fs_mgr/libfs_avb/avb_ops.h
index a849d94..b39812d 100644
--- a/fs_mgr/libfs_avb/avb_ops.h
+++ b/fs_mgr/libfs_avb/avb_ops.h
@@ -28,6 +28,7 @@
#include <vector>
#include <fs_avb/types.h>
+#include <fstab/fstab.h>
#include <libavb/libavb.h>
namespace android {
@@ -60,7 +61,9 @@
std::vector<VBMetaData>* out_vbmeta_images);
private:
+ std::string GetLogicalPath(const std::string& partition_name);
AvbOps avb_ops_;
+ Fstab fstab_;
};
} // namespace fs_mgr
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index f0767dc..04776ed 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -449,6 +449,29 @@
return AvbHashtreeResult::kSuccess;
}
+bool AvbHandle::TearDownAvbHashtree(FstabEntry* fstab_entry, bool wait) {
+ if (!fstab_entry) {
+ return false;
+ }
+
+ const std::string device_name(GetVerityDeviceName(*fstab_entry));
+
+ // TODO: remove duplicated code with UnmapDevice()
+ android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
+ std::string path;
+ if (wait) {
+ dm.GetDmDevicePathByName(device_name, &path);
+ }
+ if (!dm.DeleteDevice(device_name)) {
+ return false;
+ }
+ if (!path.empty() && !WaitForFile(path, 1000ms, FileWaitMode::DoesNotExist)) {
+ return false;
+ }
+
+ return true;
+}
+
std::string AvbHandle::GetSecurityPatchLevel(const FstabEntry& fstab_entry) const {
if (vbmeta_images_.size() < 1) {
return "";
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index 7127fa6..521f2d5 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -110,6 +110,11 @@
static AvbHashtreeResult SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry,
bool wait_for_verity_dev = true);
+ // Tear down dm devices created by SetUp[Standalone]AvbHashtree
+ // The 'wait' parameter makes this function wait for the verity device to get destroyed
+ // before return.
+ static bool TearDownAvbHashtree(FstabEntry* fstab_entry, bool wait);
+
static bool IsDeviceUnlocked();
std::string GetSecurityPatchLevel(const FstabEntry& fstab_entry) const;
diff --git a/fs_mgr/libfs_avb/tests/util_test.cpp b/fs_mgr/libfs_avb/tests/util_test.cpp
index 9e37d22..12b5acb 100644
--- a/fs_mgr/libfs_avb/tests/util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/util_test.cpp
@@ -27,6 +27,7 @@
// Target functions to test:
using android::fs_mgr::BytesToHex;
+using android::fs_mgr::FileWaitMode;
using android::fs_mgr::HexToBytes;
using android::fs_mgr::NibbleValue;
using android::fs_mgr::WaitForFile;
@@ -175,7 +176,7 @@
// Waits this path.
base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir");
ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */));
- auto wait_file = std::async(WaitForFile, wait_path.value(), 500ms);
+ auto wait_file = std::async(WaitForFile, wait_path.value(), 500ms, FileWaitMode::Exists);
// Sleeps 100ms before creating the wait_path.
std::this_thread::sleep_for(100ms);
@@ -196,7 +197,7 @@
// Waits this path.
base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir");
ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */));
- auto wait_file = std::async(WaitForFile, wait_path.value(), 50ms);
+ auto wait_file = std::async(WaitForFile, wait_path.value(), 50ms, FileWaitMode::Exists);
// Sleeps 100ms before creating the wait_path.
std::this_thread::sleep_for(100ms);
diff --git a/fs_mgr/libfs_avb/util.cpp b/fs_mgr/libfs_avb/util.cpp
index 9d4f05f..d214b5b 100644
--- a/fs_mgr/libfs_avb/util.cpp
+++ b/fs_mgr/libfs_avb/util.cpp
@@ -82,12 +82,17 @@
return hex;
}
-bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout) {
+// TODO: remove duplicate code with fs_mgr_wait_for_file
+bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout,
+ FileWaitMode file_wait_mode) {
auto start_time = std::chrono::steady_clock::now();
while (true) {
- if (0 == access(filename.c_str(), F_OK) || errno != ENOENT) {
- return true;
+ int rv = access(filename.c_str(), F_OK);
+ if (file_wait_mode == FileWaitMode::Exists) {
+ if (!rv || errno != ENOENT) return true;
+ } else if (file_wait_mode == FileWaitMode::DoesNotExist) {
+ if (rv && errno == ENOENT) return true;
}
std::this_thread::sleep_for(50ms);
diff --git a/fs_mgr/libfs_avb/util.h b/fs_mgr/libfs_avb/util.h
index cb861f4..7763da5 100644
--- a/fs_mgr/libfs_avb/util.h
+++ b/fs_mgr/libfs_avb/util.h
@@ -52,7 +52,9 @@
std::string BytesToHex(const uint8_t* bytes, size_t bytes_len);
-bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout);
+enum class FileWaitMode { Exists, DoesNotExist };
+bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout,
+ FileWaitMode wait_mode = FileWaitMode::Exists);
bool IsDeviceUnlocked();
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 27222af..41c01da 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -1057,7 +1057,7 @@
if (sABOverrideSet) {
return sABOverrideValue;
}
- return android::base::GetBoolProperty("ro.build.ab_update", false);
+ return !android::base::GetProperty("ro.boot.slot_suffix", "").empty();
}
bool MetadataBuilder::IsRetrofitDevice() const {
diff --git a/fs_mgr/liblp/partition_opener.cpp b/fs_mgr/liblp/partition_opener.cpp
index bb8ec9c..3b12213 100644
--- a/fs_mgr/liblp/partition_opener.cpp
+++ b/fs_mgr/liblp/partition_opener.cpp
@@ -26,6 +26,7 @@
#include <unistd.h>
#include <android-base/file.h>
+#include <android-base/strings.h>
#include "utility.h"
@@ -37,7 +38,7 @@
namespace {
std::string GetPartitionAbsolutePath(const std::string& path) {
- if (path[0] == '/') {
+ if (android::base::StartsWith(path, "/")) {
return path;
}
return "/dev/block/by-name/" + path;
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 0e5aa4f..edf34f7 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -78,6 +78,7 @@
#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
#define UNPLUGGED_DISPLAY_TIME (3 * MSEC_PER_SEC)
#define MAX_BATT_LEVEL_WAIT_TIME (3 * MSEC_PER_SEC)
+#define UNPLUGGED_SHUTDOWN_TIME_PROP "ro.product.charger.unplugged_shutdown_time"
#define LAST_KMSG_MAX_SZ (32 * 1024)
@@ -513,6 +514,7 @@
}
static void handle_power_supply_state(charger* charger, int64_t now) {
+ int timer_shutdown = UNPLUGGED_SHUTDOWN_TIME;
if (!charger->have_battery_state) return;
if (!charger->charger_connected) {
@@ -525,12 +527,14 @@
* Reset & kick animation to show complete animation cycles
* when charger disconnected.
*/
+ timer_shutdown =
+ property_get_int32(UNPLUGGED_SHUTDOWN_TIME_PROP, UNPLUGGED_SHUTDOWN_TIME);
charger->next_screen_transition = now - 1;
reset_animation(charger->batt_anim);
kick_animation(charger->batt_anim);
- charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
+ charger->next_pwr_check = now + timer_shutdown;
LOGW("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
- now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
+ now, (int64_t)timer_shutdown, charger->next_pwr_check);
} else if (now >= charger->next_pwr_check) {
LOGW("[%" PRId64 "] shutting down\n", now);
reboot(RB_POWER_OFF);
diff --git a/init/Android.bp b/init/Android.bp
index 69ee34f..69498ac 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -61,6 +61,7 @@
static_libs: [
"libseccomp_policy",
"libavb",
+ "libc++fs",
"libcgrouprc_format",
"libprotobuf-cpp-lite",
"libpropertyinfoserializer",
diff --git a/init/Android.mk b/init/Android.mk
index 39af0e6..b02c926 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -65,15 +65,22 @@
LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)
LOCAL_UNSTRIPPED_PATH := $(TARGET_RAMDISK_OUT_UNSTRIPPED)
+# Install adb_debug.prop into debug ramdisk.
+# This allows adb root on a user build, when debug ramdisk is used.
+LOCAL_REQUIRED_MODULES := \
+ adb_debug.prop \
+
# Set up the same mount points on the ramdisk that system-as-root contains.
LOCAL_POST_INSTALL_CMD := mkdir -p \
$(TARGET_RAMDISK_OUT)/apex \
+ $(TARGET_RAMDISK_OUT)/debug_ramdisk \
$(TARGET_RAMDISK_OUT)/dev \
$(TARGET_RAMDISK_OUT)/mnt \
$(TARGET_RAMDISK_OUT)/proc \
$(TARGET_RAMDISK_OUT)/sys \
LOCAL_STATIC_LIBRARIES := \
+ libc++fs \
libfs_avb \
libfs_mgr \
libfec \
diff --git a/init/README.md b/init/README.md
index aadf11d..51deb5a 100644
--- a/init/README.md
+++ b/init/README.md
@@ -488,7 +488,11 @@
This is included in the default init.rc.
`loglevel <level>`
-> Sets the kernel log level to level. Properties are expanded within _level_.
+> Sets init's log level to the integer level, from 7 (all logging) to 0
+ (fatal logging only). The numeric values correspond to the kernel log
+ levels, but this command does not affect the kernel log level. Use the
+ `write` command to write to `/proc/sys/kernel/printk` to change that.
+ Properties are expanded within _level_.
`mkdir <path> [mode] [owner] [group]`
> Create a directory at _path_, optionally with the given mode, owner, and
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 8437e37..06da4be 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -451,52 +451,6 @@
if (false) DumpState();
}
-/* mount_fstab
- *
- * Call fs_mgr_mount_all() to mount the given fstab
- */
-static Result<int> mount_fstab(const char* fstabfile, int mount_mode) {
- /*
- * Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and
- * do the call in the child to provide protection to the main init
- * process if anything goes wrong (crash or memory leak), and wait for
- * the child to finish in the parent.
- */
- pid_t pid = fork();
- if (pid > 0) {
- /* Parent. Wait for the child to return */
- int status;
- int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
- if (wp_ret == -1) {
- // Unexpected error code. We will continue anyway.
- PLOG(WARNING) << "waitpid failed";
- }
-
- if (WIFEXITED(status)) {
- return WEXITSTATUS(status);
- } else {
- return Error() << "child aborted";
- }
- } else if (pid == 0) {
- /* child, call fs_mgr_mount_all() */
-
- // So we can always see what fs_mgr_mount_all() does.
- // Only needed if someone explicitly changes the default log level in their init.rc.
- android::base::ScopedLogSeverity info(android::base::INFO);
-
- Fstab fstab;
- ReadFstabFromFile(fstabfile, &fstab);
-
- int child_ret = fs_mgr_mount_all(&fstab, mount_mode);
- if (child_ret == -1) {
- PLOG(ERROR) << "fs_mgr_mount_all returned an error";
- }
- _exit(child_ret);
- } else {
- return Error() << "fork() failed";
- }
-}
-
/* Queue event based on fs_mgr return code.
*
* code: return code of fs_mgr_mount_all
@@ -583,7 +537,7 @@
bool import_rc = true;
bool queue_event = true;
int mount_mode = MOUNT_MODE_DEFAULT;
- const char* fstabfile = args[1].c_str();
+ const auto& fstab_file = args[1];
std::size_t path_arg_end = args.size();
const char* prop_post_fix = "default";
@@ -603,10 +557,12 @@
std::string prop_name = "ro.boottime.init.mount_all."s + prop_post_fix;
android::base::Timer t;
- auto mount_fstab_return_code = mount_fstab(fstabfile, mount_mode);
- if (!mount_fstab_return_code) {
- return Error() << "mount_fstab() failed " << mount_fstab_return_code.error();
+
+ Fstab fstab;
+ if (!ReadFstabFromFile(fstab_file, &fstab)) {
+ return Error() << "Could not read fstab";
}
+ auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_mode);
property_set(prop_name, std::to_string(t.duration().count()));
if (import_rc) {
@@ -617,7 +573,7 @@
if (queue_event) {
/* queue_fs_event will queue event based on mount_fstab return code
* and return processed return code*/
- auto queue_fs_result = queue_fs_event(*mount_fstab_return_code);
+ auto queue_fs_result = queue_fs_event(mount_fstab_return_code);
if (!queue_fs_result) {
return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
}
@@ -626,6 +582,19 @@
return Success();
}
+/* umount_all <fstab> */
+static Result<Success> do_umount_all(const BuiltinArguments& args) {
+ Fstab fstab;
+ if (!ReadFstabFromFile(args[1], &fstab)) {
+ return Error() << "Could not read fstab";
+ }
+
+ if (auto result = fs_mgr_umount_all(&fstab); result != 0) {
+ return Error() << "umount_fstab() failed " << result;
+ }
+ return Success();
+}
+
static Result<Success> do_swapon_all(const BuiltinArguments& args) {
Fstab fstab;
if (!ReadFstabFromFile(args[1], &fstab)) {
@@ -1165,6 +1134,7 @@
{"mount", {3, kMax, {false, do_mount}}},
{"parse_apex_configs", {0, 0, {false, do_parse_apex_configs}}},
{"umount", {1, 1, {false, do_umount}}},
+ {"umount_all", {1, 1, {false, do_umount_all}}},
{"readahead", {1, 2, {true, do_readahead}}},
{"restart", {1, 1, {false, do_restart}}},
{"restorecon", {1, kMax, {true, do_restorecon}}},
diff --git a/init/debug_ramdisk.h b/init/debug_ramdisk.h
new file mode 100644
index 0000000..4e3a395
--- /dev/null
+++ b/init/debug_ramdisk.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android {
+namespace init {
+
+constexpr const char kDebugRamdiskProp[] = "/debug_ramdisk/adb_debug.prop";
+constexpr const char kDebugRamdiskSEPolicy[] = "/debug_ramdisk/userdebug_plat_sepolicy.cil";
+
+} // namespace init
+} // namespace android
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index c566676..8b95e38 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <filesystem>
#include <string>
#include <vector>
@@ -35,6 +36,7 @@
#include <cutils/android_reboot.h>
#include <private/android_filesystem_config.h>
+#include "debug_ramdisk.h"
#include "first_stage_mount.h"
#include "reboot_utils.h"
#include "switch_root.h"
@@ -44,6 +46,8 @@
using namespace std::literals;
+namespace fs = std::filesystem;
+
namespace android {
namespace init {
@@ -159,6 +163,9 @@
CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=0"));
+ // /debug_ramdisk is used to preserve additional files from the debug ramdisk
+ CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+ "mode=0755,uid=0,gid=0"));
#undef CHECKCALL
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
@@ -202,7 +209,14 @@
// If this file is present, the second-stage init will use a userdebug sepolicy
// and load adb_debug.prop to allow adb root, if the device is unlocked.
if (access("/force_debuggable", F_OK) == 0) {
- setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
+ std::error_code ec; // to invoke the overloaded copy_file() that won't throw.
+ if (!fs::copy_file("/adb_debug.prop", kDebugRamdiskProp, ec) ||
+ !fs::copy_file("/userdebug_plat_sepolicy.cil", kDebugRamdiskSEPolicy, ec)) {
+ LOG(ERROR) << "Failed to setup debug ramdisk";
+ } else {
+ // setenv for second-stage init to read above kDebugRamdisk* files.
+ setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
+ }
}
if (!DoFirstStageMount()) {
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index dd9c4d7..3e76556 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -80,7 +80,7 @@
bool InitMappedDevice(const std::string& verity_device);
bool InitDeviceMapper();
bool CreateLogicalPartitions();
- bool MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
+ bool MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end = nullptr);
bool MountPartitions();
@@ -437,21 +437,26 @@
uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
if (!found) {
- LOG(INFO) << "dm-verity device not found in /sys, waiting for its uevent";
+ LOG(INFO) << "dm device '" << dm_device << "' not found in /sys, waiting for its uevent";
Timer t;
uevent_listener_.Poll(verity_callback, 10s);
- LOG(INFO) << "wait for dm-verity device returned after " << t;
+ LOG(INFO) << "wait for dm device '" << dm_device << "' returned after " << t;
}
if (!found) {
- LOG(ERROR) << "dm-verity device not found after polling timeout";
+ LOG(ERROR) << "dm device '" << dm_device << "' not found after polling timeout";
return false;
}
return true;
}
-bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
+bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end) {
+ // Sets end to begin + 1, so we can just return on failure below.
+ if (end) {
+ *end = begin + 1;
+ }
+
if (begin->fs_mgr_flags.logical) {
if (!fs_mgr_update_logical_partition(&(*begin))) {
return false;
@@ -477,7 +482,7 @@
mounted = (fs_mgr_do_mount_one(*current) == 0);
}
}
- if (erase_used_fstab_entry) {
+ if (erase_same_mounts) {
current = fstab_.erase(begin, current);
}
if (end) {
@@ -494,7 +499,7 @@
return entry.mount_point == "/metadata";
});
if (metadata_partition != fstab_.end()) {
- if (MountPartition(metadata_partition, true /* erase_used_fstab_entry */)) {
+ if (MountPartition(metadata_partition, true /* erase_same_mounts */)) {
UseGsiIfPresent();
}
}
@@ -505,7 +510,7 @@
if (system_partition == fstab_.end()) return true;
- if (MountPartition(system_partition, false)) {
+ if (MountPartition(system_partition, false /* erase_same_mounts */)) {
if (gsi_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) {
LOG(ERROR) << "check_most_at_once forbidden on external media";
return false;
@@ -532,7 +537,7 @@
}
Fstab::iterator end;
- if (!MountPartition(current, false, &end)) {
+ if (!MountPartition(current, false /* erase_same_mounts */, &end)) {
if (current->fs_mgr_flags.no_fail) {
LOG(INFO) << "Failed to mount " << current->mount_point
<< ", ignoring mount for no_fail partition";
@@ -769,11 +774,9 @@
bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) {
AvbHashtreeResult hashtree_result;
- if (fstab_entry->fs_mgr_flags.avb) {
- if (!InitAvbHandle()) return false;
- hashtree_result =
- avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
- } else if (!fstab_entry->avb_keys.empty()) {
+ // It's possible for a fstab_entry to have both avb_keys and avb flag.
+ // In this case, try avb_keys first, then fallback to avb flag.
+ if (!fstab_entry->avb_keys.empty()) {
if (!InitAvbHandle()) return false;
// Checks if hashtree should be disabled from the top-level /vbmeta.
if (avb_handle_->status() == AvbHandleStatus::kHashtreeDisabled ||
@@ -785,14 +788,24 @@
auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry);
if (!avb_standalone_handle) {
LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point;
- return false;
+ // Fallbacks to built-in hashtree if fs_mgr_flags.avb is set.
+ if (!fstab_entry->fs_mgr_flags.avb) return false;
+ LOG(INFO) << "Fallback to built-in hashtree for " << fstab_entry->mount_point;
+ hashtree_result =
+ avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
+ } else {
+ // Sets up hashtree via the standalone handle.
+ if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) {
+ return false;
+ }
+ hashtree_result = avb_standalone_handle->SetUpAvbHashtree(
+ fstab_entry, false /* wait_for_verity_dev */);
}
- if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) {
- return false;
- }
- hashtree_result = avb_standalone_handle->SetUpAvbHashtree(
- fstab_entry, false /* wait_for_verity_dev */);
}
+ } else if (fstab_entry->fs_mgr_flags.avb) {
+ if (!InitAvbHandle()) return false;
+ hashtree_result =
+ avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
} else {
return true; // No need AVB, returns true to mount the partition directly.
}
diff --git a/init/init.cpp b/init/init.cpp
index 0f44efd..c79e459 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -621,6 +621,12 @@
});
}
+static void UmountDebugRamdisk() {
+ if (umount("/debug_ramdisk") != 0) {
+ LOG(ERROR) << "Failed to umount /debug_ramdisk";
+ }
+}
+
int SecondStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
@@ -630,6 +636,11 @@
InitKernelLogging(argv, InitAborter);
LOG(INFO) << "init second stage started!";
+ // Set init and its forked children's oom_adj.
+ if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) {
+ LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error();
+ }
+
// Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
GlobalSeccomp();
@@ -685,6 +696,7 @@
InstallSignalFdHandler(&epoll);
property_load_boot_defaults(load_debug_prop);
+ UmountDebugRamdisk();
fs_mgr_vendor_overlay_mount_all();
export_oem_lock_status();
StartPropertyService(&epoll);
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 467568c..9766584 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -56,6 +56,7 @@
#include <selinux/label.h>
#include <selinux/selinux.h>
+#include "debug_ramdisk.h"
#include "epoll.h"
#include "init.h"
#include "persistent_properties.h"
@@ -99,7 +100,24 @@
const char* name;
};
+static int PropertyAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
+ auto* d = reinterpret_cast<PropertyAuditData*>(data);
+
+ if (!d || !d->name || !d->cr) {
+ LOG(ERROR) << "AuditCallback invoked with null data arguments!";
+ return 0;
+ }
+
+ snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name, d->cr->pid, d->cr->uid,
+ d->cr->gid);
+ return 0;
+}
+
void property_init() {
+ selinux_callback cb;
+ cb.func_audit = PropertyAuditCallback;
+ selinux_set_callback(SELINUX_CB_AUDIT, cb);
+
mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
CreateSerializedPropertyInfo();
if (__system_property_area_init()) {
@@ -328,18 +346,20 @@
return result == sizeof(value);
}
+ bool GetSourceContext(std::string* source_context) const {
+ char* c_source_context = nullptr;
+ if (getpeercon(socket_, &c_source_context) != 0) {
+ return false;
+ }
+ *source_context = c_source_context;
+ freecon(c_source_context);
+ return true;
+ }
+
int socket() { return socket_; }
const ucred& cred() { return cred_; }
- std::string source_context() const {
- char* source_context = nullptr;
- getpeercon(socket_, &source_context);
- std::string result = source_context;
- freecon(source_context);
- return result;
- }
-
private:
bool PollIn(uint32_t* timeout_ms) {
struct pollfd ufds[1];
@@ -552,10 +572,15 @@
prop_name[PROP_NAME_MAX-1] = 0;
prop_value[PROP_VALUE_MAX-1] = 0;
+ std::string source_context;
+ if (!socket.GetSourceContext(&source_context)) {
+ PLOG(ERROR) << "Unable to set property '" << prop_name << "': getpeercon() failed";
+ return;
+ }
+
const auto& cr = socket.cred();
std::string error;
- uint32_t result =
- HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);
+ uint32_t result = HandlePropertySet(prop_name, prop_value, source_context, cr, &error);
if (result != PROP_SUCCESS) {
LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
<< " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -574,9 +599,16 @@
return;
}
+ std::string source_context;
+ if (!socket.GetSourceContext(&source_context)) {
+ PLOG(ERROR) << "Unable to set property '" << name << "': getpeercon() failed";
+ socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
+ return;
+ }
+
const auto& cr = socket.cred();
std::string error;
- uint32_t result = HandlePropertySet(name, value, socket.source_context(), cr, &error);
+ uint32_t result = HandlePropertySet(name, value, source_context, cr, &error);
if (result != PROP_SUCCESS) {
LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
<< " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -887,9 +919,8 @@
load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
if (load_debug_prop) {
- constexpr static const char kAdbDebugProp[] = "/system/etc/adb_debug.prop";
- LOG(INFO) << "Loading " << kAdbDebugProp;
- load_properties_from_file(kAdbDebugProp, nullptr, &properties);
+ LOG(INFO) << "Loading " << kDebugRamdiskProp;
+ load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
}
for (const auto& [name, value] : properties) {
@@ -906,19 +937,6 @@
update_sys_usb_config();
}
-static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
- auto* d = reinterpret_cast<PropertyAuditData*>(data);
-
- if (!d || !d->name || !d->cr) {
- LOG(ERROR) << "AuditCallback invoked with null data arguments!";
- return 0;
- }
-
- snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name, d->cr->pid, d->cr->uid,
- d->cr->gid);
- return 0;
-}
-
bool LoadPropertyInfoFromFile(const std::string& filename,
std::vector<PropertyInfoEntry>* property_infos) {
auto file_contents = std::string();
@@ -989,10 +1007,6 @@
}
void StartPropertyService(Epoll* epoll) {
- selinux_callback cb;
- cb.func_audit = SelinuxAuditCallback;
- selinux_set_callback(SELINUX_CB_AUDIT, cb);
-
property_set("ro.property_service.version", "2");
property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
diff --git a/init/property_service.h b/init/property_service.h
index 85e7bc0..207c03b 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _INIT_PROPERTY_H
-#define _INIT_PROPERTY_H
+#pragma once
#include <sys/socket.h>
@@ -35,13 +34,10 @@
extern bool PropertyChildReap(pid_t pid);
-void property_init(void);
-void property_load_boot_defaults(bool);
-void load_persist_props(void);
-void load_system_props(void);
+void property_init();
+void property_load_boot_defaults(bool load_debug_prop);
+void load_persist_props();
void StartPropertyService(Epoll* epoll);
} // namespace init
} // namespace android
-
-#endif /* _INIT_PROPERTY_H */
diff --git a/init/selinux.cpp b/init/selinux.cpp
index aa66baa..132fc13 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -64,6 +64,7 @@
#include <fs_avb/fs_avb.h>
#include <selinux/android.h>
+#include "debug_ramdisk.h"
#include "reboot_utils.h"
#include "util.h"
@@ -271,8 +272,6 @@
}
constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil";
-constexpr const char userdebug_plat_policy_cil_file[] =
- "/system/etc/selinux/userdebug_plat_sepolicy.cil";
bool IsSplitPolicyDevice() {
return access(plat_policy_cil_file, R_OK) != -1;
@@ -292,7 +291,7 @@
const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
bool use_userdebug_policy =
((force_debuggable_env && "true"s == force_debuggable_env) &&
- AvbHandle::IsDeviceUnlocked() && access(userdebug_plat_policy_cil_file, F_OK) == 0);
+ AvbHandle::IsDeviceUnlocked() && access(kDebugRamdiskSEPolicy, F_OK) == 0);
if (use_userdebug_policy) {
LOG(WARNING) << "Using userdebug system sepolicy";
}
@@ -367,7 +366,7 @@
// clang-format off
std::vector<const char*> compile_args {
"/system/bin/secilc",
- use_userdebug_policy ? userdebug_plat_policy_cil_file : plat_policy_cil_file,
+ use_userdebug_policy ? kDebugRamdiskSEPolicy: plat_policy_cil_file,
"-m", "-M", "true", "-G", "-N",
"-c", version_as_string.c_str(),
plat_mapping_file.c_str(),
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 6bec63c..71980d7 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -170,5 +170,7 @@
return "Failed to unwind due to invalid unwind information";
case BACKTRACE_UNWIND_ERROR_REPEATED_FRAME:
return "Failed to unwind due to same sp/pc repeating";
+ case BACKTRACE_UNWIND_ERROR_INVALID_ELF:
+ return "Failed to unwind due to invalid elf";
}
}
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index f5f9b2a..36640cd 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -89,6 +89,10 @@
case unwindstack::ERROR_REPEATED_FRAME:
error->error_code = BACKTRACE_UNWIND_ERROR_REPEATED_FRAME;
break;
+
+ case unwindstack::ERROR_INVALID_ELF:
+ error->error_code = BACKTRACE_UNWIND_ERROR_INVALID_ELF;
+ break;
}
}
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 10e790b..404e7e8 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -64,6 +64,8 @@
BACKTRACE_UNWIND_ERROR_UNWIND_INFO,
// Unwind information stopped due to sp/pc repeating.
BACKTRACE_UNWIND_ERROR_REPEATED_FRAME,
+ // Unwind information stopped due to invalid elf.
+ BACKTRACE_UNWIND_ERROR_INVALID_ELF,
};
struct BacktraceUnwindError {
diff --git a/libkeyutils/mini_keyctl_utils.cpp b/libkeyutils/mini_keyctl_utils.cpp
index b012a33..79b4680 100644
--- a/libkeyutils/mini_keyctl_utils.cpp
+++ b/libkeyutils/mini_keyctl_utils.cpp
@@ -67,7 +67,7 @@
if (tokens.size() < 9) {
continue;
}
- std::string key_id = tokens[0];
+ std::string key_id = "0x" + tokens[0];
std::string key_type = tokens[7];
// The key description may contain space.
std::string key_desc_prefix = tokens[8];
@@ -77,7 +77,7 @@
continue;
}
if (!android::base::ParseInt(key_id.c_str(), &keyring_id)) {
- error(1, 0, "Unexpected key format in /proc/keys");
+ error(1, 0, "Unexpected key format in /proc/keys: %s", key_id.c_str());
return -1;
}
return keyring_id;
diff --git a/libmeminfo/tools/procrank.cpp b/libmeminfo/tools/procrank.cpp
index 21a684c..cb3757d 100644
--- a/libmeminfo/tools/procrank.cpp
+++ b/libmeminfo/tools/procrank.cpp
@@ -14,11 +14,17 @@
* limitations under the License.
*/
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <dirent.h>
#include <errno.h>
#include <inttypes.h>
#include <linux/kernel-page-flags.h>
#include <linux/oom.h>
+#include <meminfo/procmeminfo.h>
+#include <meminfo/sysmeminfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -29,14 +35,6 @@
#include <sstream>
#include <vector>
-#include <android-base/file.h>
-#include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include <meminfo/procmeminfo.h>
-#include <meminfo/sysmeminfo.h>
-
using ::android::meminfo::MemUsage;
using ::android::meminfo::ProcMemInfo;
@@ -44,7 +42,6 @@
public:
ProcessRecord(pid_t pid, bool get_wss = false, uint64_t pgflags = 0, uint64_t pgflags_mask = 0)
: pid_(-1),
- procmem_(nullptr),
oomadj_(OOM_SCORE_ADJ_MAX + 1),
cmdline_(""),
proportional_swap_(0),
@@ -81,15 +78,15 @@
// The .c_str() assignment below then takes care of trimming the cmdline at the first
// 0x00. This is how original procrank worked (luckily)
cmdline_.resize(strlen(cmdline_.c_str()));
- procmem_ = std::move(procmem);
+ usage_or_wss_ = get_wss ? procmem->Wss() : procmem->Usage();
+ swap_offsets_ = procmem->SwapOffsets();
pid_ = pid;
}
bool valid() const { return pid_ != -1; }
void CalculateSwap(const uint16_t* swap_offset_array, float zram_compression_ratio) {
- const std::vector<uint16_t>& swp_offs = procmem_->SwapOffsets();
- for (auto& off : swp_offs) {
+ for (auto& off : swap_offsets_) {
proportional_swap_ += getpagesize() / swap_offset_array[off];
unique_swap_ += swap_offset_array[off] == 1 ? getpagesize() : 0;
zswap_ = proportional_swap_ * zram_compression_ratio;
@@ -105,18 +102,19 @@
uint64_t zswap() const { return zswap_; }
// Wrappers to ProcMemInfo
- const std::vector<uint16_t>& SwapOffsets() const { return procmem_->SwapOffsets(); }
- const MemUsage& Usage() const { return procmem_->Usage(); }
- const MemUsage& Wss() const { return procmem_->Wss(); }
+ const std::vector<uint16_t>& SwapOffsets() const { return swap_offsets_; }
+ const MemUsage& Usage() const { return usage_or_wss_; }
+ const MemUsage& Wss() const { return usage_or_wss_; }
private:
pid_t pid_;
- std::unique_ptr<ProcMemInfo> procmem_;
int32_t oomadj_;
std::string cmdline_;
uint64_t proportional_swap_;
uint64_t unique_swap_;
uint64_t zswap_;
+ MemUsage usage_or_wss_;
+ std::vector<uint16_t> swap_offsets_;
};
// Show working set instead of memory consumption
@@ -173,7 +171,7 @@
while ((dir = readdir(procdir.get()))) {
if (!::android::base::ParseInt(dir->d_name, &pid)) continue;
if (!for_each_pid(pid)) return false;
- pids->push_back(pid);
+ pids->emplace_back(pid);
}
return true;
@@ -460,12 +458,20 @@
auto mark_swap_usage = [&](pid_t pid) -> bool {
ProcessRecord proc(pid, show_wss, pgflags, pgflags_mask);
if (!proc.valid()) {
- std::cerr << "Failed to create process record for: " << pid << std::endl;
- return false;
+ // Check to see if the process is still around, skip the process if the proc
+ // directory is inaccessible. It was most likely killed while creating the process
+ // record
+ std::string procdir = ::android::base::StringPrintf("/proc/%d", pid);
+ if (access(procdir.c_str(), F_OK | R_OK)) return true;
+
+ // Warn if we failed to gather process stats even while it is still alive.
+ // Return success here, so we continue to print stats for other processes.
+ std::cerr << "warning: failed to create process record for: " << pid << std::endl;
+ return true;
}
// Skip processes with no memory mappings
- uint64_t vss = proc.Usage().vss;
+ uint64_t vss = show_wss ? proc.Wss().vss : proc.Usage().vss;
if (vss == 0) return true;
// collect swap_offset counts from all processes in 1st pass
@@ -475,13 +481,13 @@
return false;
}
- procs.push_back(std::move(proc));
+ procs.emplace_back(std::move(proc));
return true;
};
- // Get a list of all pids currently running in the system in
- // 1st pass through all processes. Mark each swap offset used by the process as we find them
- // for calculating proportional swap usage later.
+ // Get a list of all pids currently running in the system in 1st pass through all processes.
+ // Mark each swap offset used by the process as we find them for calculating proportional
+ // swap usage later.
if (!read_all_pids(&pids, mark_swap_usage)) {
std::cerr << "Failed to read all pids from the system" << std::endl;
exit(EXIT_FAILURE);
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 86e6035..7e6bf45 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -24,16 +24,20 @@
__BEGIN_DECLS
static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2";
-static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path);
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path);
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path);
-bool UsePerAppMemcg();
+bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache = false);
+bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
+ bool use_fd_cache = false);
-bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles);
-bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
+#ifndef __ANDROID_VNDK__
+
+static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
+
+bool UsePerAppMemcg();
// Return 0 and removes the cgroup if there are no longer any processes in it.
// Returns -1 in the case of an error occurring or if there are processes still running
@@ -54,4 +58,6 @@
void removeAllProcessGroups(void);
+#endif // __ANDROID_VNDK__
+
__END_DECLS
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index abe63dd..1485ae9 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -112,12 +112,16 @@
return memcg_supported;
}
-bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
+bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
+ bool use_fd_cache) {
const TaskProfiles& tp = TaskProfiles::GetInstance();
for (const auto& name : profiles) {
- const TaskProfile* profile = tp.GetProfile(name);
+ TaskProfile* profile = tp.GetProfile(name);
if (profile != nullptr) {
+ if (use_fd_cache) {
+ profile->EnableResourceCaching();
+ }
if (!profile->ExecuteForProcess(uid, pid)) {
PLOG(WARNING) << "Failed to apply " << name << " process profile";
}
@@ -129,12 +133,15 @@
return true;
}
-bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles) {
+bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
const TaskProfiles& tp = TaskProfiles::GetInstance();
for (const auto& name : profiles) {
- const TaskProfile* profile = tp.GetProfile(name);
+ TaskProfile* profile = tp.GetProfile(name);
if (profile != nullptr) {
+ if (use_fd_cache) {
+ profile->EnableResourceCaching();
+ }
if (!profile->ExecuteForTask(tid)) {
PLOG(WARNING) << "Failed to apply " << name << " task profile";
}
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index c7d0cca..fe4f93b 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -46,26 +46,34 @@
switch (policy) {
case SP_BACKGROUND:
- return SetTaskProfiles(tid, {"HighEnergySaving", "ProcessCapacityLow", "LowIoPriority",
- "TimerSlackHigh"})
+ return SetTaskProfiles(tid,
+ {"HighEnergySaving", "ProcessCapacityLow", "LowIoPriority",
+ "TimerSlackHigh"},
+ true)
? 0
: -1;
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
- return SetTaskProfiles(tid, {"HighPerformance", "ProcessCapacityHigh", "HighIoPriority",
- "TimerSlackNormal"})
+ return SetTaskProfiles(tid,
+ {"HighPerformance", "ProcessCapacityHigh", "HighIoPriority",
+ "TimerSlackNormal"},
+ true)
? 0
: -1;
case SP_TOP_APP:
- return SetTaskProfiles(tid, {"MaxPerformance", "ProcessCapacityMax", "MaxIoPriority",
- "TimerSlackNormal"})
+ return SetTaskProfiles(tid,
+ {"MaxPerformance", "ProcessCapacityMax", "MaxIoPriority",
+ "TimerSlackNormal"},
+ true)
? 0
: -1;
case SP_SYSTEM:
- return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}) ? 0 : -1;
+ return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}, true) ? 0 : -1;
case SP_RESTRICTED:
- return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}) ? 0 : -1;
+ return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}, true)
+ ? 0
+ : -1;
default:
break;
}
@@ -126,26 +134,17 @@
switch (policy) {
case SP_BACKGROUND:
- return SetTaskProfiles(tid, {"HighEnergySaving", "LowIoPriority", "TimerSlackHigh"})
- ? 0
- : -1;
+ return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}, true) ? 0 : -1;
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
- return SetTaskProfiles(tid, {"HighPerformance", "HighIoPriority", "TimerSlackNormal"})
- ? 0
- : -1;
+ return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}, true) ? 0 : -1;
case SP_TOP_APP:
- return SetTaskProfiles(tid, {"MaxPerformance", "MaxIoPriority", "TimerSlackNormal"})
- ? 0
- : -1;
+ return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}, true) ? 0 : -1;
case SP_RT_APP:
- return SetTaskProfiles(tid,
- {"RealtimePerformance", "MaxIoPriority", "TimerSlackNormal"})
- ? 0
- : -1;
+ return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}, true) ? 0 : -1;
default:
- return SetTaskProfiles(tid, {"TimerSlackNormal"}) ? 0 : -1;
+ return SetTaskProfiles(tid, {"TimerSlackNormal"}, true) ? 0 : -1;
}
return 0;
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 4b45c87..40d8d90 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -138,31 +138,38 @@
SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
: controller_(c), path_(p) {
-#ifdef CACHE_FILE_DESCRIPTORS
- // cache file descriptor only if path is app independent
+ // file descriptors for app-dependent paths can't be cached
if (IsAppDependentPath(path_)) {
// file descriptor is not cached
- fd_.reset(-2);
+ fd_.reset(FDS_APP_DEPENDENT);
return;
}
- std::string tasks_path = c.GetTasksFilePath(p);
+ // file descriptor can be cached later on request
+ fd_.reset(FDS_NOT_CACHED);
+}
+
+void SetCgroupAction::EnableResourceCaching() {
+ if (fd_ != FDS_NOT_CACHED) {
+ return;
+ }
+
+ std::string tasks_path = controller_.GetTasksFilePath(path_);
if (access(tasks_path.c_str(), W_OK) != 0) {
// file is not accessible
- fd_.reset(-1);
+ fd_.reset(FDS_INACCESSIBLE);
return;
}
unique_fd fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (fd < 0) {
PLOG(ERROR) << "Failed to cache fd '" << tasks_path << "'";
- fd_.reset(-1);
+ fd_.reset(FDS_INACCESSIBLE);
return;
}
fd_ = std::move(fd);
-#endif
}
bool SetCgroupAction::AddTidToCgroup(int tid, int fd) {
@@ -184,8 +191,7 @@
}
bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
-#ifdef CACHE_FILE_DESCRIPTORS
- if (fd_ >= 0) {
+ if (IsFdValid()) {
// fd is cached, reuse it
if (!AddTidToCgroup(pid, fd_)) {
LOG(ERROR) << "Failed to add task into cgroup";
@@ -194,12 +200,12 @@
return true;
}
- if (fd_ == -1) {
+ if (fd_ == FDS_INACCESSIBLE) {
// no permissions to access the file, ignore
return true;
}
- // this is app-dependent path, file descriptor is not cached
+ // this is app-dependent path and fd is not cached or cached fd can't be used
std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
@@ -212,25 +218,10 @@
}
return true;
-#else
- std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
- unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
- if (tmp_fd < 0) {
- // no permissions to access the file, ignore
- return true;
- }
- if (!AddTidToCgroup(pid, tmp_fd)) {
- LOG(ERROR) << "Failed to add task into cgroup";
- return false;
- }
-
- return true;
-#endif
}
bool SetCgroupAction::ExecuteForTask(int tid) const {
-#ifdef CACHE_FILE_DESCRIPTORS
- if (fd_ >= 0) {
+ if (IsFdValid()) {
// fd is cached, reuse it
if (!AddTidToCgroup(tid, fd_)) {
LOG(ERROR) << "Failed to add task into cgroup";
@@ -239,20 +230,23 @@
return true;
}
- if (fd_ == -1) {
+ if (fd_ == FDS_INACCESSIBLE) {
// no permissions to access the file, ignore
return true;
}
- // application-dependent path can't be used with tid
- LOG(ERROR) << "Application profile can't be applied to a thread";
- return false;
-#else
+ if (fd_ == FDS_APP_DEPENDENT) {
+ // application-dependent path can't be used with tid
+ PLOG(ERROR) << "Application profile can't be applied to a thread";
+ return false;
+ }
+
+ // fd was not cached because cached fd can't be used
std::string tasks_path = controller()->GetTasksFilePath(path_);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
- // no permissions to access the file, ignore
- return true;
+ PLOG(WARNING) << "Failed to open " << tasks_path << ": " << strerror(errno);
+ return false;
}
if (!AddTidToCgroup(tid, tmp_fd)) {
LOG(ERROR) << "Failed to add task into cgroup";
@@ -260,7 +254,6 @@
}
return true;
-#endif
}
bool TaskProfile::ExecuteForProcess(uid_t uid, pid_t pid) const {
@@ -284,6 +277,18 @@
return true;
}
+void TaskProfile::EnableResourceCaching() {
+ if (res_cached_) {
+ return;
+ }
+
+ for (auto& element : elements_) {
+ element->EnableResourceCaching();
+ }
+
+ res_cached_ = true;
+}
+
TaskProfiles& TaskProfiles::GetInstance() {
// Deliberately leak this object to avoid a race between destruction on
// process exit and concurrent access from another thread.
@@ -411,7 +416,7 @@
return true;
}
-const TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
+TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
auto iter = profiles_.find(name);
if (iter != profiles_.end()) {
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 37cc305..445647d 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -48,6 +48,8 @@
// Default implementations will fail
virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; };
virtual bool ExecuteForTask(int) const { return false; };
+
+ virtual void EnableResourceCaching() {}
};
// Profile actions
@@ -110,31 +112,40 @@
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
+ virtual void EnableResourceCaching();
const CgroupController* controller() const { return &controller_; }
std::string path() const { return path_; }
private:
+ enum FdState {
+ FDS_INACCESSIBLE = -1,
+ FDS_APP_DEPENDENT = -2,
+ FDS_NOT_CACHED = -3,
+ };
+
CgroupController controller_;
std::string path_;
-#ifdef CACHE_FILE_DESCRIPTORS
android::base::unique_fd fd_;
-#endif
static bool IsAppDependentPath(const std::string& path);
static bool AddTidToCgroup(int tid, int fd);
+
+ bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; }
};
class TaskProfile {
public:
- TaskProfile() {}
+ TaskProfile() : res_cached_(false) {}
void Add(std::unique_ptr<ProfileAction> e) { elements_.push_back(std::move(e)); }
bool ExecuteForProcess(uid_t uid, pid_t pid) const;
bool ExecuteForTask(int tid) const;
+ void EnableResourceCaching();
private:
+ bool res_cached_;
std::vector<std::unique_ptr<ProfileAction>> elements_;
};
@@ -143,7 +154,7 @@
// Should be used by all users
static TaskProfiles& GetInstance();
- const TaskProfile* GetProfile(const std::string& name) const;
+ TaskProfile* GetProfile(const std::string& name) const;
const ProfileAttribute* GetAttribute(const std::string& name) const;
private:
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index ded5adb..9780606 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -95,7 +95,7 @@
} else if (!mListen)
mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum);
- if (pipe(mCtrlPipe)) {
+ if (pipe2(mCtrlPipe, O_CLOEXEC)) {
SLOGE("pipe failed (%s)", strerror(errno));
return -1;
}
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 4b93abb..3454913 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -160,7 +160,7 @@
if (valid_) {
return interface_->LastErrorCode();
}
- return ERROR_NONE;
+ return ERROR_INVALID_ELF;
}
uint64_t Elf::GetLastErrorAddress() {
@@ -170,22 +170,23 @@
return 0;
}
+// The relative pc expectd by this function is relative to the start of the elf.
+bool Elf::StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
+ if (!valid_) {
+ return false;
+ }
+ return regs->StepIfSignalHandler(rel_pc, this, process_memory);
+}
+
// The relative pc is always relative to the start of the map from which it comes.
-bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,
- bool* finished) {
+bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) {
if (!valid_) {
return false;
}
- // The relative pc expectd by StepIfSignalHandler is relative to the start of the elf.
- if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) {
- *finished = false;
- return true;
- }
-
// Lock during the step which can update information in the object.
std::lock_guard<std::mutex> guard(lock_);
- return interface_->Step(adjusted_rel_pc, regs, process_memory, finished);
+ return interface_->Step(rel_pc, regs, process_memory, finished);
}
bool Elf::IsValidElf(Memory* memory) {
diff --git a/libunwindstack/LocalUnwinder.cpp b/libunwindstack/LocalUnwinder.cpp
index 5b2fadf..5d81200 100644
--- a/libunwindstack/LocalUnwinder.cpp
+++ b/libunwindstack/LocalUnwinder.cpp
@@ -111,6 +111,14 @@
pc_adjustment = 0;
}
step_pc -= pc_adjustment;
+
+ bool finished = false;
+ if (elf->StepIfSignalHandler(rel_pc, regs.get(), process_memory_.get())) {
+ step_pc = rel_pc;
+ } else if (!elf->Step(step_pc, regs.get(), process_memory_.get(), &finished)) {
+ finished = true;
+ }
+
// Skip any locations that are within this library.
if (num_frames != 0 || !ShouldSkipLibrary(map_info->name)) {
// Add frame information.
@@ -124,22 +132,12 @@
}
num_frames++;
}
- if (!elf->valid()) {
- break;
- }
- if (frame_info->size() == max_frames) {
- break;
- }
+ if (finished || frame_info->size() == max_frames ||
+ (cur_pc == regs->pc() && cur_sp == regs->sp())) {
+ break;
+ }
adjust_pc = true;
- bool finished;
- if (!elf->Step(rel_pc, step_pc, regs.get(), process_memory_.get(), &finished) || finished) {
- break;
- }
- // pc and sp are the same, terminate the unwind.
- if (cur_pc == regs->pc() && cur_sp == regs->sp()) {
- break;
- }
}
return num_frames != 0;
}
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 28373b2..03658b4 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -161,6 +161,7 @@
// option is used.
std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
if (Elf::IsValidElf(memory.get())) {
+ memory_backed_elf = true;
return memory.release();
}
@@ -184,6 +185,7 @@
new MemoryRange(process_memory, prev_map->start, prev_map->end - prev_map->start, 0));
ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
+ memory_backed_elf = true;
return ranges;
}
@@ -237,6 +239,7 @@
std::lock_guard<std::mutex> guard(prev_map->mutex_);
if (prev_map->elf.get() == nullptr) {
prev_map->elf = elf;
+ prev_map->memory_backed_elf = memory_backed_elf;
}
}
return elf.get();
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 3f2e1c1..26626b5 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -89,8 +89,8 @@
#endif
}
-void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t func_pc,
- uint64_t pc_adjustment) {
+FrameData* Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc,
+ uint64_t pc_adjustment) {
size_t frame_num = frames_.size();
frames_.resize(frame_num + 1);
FrameData* frame = &frames_.at(frame_num);
@@ -100,7 +100,8 @@
frame->pc = regs_->pc() - pc_adjustment;
if (map_info == nullptr) {
- return;
+ // Nothing else to update.
+ return nullptr;
}
if (resolve_names_) {
@@ -118,12 +119,7 @@
frame->map_end = map_info->end;
frame->map_flags = map_info->flags;
frame->map_load_bias = elf->GetLoadBias();
-
- if (!resolve_names_ ||
- !elf->GetFunctionName(func_pc, &frame->function_name, &frame->function_offset)) {
- frame->function_name = "";
- frame->function_offset = 0;
- }
+ return frame;
}
static bool ShouldStop(const std::vector<std::string>* map_suffixes_to_ignore,
@@ -145,6 +141,7 @@
frames_.clear();
last_error_.code = ERROR_NONE;
last_error_.address = 0;
+ elf_from_memory_not_file_ = false;
ArchEnum arch = regs_->Arch();
@@ -168,6 +165,12 @@
break;
}
elf = map_info->GetElf(process_memory_, arch);
+ // If this elf is memory backed, and there is a valid file, then set
+ // an indicator that we couldn't open the file.
+ if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() &&
+ map_info->name[0] != '[') {
+ elf_from_memory_not_file_ = true;
+ }
step_pc = regs_->pc();
rel_pc = elf->GetRelPc(step_pc, map_info);
// Everyone except elf data in gdb jit debug maps uses the relative pc.
@@ -194,6 +197,7 @@
}
}
+ FrameData* frame = nullptr;
if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
@@ -210,23 +214,21 @@
}
}
- FillInFrame(map_info, elf, rel_pc, step_pc, pc_adjustment);
+ frame = FillInFrame(map_info, elf, rel_pc, pc_adjustment);
// Once a frame is added, stop skipping frames.
initial_map_names_to_skip = nullptr;
}
adjust_pc = true;
- bool stepped;
+ bool stepped = false;
bool in_device_map = false;
- if (map_info == nullptr) {
- stepped = false;
- } else {
+ bool finished = false;
+ if (map_info != nullptr) {
if (map_info->flags & MAPS_FLAGS_DEVICE_MAP) {
// Do not stop here, fall through in case we are
// in the speculative unwind path and need to remove
// some of the speculative frames.
- stepped = false;
in_device_map = true;
} else {
MapInfo* sp_info = maps_->Find(regs_->sp());
@@ -234,19 +236,37 @@
// Do not stop here, fall through in case we are
// in the speculative unwind path and need to remove
// some of the speculative frames.
- stepped = false;
in_device_map = true;
} else {
- bool finished;
- stepped = elf->Step(rel_pc, step_pc, regs_, process_memory_.get(), &finished);
- elf->GetLastError(&last_error_);
- if (stepped && finished) {
- break;
+ if (elf->StepIfSignalHandler(rel_pc, regs_, process_memory_.get())) {
+ stepped = true;
+ if (frame != nullptr) {
+ // Need to adjust the relative pc because the signal handler
+ // pc should not be adjusted.
+ frame->rel_pc = rel_pc;
+ frame->pc += pc_adjustment;
+ step_pc = rel_pc;
+ }
+ } else if (elf->Step(step_pc, regs_, process_memory_.get(), &finished)) {
+ stepped = true;
}
+ elf->GetLastError(&last_error_);
}
}
}
+ if (frame != nullptr) {
+ if (!resolve_names_ ||
+ !elf->GetFunctionName(step_pc, &frame->function_name, &frame->function_offset)) {
+ frame->function_name = "";
+ frame->function_offset = 0;
+ }
+ }
+
+ if (finished) {
+ break;
+ }
+
if (!stepped) {
if (return_address_attempt) {
// Only remove the speculative frame if there are more than two frames
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index ac94f10..56bf318 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -67,8 +67,9 @@
uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
- bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,
- bool* finished);
+ bool StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memory);
+
+ bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h
index 6ed0e0f..72ec454 100644
--- a/libunwindstack/include/unwindstack/Error.h
+++ b/libunwindstack/include/unwindstack/Error.h
@@ -29,6 +29,7 @@
ERROR_INVALID_MAP, // Unwind in an invalid map.
ERROR_MAX_FRAMES_EXCEEDED, // The number of frames exceed the total allowed.
ERROR_REPEATED_FRAME, // The last frame has the same pc/sp as the next.
+ ERROR_INVALID_ELF, // Unwind in an invalid elf.
};
struct ErrorData {
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index e938986..025fd98 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -75,6 +75,9 @@
// make it easier to move to a fine grained lock in the future.
std::atomic_uintptr_t build_id;
+ // Set to true if the elf file data is coming from memory.
+ bool memory_backed_elf = false;
+
// This function guarantees it will never return nullptr.
Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch);
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 8b01654..52b3578 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -111,6 +111,8 @@
void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
#endif
+ bool elf_from_memory_not_file() { return elf_from_memory_not_file_; }
+
ErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
@@ -118,8 +120,7 @@
Unwinder(size_t max_frames) : max_frames_(max_frames) { frames_.reserve(max_frames); }
void FillInDexFrame();
- void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t func_pc,
- uint64_t pc_adjustment);
+ FrameData* FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t pc_adjustment);
size_t max_frames_;
Maps* maps_;
@@ -133,6 +134,9 @@
bool resolve_names_ = true;
bool embedded_soname_ = true;
bool display_build_id_ = false;
+ // True if at least one elf file is coming from memory and not the related
+ // file. This is only true if there is an actual file backing up the elf.
+ bool elf_from_memory_not_file_ = false;
ErrorData last_error_;
};
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 23c9cf8..c432d6d 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -132,8 +132,12 @@
uint64_t func_offset;
ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
+ ASSERT_FALSE(elf.StepIfSignalHandler(0, nullptr, nullptr));
+ EXPECT_EQ(ERROR_INVALID_ELF, elf.GetLastErrorCode());
+
bool finished;
- ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
+ ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished));
+ EXPECT_EQ(ERROR_INVALID_ELF, elf.GetLastErrorCode());
}
TEST_F(ElfTest, elf32_invalid_machine) {
@@ -295,9 +299,8 @@
}
elf.FakeSetValid(true);
- bool finished;
- ASSERT_TRUE(elf.Step(0x3000, 0x1000, ®s, &process_memory, &finished));
- EXPECT_FALSE(finished);
+ ASSERT_TRUE(elf.StepIfSignalHandler(0x3000, ®s, &process_memory));
+ EXPECT_EQ(ERROR_NONE, elf.GetLastErrorCode());
EXPECT_EQ(15U, regs.pc());
EXPECT_EQ(13U, regs.sp());
}
@@ -336,7 +339,7 @@
EXPECT_CALL(*interface, Step(0x1000, ®s, &process_memory, &finished))
.WillOnce(::testing::Return(true));
- ASSERT_TRUE(elf.Step(0x1004, 0x1000, ®s, &process_memory, &finished));
+ ASSERT_TRUE(elf.Step(0x1000, ®s, &process_memory, &finished));
}
TEST_F(ElfTest, get_global_invalid_elf) {
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 2ddadef..6be8bdc 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -108,6 +108,7 @@
info.end = 0x101;
memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_FALSE(info.memory_backed_elf);
}
// Verify that if the offset is non-zero but there is no elf at the offset,
@@ -117,6 +118,7 @@
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0x100U, info.elf_offset);
EXPECT_EQ(0x100U, info.elf_start_offset);
@@ -140,32 +142,40 @@
// offset to zero.
info.elf_offset = 0;
info.elf_start_offset = 0;
+ info.memory_backed_elf = false;
memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0x100U, info.elf_offset);
EXPECT_EQ(0x100U, info.elf_start_offset);
prev_info.offset = 0;
info.elf_offset = 0;
info.elf_start_offset = 0;
+ info.memory_backed_elf = false;
memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0x100U, info.elf_offset);
EXPECT_EQ(0x100U, info.elf_start_offset);
prev_info.flags = PROT_READ;
info.elf_offset = 0;
info.elf_start_offset = 0;
+ info.memory_backed_elf = false;
memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0x100U, info.elf_offset);
EXPECT_EQ(0x100U, info.elf_start_offset);
prev_info.name = info.name;
info.elf_offset = 0;
info.elf_start_offset = 0;
+ info.memory_backed_elf = false;
memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0x100U, info.elf_offset);
EXPECT_EQ(0U, info.elf_start_offset);
}
@@ -177,6 +187,7 @@
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0U, info.elf_offset);
EXPECT_EQ(0x1000U, info.elf_start_offset);
@@ -201,6 +212,7 @@
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0U, info.elf_offset);
EXPECT_EQ(0x1000U, info.elf_start_offset);
@@ -218,6 +230,7 @@
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0U, info.elf_offset);
EXPECT_EQ(0x2000U, info.elf_start_offset);
@@ -259,6 +272,7 @@
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_TRUE(info.memory_backed_elf);
memset(buffer.data(), 0, buffer.size());
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
@@ -290,6 +304,7 @@
std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
ASSERT_TRUE(mem.get() != nullptr);
+ EXPECT_TRUE(map_info->memory_backed_elf);
EXPECT_EQ(0x4000UL, map_info->elf_offset);
EXPECT_EQ(0x4000UL, map_info->offset);
EXPECT_EQ(0U, map_info->elf_start_offset);
@@ -336,6 +351,7 @@
std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
ASSERT_TRUE(mem.get() != nullptr);
+ EXPECT_TRUE(map_info->memory_backed_elf);
EXPECT_EQ(0x1000UL, map_info->elf_offset);
EXPECT_EQ(0xb000UL, map_info->offset);
EXPECT_EQ(0xa000UL, map_info->elf_start_offset);
@@ -374,6 +390,7 @@
// extend over the executable segment.
std::unique_ptr<Memory> memory(map_info->CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
+ EXPECT_FALSE(map_info->memory_backed_elf);
std::vector<uint8_t> buffer(0x100);
EXPECT_EQ(0x2000U, map_info->offset);
EXPECT_EQ(0U, map_info->elf_offset);
@@ -388,7 +405,9 @@
ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
+ map_info->memory_backed_elf = false;
memory.reset(map_info->CreateMemory(process_memory_));
+ EXPECT_FALSE(map_info->memory_backed_elf);
EXPECT_EQ(0x2000U, map_info->offset);
EXPECT_EQ(0x1000U, map_info->elf_offset);
EXPECT_EQ(0x1000U, map_info->elf_start_offset);
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 02ba9c8..6c64c40 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1215,7 +1215,7 @@
" #02 pc 0032bff3 libunwindstack_test (SignalOuterFunction+2)\n"
" #03 pc 0032fed3 libunwindstack_test "
"(unwindstack::SignalCallerHandler(int, siginfo*, void*)+26)\n"
- " #04 pc 00026528 libc.so\n"
+ " #04 pc 0002652c libc.so (__restore)\n"
" #05 pc 00000000 <unknown>\n"
" #06 pc 0032c2d9 libunwindstack_test (InnerFunction+736)\n"
" #07 pc 0032cc4f libunwindstack_test (MiddleFunction+42)\n"
@@ -1243,7 +1243,7 @@
EXPECT_EQ(0xf43d2ce8U, unwinder.frames()[2].sp);
EXPECT_EQ(0x2e59ed3U, unwinder.frames()[3].pc);
EXPECT_EQ(0xf43d2cf0U, unwinder.frames()[3].sp);
- EXPECT_EQ(0xf4136528U, unwinder.frames()[4].pc);
+ EXPECT_EQ(0xf413652cU, unwinder.frames()[4].pc);
EXPECT_EQ(0xf43d2d10U, unwinder.frames()[4].sp);
EXPECT_EQ(0U, unwinder.frames()[5].pc);
EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[5].sp);
@@ -1326,7 +1326,7 @@
" #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n"
" #01 pc 000000000005426c linker64 "
"(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
- " #02 pc 00000000000008bc vdso.so\n"
+ " #02 pc 00000000000008c0 vdso.so (__kernel_rt_sigreturn)\n"
" #03 pc 00000000000846f4 libc.so (abort+172)\n"
" #04 pc 0000000000084ad4 libc.so (__assert2+36)\n"
" #05 pc 000000000003d5b4 ANGLEPrebuilt.apk!libfeature_support_angle.so (offset 0x4000) "
@@ -1338,7 +1338,7 @@
EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp);
- EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc);
+ EXPECT_EQ(0x7e82b018c0ULL, unwinder.frames()[2].pc);
EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp);
EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc);
EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp);
@@ -1366,7 +1366,7 @@
" #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n"
" #01 pc 000000000005426c linker64 "
"(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
- " #02 pc 00000000000008bc vdso.so\n"
+ " #02 pc 00000000000008c0 vdso.so (__kernel_rt_sigreturn)\n"
" #03 pc 00000000000846f4 libc.so (abort+172)\n"
" #04 pc 0000000000084ad4 libc.so (__assert2+36)\n"
" #05 pc 000000000003d5b4 ANGLEPrebuilt.apk (offset 0x21d5000)\n"
@@ -1377,7 +1377,7 @@
EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp);
- EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc);
+ EXPECT_EQ(0x7e82b018c0ULL, unwinder.frames()[2].pc);
EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp);
EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc);
EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 48e038e..f635021 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -108,6 +108,24 @@
const auto& info2 = *--maps_->end();
info2->elf_offset = 0x8000;
+ elf = new ElfFake(new MemoryFake);
+ elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/unreadable.so", elf);
+ const auto& info3 = *--maps_->end();
+ info3->memory_backed_elf = true;
+
+ elf = new ElfFake(new MemoryFake);
+ elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
+ const auto& info4 = *--maps_->end();
+ info4->memory_backed_elf = true;
+
+ elf = new ElfFake(new MemoryFake);
+ elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
+ const auto& info5 = *--maps_->end();
+ info5->memory_backed_elf = true;
+
process_memory_.reset(new MemoryFake);
}
@@ -140,6 +158,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -204,6 +223,7 @@
unwinder.SetResolveNames(false);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -263,6 +283,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -292,6 +313,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -321,6 +343,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -351,6 +374,7 @@
unwinder.SetEmbeddedSoname(false);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -387,6 +411,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -419,6 +444,7 @@
Unwinder unwinder(20, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(20U, unwinder.NumFrames());
@@ -461,6 +487,7 @@
std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
unwinder.Unwind(&skip_libs);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -522,6 +549,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -569,6 +597,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
}
@@ -588,6 +617,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
}
@@ -602,6 +632,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -638,6 +669,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -703,6 +735,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -752,6 +785,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -799,6 +833,7 @@
std::vector<std::string> skip_names{"libanother.so"};
unwinder.Unwind(&skip_names);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(0U, unwinder.NumFrames());
}
@@ -821,6 +856,7 @@
std::vector<std::string> suffixes{"oat"};
unwinder.Unwind(nullptr, &suffixes);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
// Make sure the elf was not initialized.
@@ -879,6 +915,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -937,6 +974,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -980,6 +1018,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1026,6 +1065,7 @@
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -1084,6 +1124,7 @@
Unwinder unwinder(1, maps_.get(), ®s_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1103,6 +1144,96 @@
EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
+TEST_F(UnwinderTest, elf_from_memory_not_file) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+ regs_.set_pc(0xc0050);
+ regs_.set_sp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_TRUE(unwinder.elf_from_memory_not_file());
+
+ ASSERT_EQ(1U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0x50U, frame->rel_pc);
+ EXPECT_EQ(0xc0050U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/fake/unreadable.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xc0000U, frame->map_start);
+ EXPECT_EQ(0xc1000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, elf_from_memory_but_no_valid_file_with_bracket) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+ regs_.set_pc(0xc1050);
+ regs_.set_sp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+ ASSERT_EQ(1U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0x50U, frame->rel_pc);
+ EXPECT_EQ(0xc1050U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("[vdso]", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xc1000U, frame->map_start);
+ EXPECT_EQ(0xc2000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, elf_from_memory_but_empty_filename) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+ regs_.set_pc(0xc2050);
+ regs_.set_sp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+ ASSERT_EQ(1U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0x50U, frame->rel_pc);
+ EXPECT_EQ(0xc2050U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xc2000U, frame->map_start);
+ EXPECT_EQ(0xc3000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
// Verify format frame code.
TEST_F(UnwinderTest, format_frame) {
RegsFake regs_arm(10);
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index bc1543b..858c0bb 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -26,6 +26,8 @@
// Incorrectly warns when C++11 empty brace {} initializer is used.
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61489
"-Wno-missing-field-initializers",
+ "-Wconversion",
+ "-Wno-sign-conversion",
],
// Enable -Wold-style-cast only for non-Windows targets. _islower_l,
diff --git a/libziparchive/entry_name_utils-inl.h b/libziparchive/entry_name_utils-inl.h
index 1714586..10311b5 100644
--- a/libziparchive/entry_name_utils-inl.h
+++ b/libziparchive/entry_name_utils-inl.h
@@ -20,9 +20,15 @@
#include <stddef.h>
#include <stdint.h>
+#include <limits>
+
// Check if |length| bytes at |entry_name| constitute a valid entry name.
-// Entry names must be valid UTF-8 and must not contain '0'.
+// Entry names must be valid UTF-8 and must not contain '0'. They also must
+// fit into the central directory record.
inline bool IsValidEntryName(const uint8_t* entry_name, const size_t length) {
+ if (length > std::numeric_limits<uint16_t>::max()) {
+ return false;
+ }
for (size_t i = 0; i < length; ++i) {
const uint8_t byte = entry_name[i];
if (byte == 0) {
@@ -35,7 +41,8 @@
return false;
} else {
// 2-5 byte sequences.
- for (uint8_t first = (byte & 0x7f) << 1; first & 0x80; first = (first & 0x7f) << 1) {
+ for (uint8_t first = static_cast<uint8_t>((byte & 0x7f) << 1); first & 0x80;
+ first = static_cast<uint8_t>((first & 0x7f) << 1)) {
++i;
// Missing continuation byte..
diff --git a/libziparchive/include/ziparchive/zip_writer.h b/libziparchive/include/ziparchive/zip_writer.h
index f6c8427..bd44fdb 100644
--- a/libziparchive/include/ziparchive/zip_writer.h
+++ b/libziparchive/include/ziparchive/zip_writer.h
@@ -76,7 +76,7 @@
uint32_t uncompressed_size;
uint16_t last_mod_time;
uint16_t last_mod_date;
- uint32_t padding_length;
+ uint16_t padding_length;
off64_t local_file_header_offset;
};
@@ -161,8 +161,8 @@
int32_t HandleError(int32_t error_code);
int32_t PrepareDeflate();
- int32_t StoreBytes(FileEntry* file, const void* data, size_t len);
- int32_t CompressBytes(FileEntry* file, const void* data, size_t len);
+ int32_t StoreBytes(FileEntry* file, const void* data, uint32_t len);
+ int32_t CompressBytes(FileEntry* file, const void* data, uint32_t len);
int32_t FlushCompressedBytes(FileEntry* file);
enum class State {
diff --git a/libziparchive/unzip.cpp b/libziparchive/unzip.cpp
index 6756007..c6def73 100644
--- a/libziparchive/unzip.cpp
+++ b/libziparchive/unzip.cpp
@@ -17,6 +17,7 @@
#include <errno.h>
#include <error.h>
#include <fcntl.h>
+#include <fnmatch.h>
#include <getopt.h>
#include <inttypes.h>
#include <stdio.h>
@@ -52,9 +53,21 @@
static uint64_t total_compressed_length = 0;
static size_t file_count = 0;
-static bool Filter(const std::string& name) {
- if (!excludes.empty() && excludes.find(name) != excludes.end()) return true;
- if (!includes.empty() && includes.find(name) == includes.end()) return true;
+static bool ShouldInclude(const std::string& name) {
+ // Explicitly excluded?
+ if (!excludes.empty()) {
+ for (const auto& exclude : excludes) {
+ if (!fnmatch(exclude.c_str(), name.c_str(), 0)) return false;
+ }
+ }
+
+ // Implicitly included?
+ if (includes.empty()) return true;
+
+ // Explicitly included?
+ for (const auto& include : includes) {
+ if (!fnmatch(include.c_str(), name.c_str(), 0)) return true;
+ }
return false;
}
@@ -72,7 +85,7 @@
static int CompressionRatio(int64_t uncompressed, int64_t compressed) {
if (uncompressed == 0) return 0;
- return (100LL * (uncompressed - compressed)) / uncompressed;
+ return static_cast<int>((100LL * (uncompressed - compressed)) / uncompressed);
}
static void MaybeShowHeader() {
@@ -245,7 +258,7 @@
ZipString string;
while ((err = Next(cookie, &entry, &string)) >= 0) {
std::string name(string.name, string.name + string.name_length);
- if (!Filter(name)) ProcessOne(zah, entry, name);
+ if (ShouldInclude(name)) ProcessOne(zah, entry, name);
}
if (err < -1) error(1, 0, "failed iterating %s: %s", archive_name, ErrorCodeString(err));
@@ -260,7 +273,8 @@
printf(
"\n"
- "Extract FILEs from ZIP archive. Default is all files.\n"
+ "Extract FILEs from ZIP archive. Default is all files. Both the include and\n"
+ "exclude (-x) lists use shell glob patterns.\n"
"\n"
"-d DIR Extract into DIR\n"
"-l List contents (-lq excludes archive name, -lv is verbose)\n"
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index e1ec47a..596786a 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -146,7 +146,7 @@
/*
* Add a new entry to the hash table.
*/
-static int32_t AddToHash(ZipStringOffset* hash_table, const uint64_t hash_table_size,
+static int32_t AddToHash(ZipStringOffset* hash_table, const uint32_t hash_table_size,
const ZipString& name, const uint8_t* start) {
const uint64_t hash = ComputeHash(name);
uint32_t ent = hash & (hash_table_size - 1);
@@ -214,7 +214,7 @@
}
static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
- off64_t file_length, off64_t read_amount,
+ off64_t file_length, uint32_t read_amount,
uint8_t* scan_buffer) {
const off64_t search_start = file_length - read_amount;
@@ -230,7 +230,8 @@
* doing an initial minimal read; if we don't find it, retry with a
* second read as above.)
*/
- int i = read_amount - sizeof(EocdRecord);
+ CHECK_LE(read_amount, std::numeric_limits<int32_t>::max());
+ int32_t i = read_amount - sizeof(EocdRecord);
for (; i >= 0; i--) {
if (scan_buffer[i] == 0x50) {
uint32_t* sig_addr = reinterpret_cast<uint32_t*>(&scan_buffer[i]);
@@ -333,9 +334,9 @@
*
* We start by pulling in the last part of the file.
*/
- off64_t read_amount = kMaxEOCDSearch;
+ uint32_t read_amount = kMaxEOCDSearch;
if (file_length < read_amount) {
- read_amount = file_length;
+ read_amount = static_cast<uint32_t>(file_length);
}
std::vector<uint8_t> scan_buffer(read_amount);
@@ -532,7 +533,7 @@
return 0;
}
-static int32_t FindEntry(const ZipArchive* archive, const int ent, ZipEntry* data) {
+static int32_t FindEntry(const ZipArchive* archive, const int32_t ent, ZipEntry* data) {
const uint16_t nameLen = archive->hash_table[ent].name_length;
// Recover the start of the central directory entry from the filename
@@ -751,9 +752,10 @@
archive->central_directory.GetBasePtr());
if (ent < 0) {
ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name);
- return ent;
+ return static_cast<int32_t>(ent); // kEntryNotFound is safe to truncate.
}
- return FindEntry(archive, ent, data);
+ // We know there are at most hast_table_size entries, safe to truncate.
+ return FindEntry(archive, static_cast<uint32_t>(ent), data);
}
int32_t Next(void* cookie, ZipEntry* data, ZipString* name) {
@@ -836,7 +838,6 @@
return FileWriter{};
}
- int result = 0;
#if defined(__linux__)
if (declared_length > 0) {
// Make sure we have enough space on the volume to extract the compressed
@@ -848,7 +849,7 @@
// EOPNOTSUPP error when issued in other filesystems.
// Hence, check for the return error code before concluding that the
// disk does not have enough space.
- result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
+ long result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
if (result == -1 && errno == ENOSPC) {
ALOGW("Zip: unable to allocate %" PRId64 " bytes at offset %" PRId64 ": %s",
static_cast<int64_t>(declared_length), static_cast<int64_t>(current_offset),
@@ -866,7 +867,7 @@
// Block device doesn't support ftruncate(2).
if (!S_ISBLK(sb.st_mode)) {
- result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+ long result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
if (result == -1) {
ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
static_cast<int64_t>(declared_length + current_offset), strerror(errno));
@@ -985,16 +986,16 @@
std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
const bool compute_crc = (crc_out != nullptr);
- uint64_t crc = 0;
+ uLong crc = 0;
uint32_t remaining_bytes = compressed_length;
do {
/* read as much as we can */
if (zstream.avail_in == 0) {
- const size_t read_size = (remaining_bytes > kBufSize) ? kBufSize : remaining_bytes;
+ const uint32_t read_size = (remaining_bytes > kBufSize) ? kBufSize : remaining_bytes;
const uint32_t offset = (compressed_length - remaining_bytes);
// Make sure to read at offset to ensure concurrent access to the fd.
if (!reader.ReadAtOffset(read_buf.data(), read_size, offset)) {
- ALOGW("Zip: inflate read failed, getSize = %zu: %s", read_size, strerror(errno));
+ ALOGW("Zip: inflate read failed, getSize = %u: %s", read_size, strerror(errno));
return kIoError;
}
@@ -1018,7 +1019,8 @@
if (!writer->Append(&write_buf[0], write_size)) {
return kIoError;
} else if (compute_crc) {
- crc = crc32(crc, &write_buf[0], write_size);
+ DCHECK_LE(write_size, kBufSize);
+ crc = crc32(crc, &write_buf[0], static_cast<uint32_t>(write_size));
}
zstream.next_out = &write_buf[0];
@@ -1063,17 +1065,17 @@
const uint32_t length = entry->uncompressed_length;
uint32_t count = 0;
- uint64_t crc = 0;
+ uLong crc = 0;
while (count < length) {
uint32_t remaining = length - count;
off64_t offset = entry->offset + count;
// Safe conversion because kBufSize is narrow enough for a 32 bit signed value.
- const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
+ const uint32_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
// Make sure to read at offset to ensure concurrent access to the fd.
if (!mapped_zip.ReadAtOffset(buf.data(), block_size, offset)) {
- ALOGW("CopyFileToFile: copy read failed, block_size = %zu, offset = %" PRId64 ": %s",
+ ALOGW("CopyFileToFile: copy read failed, block_size = %u, offset = %" PRId64 ": %s",
block_size, static_cast<int64_t>(offset), strerror(errno));
return kIoError;
}
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index 9ec89b1..1ec95b6 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -27,6 +27,7 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <log/log.h>
#include <ziparchive/zip_archive.h>
@@ -77,6 +78,12 @@
}
const std::vector<uint8_t>* ZipArchiveStreamEntryUncompressed::Read() {
+ // Simple sanity check. The vector should *only* be handled by this code. A caller
+ // should not const-cast and modify the capacity. This may invalidate next_out.
+ //
+ // Note: it would be better to store the results of data() across Read calls.
+ CHECK_EQ(data_.capacity(), kBufSize);
+
if (length_ == 0) {
return nullptr;
}
@@ -97,7 +104,8 @@
if (bytes < data_.size()) {
data_.resize(bytes);
}
- computed_crc32_ = crc32(computed_crc32_, data_.data(), data_.size());
+ computed_crc32_ = static_cast<uint32_t>(
+ crc32(computed_crc32_, data_.data(), static_cast<uint32_t>(data_.size())));
length_ -= bytes;
offset_ += bytes;
return &data_;
@@ -192,9 +200,15 @@
}
const std::vector<uint8_t>* ZipArchiveStreamEntryCompressed::Read() {
+ // Simple sanity check. The vector should *only* be handled by this code. A caller
+ // should not const-cast and modify the capacity. This may invalidate next_out.
+ //
+ // Note: it would be better to store the results of data() across Read calls.
+ CHECK_EQ(out_.capacity(), kBufSize);
+
if (z_stream_.avail_out == 0) {
z_stream_.next_out = out_.data();
- z_stream_.avail_out = out_.size();
+ z_stream_.avail_out = static_cast<uint32_t>(out_.size());
;
}
@@ -203,7 +217,9 @@
if (compressed_length_ == 0) {
return nullptr;
}
- size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
+ DCHECK_LE(in_.size(), std::numeric_limits<uint32_t>::max()); // Should be buf size = 64k.
+ uint32_t bytes = (compressed_length_ > in_.size()) ? static_cast<uint32_t>(in_.size())
+ : compressed_length_;
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
errno = 0;
if (!archive->mapped_zip.ReadAtOffset(in_.data(), bytes, offset_)) {
@@ -230,14 +246,16 @@
if (z_stream_.avail_out == 0) {
uncompressed_length_ -= out_.size();
- computed_crc32_ = crc32(computed_crc32_, out_.data(), out_.size());
+ computed_crc32_ = static_cast<uint32_t>(
+ crc32(computed_crc32_, out_.data(), static_cast<uint32_t>(out_.size())));
return &out_;
}
if (zerr == Z_STREAM_END) {
if (z_stream_.avail_out != 0) {
// Resize the vector down to the actual size of the data.
out_.resize(out_.size() - z_stream_.avail_out);
- computed_crc32_ = crc32(computed_crc32_, out_.data(), out_.size());
+ computed_crc32_ = static_cast<uint32_t>(
+ crc32(computed_crc32_, out_.data(), static_cast<uint32_t>(out_.size())));
uncompressed_length_ -= out_.size();
return &out_;
}
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index cea42d4..e471d5e 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -27,6 +27,7 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/mapped_file.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
@@ -65,7 +66,8 @@
static void SetZipString(ZipString* zip_str, const std::string& str) {
zip_str->name = reinterpret_cast<const uint8_t*>(str.c_str());
- zip_str->name_length = str.size();
+ CHECK_LE(str.size(), std::numeric_limits<uint16_t>::max());
+ zip_str->name_length = static_cast<uint16_t>(str.size());
}
TEST(ziparchive, Open) {
@@ -332,7 +334,7 @@
// Extract the entry to memory.
std::vector<uint8_t> buffer(kAbUncompressedSize);
- ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
+ ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], static_cast<uint32_t>(buffer.size())));
// Extract the entry to a file.
TemporaryFile tmp_output_file;
@@ -415,7 +417,8 @@
ASSERT_EQ(0, fstat(fd, &sb));
// Memory map the file first and open the archive from the memory region.
- auto file_map{android::base::MappedFile::FromFd(fd, 0, sb.st_size, PROT_READ)};
+ auto file_map{
+ android::base::MappedFile::FromFd(fd, 0, static_cast<size_t>(sb.st_size), PROT_READ)};
ZipArchiveHandle handle;
ASSERT_EQ(0,
OpenArchiveFromMemory(file_map->data(), file_map->size(), zip_path.c_str(), &handle));
@@ -488,7 +491,8 @@
std::vector<uint8_t> cmp_data(entry.uncompressed_length);
ASSERT_EQ(entry.uncompressed_length, read_data.size());
- ASSERT_EQ(0, ExtractToMemory(handle, &entry, cmp_data.data(), cmp_data.size()));
+ ASSERT_EQ(
+ 0, ExtractToMemory(handle, &entry, cmp_data.data(), static_cast<uint32_t>(cmp_data.size())));
ASSERT_TRUE(memcmp(read_data.data(), cmp_data.data(), read_data.size()) == 0);
CloseArchive(handle);
@@ -737,8 +741,8 @@
};
TEST(ziparchive, Inflate) {
- const uint32_t compressed_length = kATxtContentsCompressed.size();
- const uint32_t uncompressed_length = kATxtContents.size();
+ const uint32_t compressed_length = static_cast<uint32_t>(kATxtContentsCompressed.size());
+ const uint32_t uncompressed_length = static_cast<uint32_t>(kATxtContents.size());
const VectorReader reader(kATxtContentsCompressed);
{
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 0df0fa5..ae9d145 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -169,8 +169,8 @@
year = 80;
}
- *out_date = (year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday;
- *out_time = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
+ *out_date = static_cast<uint16_t>((year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday);
+ *out_time = static_cast<uint16_t>(ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1);
}
static void CopyFromFileEntry(const ZipWriter::FileEntry& src, bool use_data_descriptor,
@@ -193,7 +193,8 @@
dst->compression_method = src.compression_method;
dst->last_mod_time = src.last_mod_time;
dst->last_mod_date = src.last_mod_date;
- dst->file_name_length = src.path.size();
+ DCHECK_LE(src.path.size(), std::numeric_limits<uint16_t>::max());
+ dst->file_name_length = static_cast<uint16_t>(src.path.size());
dst->extra_field_length = src.padding_length;
}
@@ -203,6 +204,11 @@
return kInvalidState;
}
+ // Can only have 16535 entries because of zip records.
+ if (files_.size() == std::numeric_limits<uint16_t>::max()) {
+ return HandleError(kIoError);
+ }
+
if (flags & kAlign32) {
return kInvalidAlign32Flag;
}
@@ -210,10 +216,17 @@
if (powerof2(alignment) == 0) {
return kInvalidAlignment;
}
+ if (alignment > std::numeric_limits<uint16_t>::max()) {
+ return kInvalidAlignment;
+ }
FileEntry file_entry = {};
file_entry.local_file_header_offset = current_offset_;
file_entry.path = path;
+ // No support for larger than 4GB files.
+ if (file_entry.local_file_header_offset > std::numeric_limits<uint32_t>::max()) {
+ return HandleError(kIoError);
+ }
if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(file_entry.path.data()),
file_entry.path.size())) {
@@ -237,7 +250,7 @@
std::vector<char> zero_padding;
if (alignment != 0 && (offset & (alignment - 1))) {
// Pad the extra field so the data will be aligned.
- uint16_t padding = alignment - (offset % alignment);
+ uint16_t padding = static_cast<uint16_t>(alignment - (offset % alignment));
file_entry.padding_length = padding;
offset += padding;
zero_padding.resize(padding, 0);
@@ -314,7 +327,8 @@
}
z_stream_->next_out = buffer_.data();
- z_stream_->avail_out = buffer_.size();
+ DCHECK_EQ(buffer_.size(), kBufSize);
+ z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
return kNoError;
}
@@ -322,25 +336,31 @@
if (state_ != State::kWritingEntry) {
return HandleError(kInvalidState);
}
+ // Need to be able to mark down data correctly.
+ if (len + static_cast<uint64_t>(current_file_entry_.uncompressed_size) >
+ std::numeric_limits<uint32_t>::max()) {
+ return HandleError(kIoError);
+ }
+ uint32_t len32 = static_cast<uint32_t>(len);
int32_t result = kNoError;
if (current_file_entry_.compression_method & kCompressDeflated) {
- result = CompressBytes(¤t_file_entry_, data, len);
+ result = CompressBytes(¤t_file_entry_, data, len32);
} else {
- result = StoreBytes(¤t_file_entry_, data, len);
+ result = StoreBytes(¤t_file_entry_, data, len32);
}
if (result != kNoError) {
return result;
}
- current_file_entry_.crc32 =
- crc32(current_file_entry_.crc32, reinterpret_cast<const Bytef*>(data), len);
- current_file_entry_.uncompressed_size += len;
+ current_file_entry_.crc32 = static_cast<uint32_t>(
+ crc32(current_file_entry_.crc32, reinterpret_cast<const Bytef*>(data), len32));
+ current_file_entry_.uncompressed_size += len32;
return kNoError;
}
-int32_t ZipWriter::StoreBytes(FileEntry* file, const void* data, size_t len) {
+int32_t ZipWriter::StoreBytes(FileEntry* file, const void* data, uint32_t len) {
CHECK(state_ == State::kWritingEntry);
if (fwrite(data, 1, len, file_) != len) {
@@ -351,7 +371,7 @@
return kNoError;
}
-int32_t ZipWriter::CompressBytes(FileEntry* file, const void* data, size_t len) {
+int32_t ZipWriter::CompressBytes(FileEntry* file, const void* data, uint32_t len) {
CHECK(state_ == State::kWritingEntry);
CHECK(z_stream_);
CHECK(z_stream_->next_out != nullptr);
@@ -379,7 +399,8 @@
// Reset the output buffer for the next input.
z_stream_->next_out = buffer_.data();
- z_stream_->avail_out = buffer_.size();
+ DCHECK_EQ(buffer_.size(), kBufSize);
+ z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
}
}
return kNoError;
@@ -404,7 +425,8 @@
current_offset_ += write_bytes;
z_stream_->next_out = buffer_.data();
- z_stream_->avail_out = buffer_.size();
+ DCHECK_EQ(buffer_.size(), kBufSize);
+ z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
}
if (zerr != Z_STREAM_END) {
return HandleError(kZlibError);
@@ -491,7 +513,11 @@
cdr.crc32 = file.crc32;
cdr.compressed_size = file.compressed_size;
cdr.uncompressed_size = file.uncompressed_size;
- cdr.file_name_length = file.path.size();
+ // Checked in IsValidEntryName.
+ DCHECK_LE(file.path.size(), std::numeric_limits<uint16_t>::max());
+ cdr.file_name_length = static_cast<uint16_t>(file.path.size());
+ // Checked in StartAlignedEntryWithTime.
+ DCHECK_LE(file.local_file_header_offset, std::numeric_limits<uint32_t>::max());
cdr.local_file_header_offset = static_cast<uint32_t>(file.local_file_header_offset);
if (fwrite(&cdr, sizeof(cdr), 1, file_) != 1) {
return HandleError(kIoError);
@@ -508,10 +534,15 @@
er.eocd_signature = EocdRecord::kSignature;
er.disk_num = 0;
er.cd_start_disk = 0;
- er.num_records_on_disk = files_.size();
- er.num_records = files_.size();
- er.cd_size = current_offset_ - startOfCdr;
- er.cd_start_offset = startOfCdr;
+ // Checked when adding entries.
+ DCHECK_LE(files_.size(), std::numeric_limits<uint16_t>::max());
+ er.num_records_on_disk = static_cast<uint16_t>(files_.size());
+ er.num_records = static_cast<uint16_t>(files_.size());
+ if (current_offset_ > std::numeric_limits<uint32_t>::max()) {
+ return HandleError(kIoError);
+ }
+ er.cd_size = static_cast<uint32_t>(current_offset_ - startOfCdr);
+ er.cd_start_offset = static_cast<uint32_t>(startOfCdr);
if (fwrite(&er, sizeof(er), 1, file_) != 1) {
return HandleError(kIoError);
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index 7322afb..63adbbc 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -279,7 +279,8 @@
std::vector<uint8_t> decompress(kBufSize);
memset(decompress.data(), 0, kBufSize);
- ASSERT_EQ(0, ExtractToMemory(handle, &data, decompress.data(), decompress.size()));
+ ASSERT_EQ(0, ExtractToMemory(handle, &data, decompress.data(),
+ static_cast<uint32_t>(decompress.size())));
EXPECT_EQ(0, memcmp(decompress.data(), buffer.data(), kBufSize))
<< "Input buffer and output buffer are different.";
@@ -391,7 +392,7 @@
actual.resize(expected.size());
uint8_t* buffer = reinterpret_cast<uint8_t*>(&*actual.begin());
- if (ExtractToMemory(handle, zip_entry, buffer, actual.size()) != 0) {
+ if (ExtractToMemory(handle, zip_entry, buffer, static_cast<uint32_t>(actual.size())) != 0) {
return ::testing::AssertionFailure() << "failed to extract entry";
}
diff --git a/logd/Android.bp b/logd/Android.bp
index 360f2fe..9b86258 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -80,6 +80,24 @@
cflags: ["-Werror"],
}
+cc_binary {
+ name: "auditctl",
+
+ srcs: ["auditctl.cpp"],
+
+ static_libs: [
+ "liblogd",
+ ],
+
+ shared_libs: ["libbase"],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wconversion"
+ ],
+}
prebuilt_etc {
name: "logtagd.rc",
diff --git a/logd/auditctl.cpp b/logd/auditctl.cpp
new file mode 100644
index 0000000..98bb02d
--- /dev/null
+++ b/logd/auditctl.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/parseint.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libaudit.h"
+
+static void usage(const char* cmdline) {
+ fprintf(stderr, "Usage: %s [-r rate]\n", cmdline);
+}
+
+static void do_update_rate(uint32_t rate) {
+ int fd = audit_open();
+ if (fd == -1) {
+ error(EXIT_FAILURE, errno, "Unable to open audit socket");
+ }
+ int result = audit_rate_limit(fd, rate);
+ close(fd);
+ if (result < 0) {
+ fprintf(stderr, "Can't update audit rate limit: %d\n", result);
+ exit(EXIT_FAILURE);
+ }
+}
+
+int main(int argc, char* argv[]) {
+ uint32_t rate = 0;
+ bool update_rate = false;
+ int opt;
+
+ while ((opt = getopt(argc, argv, "r:")) != -1) {
+ switch (opt) {
+ case 'r':
+ if (!android::base::ParseUint<uint32_t>(optarg, &rate)) {
+ error(EXIT_FAILURE, errno, "Invalid Rate");
+ }
+ update_rate = true;
+ break;
+ default: /* '?' */
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ // In the future, we may add other options to auditctl
+ // so this if statement will expand.
+ // if (!update_rate && !update_backlog && !update_whatever) ...
+ if (!update_rate) {
+ fprintf(stderr, "Nothing to do\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (update_rate) {
+ do_update_rate(rate);
+ }
+
+ return 0;
+}
diff --git a/logd/libaudit.c b/logd/libaudit.c
index 9d9a857..f452c71 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -160,8 +160,7 @@
* and the the mask set to AUDIT_STATUS_PID
*/
status.pid = pid;
- status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
- status.rate_limit = AUDIT_RATE_LIMIT; /* audit entries per second */
+ status.mask = AUDIT_STATUS_PID;
/* Let the kernel know this pid will be registering for audit events */
rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
@@ -188,6 +187,14 @@
return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
}
+int audit_rate_limit(int fd, uint32_t limit) {
+ struct audit_status status;
+ memset(&status, 0, sizeof(status));
+ status.mask = AUDIT_STATUS_RATE_LIMIT;
+ status.rate_limit = limit; /* audit entries per second */
+ return audit_send(fd, AUDIT_SET, &status, sizeof(status));
+}
+
int audit_get_reply(int fd, struct audit_message* rep, reply_t block, int peek) {
ssize_t len;
int flags;
diff --git a/logd/libaudit.h b/logd/libaudit.h
index 2a93ea3..b4a92a8 100644
--- a/logd/libaudit.h
+++ b/logd/libaudit.h
@@ -89,8 +89,17 @@
*/
extern int audit_setup(int fd, pid_t pid);
-/* Max audit messages per second */
-#define AUDIT_RATE_LIMIT 5
+/**
+ * Throttle kernel messages at the provided rate
+ * @param fd
+ * The fd returned by a call to audit_open()
+ * @param rate
+ * The rate, in messages per second, above which the kernel
+ * should drop audit messages.
+ * @return
+ * This function returns 0 on success, -errno on error.
+ */
+extern int audit_rate_limit(int fd, uint32_t limit);
__END_DECLS
diff --git a/logd/logd.rc b/logd/logd.rc
index c740ecf..438419a 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -16,8 +16,19 @@
group logd
writepid /dev/cpuset/system-background/tasks
+# Limit SELinux denial generation to 5/second
+service logd-auditctl /system/bin/auditctl -r 5
+ oneshot
+ disabled
+ user logd
+ group logd
+ capabilities AUDIT_CONTROL
+
on fs
write /dev/event-log-tags "# content owned by logd
"
chown logd logd /dev/event-log-tags
chmod 0644 /dev/event-log-tags
+
+on property:sys.boot_completed=1
+ start logd-auditctl
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 7d7a22f..447b067 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -39,7 +39,6 @@
#endif
#include "../LogReader.h" // pickup LOGD_SNDTIMEO
-#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_*
#ifdef __ANDROID__
static void send_to_control(char* buf, size_t len) {
@@ -1065,145 +1064,3 @@
TEST(logd, multiple_test_10) {
__android_log_btwrite_multiple__helper(10);
}
-
-#ifdef __ANDROID__
-// returns violating pid
-static pid_t sepolicy_rate(unsigned rate, unsigned num) {
- pid_t pid = fork();
-
- if (pid) {
- siginfo_t info = {};
- if (TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))) return -1;
- if (info.si_status) return -1;
- return pid;
- }
-
- // We may have DAC, but let's not have MAC
- if ((setcon("u:object_r:shell:s0") < 0) && (setcon("u:r:shell:s0") < 0)) {
- int save_errno = errno;
- security_context_t context;
- getcon(&context);
- if (strcmp(context, "u:r:shell:s0")) {
- fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n",
- context, strerror(save_errno));
- freecon(context);
- _exit(-1);
- // NOTREACHED
- return -1;
- }
- }
-
- // The key here is we are root, but we are in u:r:shell:s0,
- // and the directory does not provide us DAC access
- // (eg: 0700 system system) so we trigger the pair dac_override
- // and dac_read_search on every try to get past the message
- // de-duper. We will also rotate the file name in the directory
- // as another measure.
- static const char file[] = "/data/drm/cannot_access_directory_%u";
- static const unsigned avc_requests_per_access = 2;
-
- rate /= avc_requests_per_access;
- useconds_t usec;
- if (rate == 0) {
- rate = 1;
- usec = 2000000;
- } else {
- usec = (1000000 + (rate / 2)) / rate;
- }
- num = (num + (avc_requests_per_access / 2)) / avc_requests_per_access;
-
- if (usec < 2) usec = 2;
-
- while (num > 0) {
- if (access(android::base::StringPrintf(file, num).c_str(), F_OK) == 0) {
- _exit(-1);
- // NOTREACHED
- return -1;
- }
- usleep(usec);
- --num;
- }
- _exit(0);
- // NOTREACHED
- return -1;
-}
-
-static constexpr int background_period = 10;
-
-static int count_avc(pid_t pid) {
- int count = 0;
-
- // pid=-1 skip as pid is in error
- if (pid == (pid_t)-1) return count;
-
- // pid=0 means we want to report the background count of avc: activities
- struct logger_list* logger_list =
- pid ? android_logger_list_alloc(
- ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)
- : android_logger_list_alloc_time(
- ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
- log_time(android_log_clockid()) -
- log_time(background_period, 0),
- 0);
- if (!logger_list) return count;
- struct logger* logger = android_logger_open(logger_list, LOG_ID_EVENTS);
- if (!logger) {
- android_logger_list_close(logger_list);
- return count;
- }
- for (;;) {
- log_msg log_msg;
-
- if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
-
- if ((log_msg.entry.pid != pid) || (log_msg.entry.len < (4 + 1 + 8)) ||
- (log_msg.id() != LOG_ID_EVENTS))
- continue;
-
- char* eventData = log_msg.msg();
- if (!eventData) continue;
-
- uint32_t tag = get4LE(eventData);
- if (tag != AUDITD_LOG_TAG) continue;
-
- if (eventData[4] != EVENT_TYPE_STRING) continue;
-
- // int len = get4LE(eventData + 4 + 1);
- log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
- const char* cp = strstr(eventData + 4 + 1 + 4, "): avc: denied");
- if (!cp) continue;
-
- ++count;
- }
-
- android_logger_list_close(logger_list);
-
- return count;
-}
-#endif
-
-TEST(logd, sepolicy_rate_limiter) {
-#ifdef __ANDROID__
- int background_selinux_activity_too_high = count_avc(0);
- if (background_selinux_activity_too_high > 2) {
- GTEST_LOG_(ERROR) << "Too much background selinux activity "
- << background_selinux_activity_too_high * 60 /
- background_period
- << "/minute on the device, this test\n"
- << "can not measure the functionality of the "
- << "sepolicy rate limiter. Expect test to\n"
- << "fail as this device is in a bad state, "
- << "but is not strictly a unit test failure.";
- }
-
- static const int rate = AUDIT_RATE_LIMIT;
- static const int duration = 2;
- // Two seconds of sustained denials. Depending on the overlap in the time
- // window that the kernel is considering vs what this test is considering,
- // allow some additional denials to prevent a flaky test.
- EXPECT_LE(count_avc(sepolicy_rate(rate, rate * duration)),
- rate * duration + rate);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 462ae8b..f084cd2 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -97,7 +97,7 @@
#
# create some directories (some are mount points) and symlinks
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
- sbin dev proc sys system data odm oem acct config storage mnt apex $(BOARD_ROOT_EXTRA_FOLDERS)); \
+ dev proc sys system data odm oem acct config storage mnt apex debug_ramdisk $(BOARD_ROOT_EXTRA_FOLDERS)); \
ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
@@ -377,4 +377,13 @@
$(hide) $(foreach lib,$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES), \
echo $(lib).so >> $@;)
+#######################################
+# adb_debug.prop in debug ramdisk
+include $(CLEAR_VARS)
+LOCAL_MODULE := adb_debug.prop
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_DEBUG_RAMDISK_OUT)
+include $(BUILD_PREBUILT)
+
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/rootdir/adb_debug.prop b/rootdir/adb_debug.prop
new file mode 100644
index 0000000..37e2f2d
--- /dev/null
+++ b/rootdir/adb_debug.prop
@@ -0,0 +1,12 @@
+# Note: This file will be loaded with highest priority to override
+# other system properties, if a special ramdisk with "/force_debuggable"
+# is used and the device is unlocked.
+
+# Disable adb authentication to allow test automation on user build GSI
+ro.adb.secure=0
+
+# Allow 'adb root' on user build GSI
+ro.debuggable=1
+
+# Introduce this property to indicate that init has loaded adb_debug.prop
+ro.force.debuggable=1
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index 7324ba9..e081bdf 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -79,8 +79,10 @@
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
+# Need allow_all_shared_libs because libart.so can dlopen oat files in
+# /system/framework and /data.
+# TODO(b/130340935): Use a dynamically created linker namespace similar to
+# classloader-namespace for oat files, and tighten this up.
namespace.runtime.link.default.allow_all_shared_libs = true
###############################################################################
@@ -97,7 +99,6 @@
namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
namespace.media.links = default
-namespace.media.link.default.shared_libs = libandroid.so
namespace.media.link.default.shared_libs += libbinder_ndk.so
namespace.media.link.default.shared_libs += libc.so
namespace.media.link.default.shared_libs += libcgrouprc.so
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 45e80e1..3f9882a 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -158,8 +158,10 @@
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
+# Need allow_all_shared_libs because libart.so can dlopen oat files in
+# /system/framework and /data.
+# TODO(b/130340935): Use a dynamically created linker namespace similar to
+# classloader-namespace for oat files, and tighten this up.
namespace.runtime.link.default.allow_all_shared_libs = true
###############################################################################
@@ -177,7 +179,6 @@
namespace.media.links = default
namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
namespace.media.link.default.shared_libs += libbinder_ndk.so
namespace.media.link.default.shared_libs += libmediametrics.so
namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -436,8 +437,8 @@
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = system
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
+# TODO(b/130340935): Use a dynamically created linker namespace similar to
+# classloader-namespace for oat files, and tighten this up.
namespace.runtime.link.system.allow_all_shared_libs = true
###############################################################################
@@ -601,8 +602,8 @@
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
+# TODO(b/130340935): Use a dynamically created linker namespace similar to
+# classloader-namespace for oat files, and tighten this up.
namespace.runtime.link.default.allow_all_shared_libs = true
###############################################################################
@@ -620,7 +621,6 @@
namespace.media.links = default
namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
namespace.media.link.default.shared_libs += libbinder_ndk.so
namespace.media.link.default.shared_libs += libmediametrics.so
namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index a762ba8..6d89886 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -100,8 +100,10 @@
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
+# Need allow_all_shared_libs because libart.so can dlopen oat files in
+# /system/framework and /data.
+# TODO(b/130340935): Use a dynamically created linker namespace similar to
+# classloader-namespace for oat files, and tighten this up.
namespace.runtime.link.default.allow_all_shared_libs = true
###############################################################################
@@ -119,7 +121,6 @@
namespace.media.links = default
namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
namespace.media.link.default.shared_libs += libbinder_ndk.so
namespace.media.link.default.shared_libs += libmediametrics.so
namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -373,8 +374,8 @@
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
+# TODO(b/130340935): Use a dynamically created linker namespace similar to
+# classloader-namespace for oat files, and tighten this up.
namespace.runtime.link.default.allow_all_shared_libs = true
###############################################################################
@@ -424,8 +425,8 @@
namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
namespace.runtime.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
+# TODO(b/130340935): Use a dynamically created linker namespace similar to
+# classloader-namespace for oat files, and tighten this up.
namespace.runtime.link.default.allow_all_shared_libs = true
###############################################################################
@@ -443,7 +444,6 @@
namespace.media.links = default
namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
namespace.media.link.default.shared_libs += libbinder_ndk.so
namespace.media.link.default.shared_libs += libmediametrics.so
namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 473cd8d..295e704 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -13,9 +13,6 @@
# Cgroups are mounted right before early-init using list from /etc/cgroups.json
on early-init
- # Set init and its forked children's oom_adj.
- write /proc/1/oom_score_adj -1000
-
# Disable sysrq from keyboard
write /proc/sys/kernel/sysrq 0
@@ -280,6 +277,11 @@
write /dev/cpu_variant:${ro.bionic.2nd_arch} ${ro.bionic.2nd_cpu_variant}
chmod 0444 /dev/cpu_variant:${ro.bionic.2nd_arch}
+ # Allow system processes to read / write power state.
+ chown system system /sys/power/state
+ chown system system /sys/power/wakeup_count
+ chmod 0660 /sys/power/state
+
# Start logd before any other services run to ensure we capture all of their logs.
start logd
@@ -606,6 +608,10 @@
# IOCTLs on ashmem fds any more.
setprop sys.use_memfd false
+ # Set fscklog permission
+ chown root system /dev/fscklogs/log
+ chmod 0770 /dev/fscklogs/log
+
# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
@@ -665,11 +671,8 @@
chown radio system /sys/android_power/acquire_partial_wake_lock
chown radio system /sys/android_power/release_wake_lock
chown system system /sys/power/autosleep
- chown system system /sys/power/state
- chown system system /sys/power/wakeup_count
chown radio wakelock /sys/power/wake_lock
chown radio wakelock /sys/power/wake_unlock
- chmod 0660 /sys/power/state
chmod 0660 /sys/power/wake_lock
chmod 0660 /sys/power/wake_unlock
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index f01a8c7..3bc3883 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -10,6 +10,7 @@
phony {
name: "shell_and_utilities_system",
required: [
+ "auditctl",
"awk",
"bzip2",
"grep",