Merge changes I5fe02059,Iea8bf298,I0630c302,Ifc4b8fe9,I29319bda
* changes:
adb: bump the local socket backlog to the maximum.
adb: fix unicode file path test.
adb: delete vestigial SHELL_EXIT_NOTIFY_FD.
adb: don't immediately close a socket when write fails.
adb: make fdevent_run_on_main_thread's fd nonblocking.
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 86e8789..1043df1 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -239,6 +239,8 @@
return 0
}
+BAD_BOOTLOADER_REASON=
+
[ "USAGE: EXPECT_PROPERTY <prop> <value> [--allow_failure]
Returns true (0) if current return (regex) value is true and the result matches
@@ -249,9 +251,20 @@
value="${2}"
shift 2
val=`adb shell getprop ${property} 2>&1`
- EXPECT_EQ "${value}" "${val}" for Android property ${property} ||
- [ -n "${1}" ] ||
- save_ret=${?}
+ EXPECT_EQ "${value}" "${val}" for Android property ${property}
+ local_ret=${?}
+ if [ 0 != ${local_ret} -a "ro.boot.bootreason" = "${property}" ]; then
+ if [ -z "${BAD_BOOTLOADER_REASON}" ]; then
+ BAD_BOOTLOADER_REASON=${val}
+ elif [ X"${BAD_BOOTLOADER_REASON}" = X"${val}" ]; then
+ local_ret=0
+ fi
+ fi
+ if [ 0 != ${local_ret} ]; then
+ if [ -z "${1}" ] ; then
+ save_ret=${local_ret}
+ fi
+ fi
return ${save_ret}
}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index cfea6ee..29988c8 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -291,6 +291,10 @@
{"software_master", 147},
{"cold,charger", 148},
{"cold,rtc", 149},
+ {"cold,rtc,2sec", 150},
+ {"reboot,tool", 151},
+ {"reboot,wdt", 152},
+ {"reboot,unknown", 153},
};
// Converts a string value representing the reason the system booted to an
@@ -467,6 +471,8 @@
}
return std::string::npos;
}
+
+ operator const std::string&() const { return console; }
};
// If bit error match to needle, correct it.
@@ -503,12 +509,60 @@
return corrected;
}
+// Converts a string value representing the reason the system booted to a
+// string complying with Android system standard reason.
+void transformReason(std::string& reason) {
+ std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
+ std::transform(reason.begin(), reason.end(), reason.begin(),
+ [](char c) { return ::isblank(c) ? '_' : c; });
+ std::transform(reason.begin(), reason.end(), reason.begin(),
+ [](char c) { return ::isprint(c) ? c : '?'; });
+}
+
+// Pull out and correct quoted (') subreason, pos just beyond first quote.
+// Check subreasons for reboot,<subreason> and kernel_panic,sysrq,<subreason>
+std::string getSubreason(const std::string& content, size_t pos) {
+ static constexpr size_t max_reason_length = 256;
+
+ std::string subReason(content.substr(pos, max_reason_length));
+ // Correct against any known strings that Bit Error Match
+ for (const auto& s : knownReasons) {
+ correctForBitErrorOrUnderline(subReason, s);
+ }
+ for (const auto& m : kBootReasonMap) {
+ if (m.first.length() <= strlen("cold")) continue; // too short?
+ if (correctForBitErrorOrUnderline(subReason, m.first + "'")) continue;
+ if (m.first.length() <= strlen("reboot,cold")) continue; // short?
+ if (android::base::StartsWith(m.first, "reboot,")) {
+ correctForBitErrorOrUnderline(subReason, m.first.substr(strlen("reboot,")) + "'");
+ } else if (android::base::StartsWith(m.first, "kernel_panic,sysrq,")) {
+ correctForBitErrorOrUnderline(subReason, m.first.substr(strlen("kernel_panic,sysrq,")) + "'");
+ }
+ }
+ for (pos = 0; pos < subReason.length(); ++pos) {
+ char c = subReason[pos];
+ // #, &, %, / are common single bit error for ' that we can block
+ if (!::isprint(c) || (c == '\'') || (c == '#') || (c == '&') || (c == '%') || (c == '/')) {
+ subReason.erase(pos);
+ break;
+ }
+ }
+ transformReason(subReason);
+ return subReason;
+}
+
bool addKernelPanicSubReason(const pstoreConsole& console, std::string& ret) {
// Check for kernel panic types to refine information
if ((console.rfind("SysRq : Trigger a crash") != std::string::npos) ||
(console.rfind("PC is at sysrq_handle_crash+") != std::string::npos)) {
- // Can not happen, except on userdebug, during testing/debugging.
ret = "kernel_panic,sysrq";
+ // Invented for Android to allow daemons that specifically trigger sysrq
+ // to communicate more accurate boot subreasons via last console messages.
+ static constexpr char sysrqSubreason[] = "SysRq : Trigger a crash : '";
+ auto pos = console.rfind(sysrqSubreason);
+ if (pos != std::string::npos) {
+ ret += "," + getSubreason(console, pos + strlen(sysrqSubreason));
+ }
return true;
}
if (console.rfind("Unable to handle kernel NULL pointer dereference at virtual address") !=
@@ -527,24 +581,12 @@
return addKernelPanicSubReason(pstoreConsole(content), ret);
}
-// Converts a string value representing the reason the system booted to a
-// string complying with Android system standard reason.
-void transformReason(std::string& reason) {
- std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
- std::transform(reason.begin(), reason.end(), reason.begin(),
- [](char c) { return ::isblank(c) ? '_' : c; });
- std::transform(reason.begin(), reason.end(), reason.begin(),
- [](char c) { return ::isprint(c) ? c : '?'; });
-}
-
const char system_reboot_reason_property[] = "sys.boot.reason";
const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
// Scrub, Sanitize, Standardize and Enhance the boot reason string supplied.
std::string BootReasonStrToReason(const std::string& boot_reason) {
- static const size_t max_reason_length = 256;
-
std::string ret(GetProperty(system_reboot_reason_property));
std::string reason(boot_reason);
// If sys.boot.reason == ro.boot.bootreason, let's re-evaluate
@@ -647,28 +689,7 @@
static const char cmd[] = "reboot: Restarting system with command '";
size_t pos = console.rfind(cmd);
if (pos != std::string::npos) {
- pos += strlen(cmd);
- std::string subReason(content.substr(pos, max_reason_length));
- // Correct against any known strings that Bit Error Match
- for (const auto& s : knownReasons) {
- correctForBitErrorOrUnderline(subReason, s);
- }
- for (const auto& m : kBootReasonMap) {
- if (m.first.length() <= strlen("cold")) continue; // too short?
- if (correctForBitErrorOrUnderline(subReason, m.first + "'")) continue;
- if (m.first.length() <= strlen("reboot,cold")) continue; // short?
- if (!android::base::StartsWith(m.first, "reboot,")) continue;
- correctForBitErrorOrUnderline(subReason, m.first.substr(strlen("reboot,")) + "'");
- }
- for (pos = 0; pos < subReason.length(); ++pos) {
- char c = subReason[pos];
- // #, &, %, / are common single bit error for ' that we can block
- if (!::isprint(c) || (c == '\'') || (c == '#') || (c == '&') || (c == '%') || (c == '/')) {
- subReason.erase(pos);
- break;
- }
- }
- transformReason(subReason);
+ std::string subReason(getSubreason(content, pos + strlen(cmd)));
if (subReason != "") { // Will not land "reboot" as that is too blunt.
if (isKernelRebootReason(subReason)) {
ret = "reboot," + subReason; // User space can't talk kernel reasons.
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 45fa863..72f9f7b 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -18,8 +18,10 @@
#include <errno.h>
#include <inttypes.h>
+#include <pwd.h>
#include <sched.h>
#include <signal.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
@@ -71,6 +73,9 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
#define EIGHT_MEGA (1 << 23)
+/* Defined as ProcessList.SYSTEM_ADJ in ProcessList.java */
+#define SYSTEM_ADJ (-900)
+
/* default to old in-kernel interface if no memory pressure events */
static int use_inkernel_interface = 1;
static bool has_inkernel_module;
@@ -267,24 +272,32 @@
return 0;
}
-static void writefilestring(const char *path, char *s) {
+/*
+ * Write a string to a file.
+ * Returns false if the file does not exist.
+ */
+static bool writefilestring(const char *path, const char *s,
+ bool err_if_missing) {
int fd = open(path, O_WRONLY | O_CLOEXEC);
- int len = strlen(s);
- int ret;
+ ssize_t len = strlen(s);
+ ssize_t ret;
if (fd < 0) {
- ALOGE("Error opening %s; errno=%d", path, errno);
- return;
+ if (err_if_missing) {
+ ALOGE("Error opening %s; errno=%d", path, errno);
+ }
+ return false;
}
- ret = write(fd, s, len);
+ ret = TEMP_FAILURE_RETRY(write(fd, s, len));
if (ret < 0) {
ALOGE("Error writing %s; errno=%d", path, errno);
} else if (ret < len) {
- ALOGE("Short write on %s; length=%d", path, ret);
+ ALOGE("Short write on %s; length=%zd", path, ret);
}
close(fd);
+ return true;
}
static void cmd_procprio(LMKD_CTRL_PACKET packet) {
@@ -293,6 +306,8 @@
char val[20];
int soft_limit_mult;
struct lmk_procprio params;
+ bool is_system_server;
+ struct passwd *pwdrec;
lmkd_pack_get_procprio(packet, ¶ms);
@@ -304,7 +319,12 @@
snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", params.pid);
snprintf(val, sizeof(val), "%d", params.oomadj);
- writefilestring(path, val);
+ if (!writefilestring(path, val, false)) {
+ ALOGW("Failed to open %s; errno=%d: process %d might have been killed",
+ path, errno, params.pid);
+ /* If this file does not exist the process is dead. */
+ return;
+ }
if (use_inkernel_interface)
return;
@@ -341,7 +361,15 @@
"/dev/memcg/apps/uid_%d/pid_%d/memory.soft_limit_in_bytes",
params.uid, params.pid);
snprintf(val, sizeof(val), "%d", soft_limit_mult * EIGHT_MEGA);
- writefilestring(path, val);
+
+ /*
+ * system_server process has no memcg under /dev/memcg/apps but should be
+ * registered with lmkd. This is the best way so far to identify it.
+ */
+ is_system_server = (params.oomadj == SYSTEM_ADJ &&
+ (pwdrec = getpwnam("system")) != NULL &&
+ params.uid == pwdrec->pw_uid);
+ writefilestring(path, val, !is_system_server);
procp = pid_lookup(params.pid);
if (!procp) {
@@ -408,8 +436,8 @@
strlcat(killpriostr, val, sizeof(killpriostr));
}
- writefilestring(INKERNEL_MINFREE_PATH, minfreestr);
- writefilestring(INKERNEL_ADJ_PATH, killpriostr);
+ writefilestring(INKERNEL_MINFREE_PATH, minfreestr, true);
+ writefilestring(INKERNEL_ADJ_PATH, killpriostr, true);
}
}
@@ -727,7 +755,7 @@
r = kill(pid, SIGKILL);
ALOGI(
"Killing '%s' (%d), uid %d, adj %d\n"
- " to free %ldkB because system is under %s memory pressure oom_adj %d\n",
+ " to free %ldkB because system is under %s memory pressure (min_oom_adj=%d)\n",
taskname, pid, uid, procp->oomadj, tasksize * page_k,
level_name[level], min_score_adj);
pid_remove(pid);