Merge "fs_mgr: replace make_ext4 api with e2fsprogs"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index bfb1144..ff7b71f 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -49,6 +49,7 @@
#include "adb_auth.h"
#include "adb_io.h"
#include "adb_listeners.h"
+#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "sysdeps/chrono.h"
#include "transport.h"
@@ -656,6 +657,26 @@
#endif
+static void ReportServerStartupFailure(pid_t pid) {
+ fprintf(stderr, "ADB server didn't ACK\n");
+ fprintf(stderr, "Full server startup log: %s\n", GetLogFilePath().c_str());
+ fprintf(stderr, "Server had pid: %d\n", pid);
+
+ unique_fd fd(adb_open(GetLogFilePath().c_str(), O_RDONLY));
+ if (fd == -1) return;
+
+ // Let's not show more than 128KiB of log...
+ adb_lseek(fd, -128 * 1024, SEEK_END);
+ std::string content;
+ if (!android::base::ReadFdToString(fd, &content)) return;
+
+ std::string header = android::base::StringPrintf("--- adb starting (pid %d) ---", pid);
+ std::vector<std::string> lines = android::base::Split(content, "\n");
+ int i = lines.size() - 1;
+ while (i >= 0 && lines[i] != header) --i;
+ while (static_cast<size_t>(i) < lines.size()) fprintf(stderr, "%s\n", lines[i++].c_str());
+}
+
int launch_server(const std::string& socket_spec) {
#if defined(_WIN32)
/* we need to start the server in the background */
@@ -835,7 +856,8 @@
memcmp(temp, expected, expected_length) == 0) {
got_ack = true;
} else {
- fprintf(stderr, "ADB server didn't ACK\n");
+ ReportServerStartupFailure(GetProcessId(process_handle.get()));
+ return -1;
}
} else {
const DWORD err = GetLastError();
@@ -909,12 +931,9 @@
"--reply-fd", reply_fd, NULL);
// this should not return
fprintf(stderr, "adb: execl returned %d: %s\n", result, strerror(errno));
- } else {
+ } else {
// parent side of the fork
-
- char temp[3];
-
- temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
+ char temp[3] = {};
// wait for the "OK\n" message
adb_close(fd[1]);
int ret = adb_read(fd[0], temp, 3);
@@ -925,7 +944,7 @@
return -1;
}
if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
- fprintf(stderr, "ADB server didn't ACK\n" );
+ ReportServerStartupFailure(pid);
return -1;
}
}
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 6f2403d..bb26e70 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -278,3 +278,29 @@
fprintf(stderr, "\n");
return 1;
}
+
+std::string GetLogFilePath() {
+#if defined(_WIN32)
+ const char log_name[] = "adb.log";
+ WCHAR temp_path[MAX_PATH];
+
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx
+ DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path);
+ if (nchars >= arraysize(temp_path) || nchars == 0) {
+ // If string truncation or some other error.
+ fatal("cannot retrieve temporary file path: %s\n",
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ }
+
+ std::string temp_path_utf8;
+ if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) {
+ fatal_errno("cannot convert temporary file path from UTF-16 to UTF-8");
+ }
+
+ return temp_path_utf8 + log_name;
+#else
+ const char* tmp_dir = getenv("TMPDIR");
+ if (tmp_dir == nullptr) tmp_dir = "/tmp";
+ return android::base::StringPrintf("%s/adb.%u.log", tmp_dir, getuid());
+#endif
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 11c0ec9..f764a0e 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -89,4 +89,6 @@
}
};
+std::string GetLogFilePath();
+
#endif
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 62798cd..f0d0ce7 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -39,33 +39,7 @@
#include "sysdeps/chrono.h"
#include "transport.h"
-static std::string GetLogFilePath() {
-#if defined(_WIN32)
- const char log_name[] = "adb.log";
- WCHAR temp_path[MAX_PATH];
-
- // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx
- DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path);
- if (nchars >= arraysize(temp_path) || nchars == 0) {
- // If string truncation or some other error.
- fatal("cannot retrieve temporary file path: %s\n",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- }
-
- std::string temp_path_utf8;
- if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) {
- fatal_errno("cannot convert temporary file path from UTF-16 to UTF-8");
- }
-
- return temp_path_utf8 + log_name;
-#else
- const char* tmp_dir = getenv("TMPDIR");
- if (tmp_dir == nullptr) tmp_dir = "/tmp";
- return android::base::StringPrintf("%s/adb.%u.log", tmp_dir, getuid());
-#endif
-}
-
-static void setup_daemon_logging(void) {
+static void setup_daemon_logging() {
const std::string log_file_path(GetLogFilePath());
int fd = unix_open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0640);
if (fd == -1) {
diff --git a/init/devices.cpp b/init/devices.cpp
index c52d8f8..2943fb7 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -147,21 +147,34 @@
}
}
-// Given a path that may start with a platform device, find the length of the
-// platform device prefix. If it doesn't start with a platform device, return false
-bool PlatformDeviceList::Find(const std::string& path, std::string* out_path) const {
- out_path->clear();
- // platform_devices is searched backwards, since parents are added before their children,
- // and we want to match as deep of a child as we can.
- for (auto it = platform_devices_.crbegin(); it != platform_devices_.crend(); ++it) {
- auto platform_device_path_length = it->length();
- if (platform_device_path_length < path.length() &&
- path[platform_device_path_length] == '/' &&
- android::base::StartsWith(path, it->c_str())) {
- *out_path = *it;
+// Given a path that may start with a platform device, find the parent platform device by finding a
+// parent directory with a 'subsystem' symlink that points to the platform bus.
+// If it doesn't start with a platform device, return false
+bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_device_path) const {
+ platform_device_path->clear();
+
+ // Uevents don't contain the mount point, so we need to add it here.
+ path.insert(0, sysfs_mount_point_);
+
+ std::string directory = android::base::Dirname(path);
+
+ while (directory != "/" && directory != ".") {
+ std::string subsystem_link_path;
+ if (android::base::Realpath(directory + "/subsystem", &subsystem_link_path) &&
+ subsystem_link_path == sysfs_mount_point_ + "/bus/platform") {
+ // We need to remove the mount point that we added above before returning.
+ directory.erase(0, sysfs_mount_point_.size());
+ *platform_device_path = directory;
return true;
}
+
+ auto last_slash = path.rfind('/');
+ if (last_slash == std::string::npos) return false;
+
+ path.erase(last_slash);
+ directory = android::base::Dirname(path);
}
+
return false;
}
@@ -258,7 +271,7 @@
std::vector<std::string> DeviceHandler::GetCharacterDeviceSymlinks(const Uevent& uevent) const {
std::string parent_device;
- if (!platform_devices_.Find(uevent.path, &parent_device)) return {};
+ if (!FindPlatformDevice(uevent.path, &parent_device)) return {};
// skip path to the parent driver
std::string path = uevent.path.substr(parent_device.length());
@@ -316,7 +329,7 @@
std::string device;
std::string type;
- if (platform_devices_.Find(uevent.path, &device)) {
+ if (FindPlatformDevice(uevent.path, &device)) {
// Skip /devices/platform or /devices/ if present
static const std::string devices_platform_prefix = "/devices/platform/";
static const std::string devices_prefix = "/devices/";
@@ -388,14 +401,6 @@
}
}
-void DeviceHandler::HandlePlatformDeviceEvent(const Uevent& uevent) {
- if (uevent.action == "add") {
- platform_devices_.Add(uevent.path);
- } else if (uevent.action == "remove") {
- platform_devices_.Remove(uevent.path);
- }
-}
-
void DeviceHandler::HandleBlockDeviceEvent(const Uevent& uevent) const {
// if it's not a /dev device, nothing to do
if (uevent.major < 0 || uevent.minor < 0) return;
@@ -458,8 +463,6 @@
if (uevent.subsystem == "block") {
HandleBlockDeviceEvent(uevent);
- } else if (uevent.subsystem == "platform") {
- HandlePlatformDeviceEvent(uevent);
} else {
HandleGenericDeviceEvent(uevent);
}
@@ -472,7 +475,8 @@
sysfs_permissions_(std::move(sysfs_permissions)),
subsystems_(std::move(subsystems)),
sehandle_(selinux_android_file_context_handle()),
- skip_restorecon_(skip_restorecon) {}
+ skip_restorecon_(skip_restorecon),
+ sysfs_mount_point_("/sys") {}
DeviceHandler::DeviceHandler()
: DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
diff --git a/init/devices.h b/init/devices.h
index 09a0ce3..362c38c 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -93,20 +93,6 @@
DevnameSource devname_source_;
};
-class PlatformDeviceList {
- public:
- void Add(const std::string& path) { platform_devices_.emplace_back(path); }
- void Remove(const std::string& path) {
- auto it = std::find(platform_devices_.begin(), platform_devices_.end(), path);
- if (it != platform_devices_.end()) platform_devices_.erase(it);
- }
- bool Find(const std::string& path, std::string* out_path) const;
- auto size() const { return platform_devices_.size(); }
-
- private:
- std::vector<std::string> platform_devices_;
-};
-
class DeviceHandler {
public:
friend class DeviceHandlerTester;
@@ -119,16 +105,11 @@
void HandleDeviceEvent(const Uevent& uevent);
- void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
-
- void HandlePlatformDeviceEvent(const Uevent& uevent);
- void HandleBlockDeviceEvent(const Uevent& uevent) const;
- void HandleGenericDeviceEvent(const Uevent& uevent) const;
-
std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
void set_skip_restorecon(bool value) { skip_restorecon_ = value; }
private:
+ bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
const std::string& path, const std::vector<std::string>& links) const;
void MakeDevice(const std::string& path, int block, int major, int minor,
@@ -136,13 +117,17 @@
std::vector<std::string> GetCharacterDeviceSymlinks(const Uevent& uevent) const;
void HandleDevice(const std::string& action, const std::string& devpath, int block, int major,
int minor, const std::vector<std::string>& links) const;
+ void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
+
+ void HandleBlockDeviceEvent(const Uevent& uevent) const;
+ void HandleGenericDeviceEvent(const Uevent& uevent) const;
std::vector<Permissions> dev_permissions_;
std::vector<SysfsPermissions> sysfs_permissions_;
std::vector<Subsystem> subsystems_;
- PlatformDeviceList platform_devices_;
selabel_handle* sehandle_;
bool skip_restorecon_;
+ std::string sysfs_mount_point_;
};
// Exposed for testing
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index 41b101b..e1e4e49 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -16,33 +16,29 @@
#include "devices.h"
-#include <string>
-#include <vector>
-
#include <android-base/scopeguard.h>
+#include <android-base/test_utils.h>
#include <gtest/gtest.h>
+#include "util.h"
+
+using namespace std::string_literals;
+
class DeviceHandlerTester {
public:
- void AddPlatformDevice(const std::string& path) {
- Uevent uevent = {
- .action = "add", .subsystem = "platform", .path = path,
- };
- device_handler_.HandlePlatformDeviceEvent(uevent);
- }
-
- void RemovePlatformDevice(const std::string& path) {
- Uevent uevent = {
- .action = "remove", .subsystem = "platform", .path = path,
- };
- device_handler_.HandlePlatformDeviceEvent(uevent);
- }
-
- void TestGetSymlinks(const std::string& platform_device_name, const Uevent& uevent,
+ void TestGetSymlinks(const std::string& platform_device, const Uevent& uevent,
const std::vector<std::string> expected_links, bool block) {
- AddPlatformDevice(platform_device_name);
- auto platform_device_remover = android::base::make_scope_guard(
- [this, &platform_device_name]() { RemovePlatformDevice(platform_device_name); });
+ TemporaryDir fake_sys_root;
+ device_handler_.sysfs_mount_point_ = fake_sys_root.path;
+
+ std::string platform_device_dir = fake_sys_root.path + platform_device;
+ mkdir_recursive(platform_device_dir, 0777, nullptr);
+
+ std::string platform_bus = fake_sys_root.path + "/bus/platform"s;
+ mkdir_recursive(platform_bus, 0777, nullptr);
+ symlink(platform_bus.c_str(), (platform_device_dir + "/subsystem").c_str());
+
+ mkdir_recursive(android::base::Dirname(fake_sys_root.path + uevent.path), 0777, nullptr);
std::vector<std::string> result;
if (block) {
@@ -65,30 +61,6 @@
DeviceHandler device_handler_;
};
-TEST(device_handler, PlatformDeviceList) {
- PlatformDeviceList platform_device_list;
-
- platform_device_list.Add("/devices/platform/some_device_name");
- platform_device_list.Add("/devices/platform/some_device_name/longer");
- platform_device_list.Add("/devices/platform/other_device_name");
- EXPECT_EQ(3U, platform_device_list.size());
-
- std::string out_path;
- EXPECT_FALSE(platform_device_list.Find("/devices/platform/not_found", &out_path));
- EXPECT_EQ("", out_path);
-
- EXPECT_FALSE(platform_device_list.Find("/devices/platform/some_device_name_with_same_prefix",
- &out_path));
-
- EXPECT_TRUE(platform_device_list.Find("/devices/platform/some_device_name/longer/longer_child",
- &out_path));
- EXPECT_EQ("/devices/platform/some_device_name/longer", out_path);
-
- EXPECT_TRUE(
- platform_device_list.Find("/devices/platform/some_device_name/other_child", &out_path));
- EXPECT_EQ("/devices/platform/some_device_name", out_path);
-}
-
TEST(device_handler, get_character_device_symlinks_success) {
const char* platform_device = "/devices/platform/some_device_name";
Uevent uevent = {
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 0f2b1f3..8433056 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <unistd.h>
+#include <chrono>
#include <memory>
#include <set>
#include <string>
@@ -35,6 +36,8 @@
#include "uevent_listener.h"
#include "util.h"
+using namespace std::chrono_literals;
+
// Class Declarations
// ------------------
class FirstStageMount {
@@ -49,11 +52,11 @@
bool InitDevices();
protected:
- void InitRequiredDevices();
- void InitVerityDevice(const std::string& verity_device);
+ bool InitRequiredDevices();
+ bool InitVerityDevice(const std::string& verity_device);
bool MountPartitions();
- virtual RegenerationAction UeventCallback(const Uevent& uevent);
+ virtual ListenerAction UeventCallback(const Uevent& uevent);
// Pure virtual functions.
virtual bool GetRequiredDevices() = 0;
@@ -86,7 +89,7 @@
~FirstStageMountVBootV2() override = default;
protected:
- RegenerationAction UeventCallback(const Uevent& uevent) override;
+ ListenerAction UeventCallback(const Uevent& uevent) override;
bool GetRequiredDevices() override;
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
bool InitAvbHandle();
@@ -141,55 +144,60 @@
}
bool FirstStageMount::InitDevices() {
- if (!GetRequiredDevices()) return false;
-
- InitRequiredDevices();
-
- // InitRequiredDevices() will remove found partitions from required_devices_partition_names_.
- // So if it isn't empty here, it means some partitions are not found.
- if (!required_devices_partition_names_.empty()) {
- LOG(ERROR) << __FUNCTION__ << "(): partition(s) not found: "
- << android::base::Join(required_devices_partition_names_, ", ");
- return false;
- } else {
- return true;
- }
+ return GetRequiredDevices() && InitRequiredDevices();
}
// Creates devices with uevent->partition_name matching one in the member variable
// required_devices_partition_names_. Found partitions will then be removed from it
// for the subsequent member function to check which devices are NOT created.
-void FirstStageMount::InitRequiredDevices() {
+bool FirstStageMount::InitRequiredDevices() {
if (required_devices_partition_names_.empty()) {
- return;
+ return true;
}
if (need_dm_verity_) {
const std::string dm_path = "/devices/virtual/misc/device-mapper";
- uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path,
- [this, &dm_path](const Uevent& uevent) {
- if (uevent.path == dm_path) {
- device_handler_.HandleDeviceEvent(uevent);
- return RegenerationAction::kStop;
- }
- return RegenerationAction::kContinue;
- });
+ bool found = false;
+ auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
+ if (uevent.path == dm_path) {
+ device_handler_.HandleDeviceEvent(uevent);
+ found = true;
+ return ListenerAction::kStop;
+ }
+ return ListenerAction::kContinue;
+ };
+ uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
+ if (!found) {
+ uevent_listener_.Poll(dm_callback, 10s);
+ }
+ if (!found) {
+ LOG(ERROR) << "device-mapper device not found";
+ return false;
+ }
}
- uevent_listener_.RegenerateUevents(
- [this](const Uevent& uevent) { return UeventCallback(uevent); });
+ auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
+ uevent_listener_.RegenerateUevents(uevent_callback);
+
+ // UeventCallback() will remove found partitions from required_devices_partition_names_.
+ // So if it isn't empty here, it means some partitions are not found.
+ if (!required_devices_partition_names_.empty()) {
+ uevent_listener_.Poll(uevent_callback, 10s);
+ }
+
+ if (!required_devices_partition_names_.empty()) {
+ LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found: "
+ << android::base::Join(required_devices_partition_names_, ", ");
+ return false;
+ }
+
+ return true;
}
-RegenerationAction FirstStageMount::UeventCallback(const Uevent& uevent) {
- // We need platform devices to create symlinks.
- if (uevent.subsystem == "platform") {
- device_handler_.HandleDeviceEvent(uevent);
- return RegenerationAction::kContinue;
- }
-
+ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
// Ignores everything that is not a block device.
if (uevent.subsystem != "block") {
- return RegenerationAction::kContinue;
+ return ListenerAction::kContinue;
}
if (!uevent.partition_name.empty()) {
@@ -198,34 +206,46 @@
// suffix when A/B is used.
auto iter = required_devices_partition_names_.find(uevent.partition_name);
if (iter != required_devices_partition_names_.end()) {
- LOG(VERBOSE) << __FUNCTION__ << "(): found partition: " << *iter;
+ LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
required_devices_partition_names_.erase(iter);
device_handler_.HandleDeviceEvent(uevent);
if (required_devices_partition_names_.empty()) {
- return RegenerationAction::kStop;
+ return ListenerAction::kStop;
} else {
- return RegenerationAction::kContinue;
+ return ListenerAction::kContinue;
}
}
}
// Not found a partition or find an unneeded partition, continue to find others.
- return RegenerationAction::kContinue;
+ return ListenerAction::kContinue;
}
// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
-void FirstStageMount::InitVerityDevice(const std::string& verity_device) {
+bool FirstStageMount::InitVerityDevice(const std::string& verity_device) {
const std::string device_name(basename(verity_device.c_str()));
const std::string syspath = "/sys/block/" + device_name;
+ bool found = false;
- uevent_listener_.RegenerateUeventsForPath(
- syspath, [&device_name, &verity_device, this](const Uevent& uevent) {
- if (uevent.device_name == device_name) {
- LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
- device_handler_.HandleDeviceEvent(uevent);
- return RegenerationAction::kStop;
- }
- return RegenerationAction::kContinue;
- });
+ auto verity_callback = [&device_name, &verity_device, this, &found](const Uevent& uevent) {
+ if (uevent.device_name == device_name) {
+ LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
+ device_handler_.HandleDeviceEvent(uevent);
+ found = true;
+ return ListenerAction::kStop;
+ }
+ return ListenerAction::kContinue;
+ };
+
+ uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
+ if (!found) {
+ uevent_listener_.Poll(verity_callback, 10s);
+ }
+ if (!found) {
+ LOG(ERROR) << "dm-verity device not found";
+ return false;
+ }
+
+ return true;
}
bool FirstStageMount::MountPartitions() {
@@ -291,7 +311,7 @@
} else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
// The exact block device name (fstab_rec->blk_device) is changed to "/dev/block/dm-XX".
// Needs to create it because ueventd isn't started in init first stage.
- InitVerityDevice(fstab_rec->blk_device);
+ return InitVerityDevice(fstab_rec->blk_device);
} else {
return false;
}
@@ -351,7 +371,7 @@
return true;
}
-RegenerationAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
+ListenerAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
// Check if this uevent corresponds to one of the required partitions and store its symlinks if
// so, in order to create FsManagerAvbHandle later.
// Note that the parent callback removes partitions from the list of required partitions
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index 27c5d23..c748984 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -121,8 +121,8 @@
// make sure we don't overrun the socket's buffer.
//
-RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d,
- RegenerateCallback callback) const {
+ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d,
+ const ListenerCallback& callback) const {
int dfd = dirfd(d);
int fd = openat(dfd, "uevent", O_WRONLY);
@@ -132,7 +132,7 @@
Uevent uevent;
while (ReadUevent(&uevent)) {
- if (callback(uevent) == RegenerationAction::kStop) return RegenerationAction::kStop;
+ if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop;
}
}
@@ -147,49 +147,67 @@
if (d2 == 0) {
close(fd);
} else {
- if (RegenerateUeventsForDir(d2.get(), callback) == RegenerationAction::kStop) {
- return RegenerationAction::kStop;
+ if (RegenerateUeventsForDir(d2.get(), callback) == ListenerAction::kStop) {
+ return ListenerAction::kStop;
}
}
}
// default is always to continue looking for uevents
- return RegenerationAction::kContinue;
+ return ListenerAction::kContinue;
}
-RegenerationAction UeventListener::RegenerateUeventsForPath(const std::string& path,
- RegenerateCallback callback) const {
+ListenerAction UeventListener::RegenerateUeventsForPath(const std::string& path,
+ const ListenerCallback& callback) const {
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
- if (!d) return RegenerationAction::kContinue;
+ if (!d) return ListenerAction::kContinue;
return RegenerateUeventsForDir(d.get(), callback);
}
static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};
-void UeventListener::RegenerateUevents(RegenerateCallback callback) const {
+void UeventListener::RegenerateUevents(const ListenerCallback& callback) const {
for (const auto path : kRegenerationPaths) {
- if (RegenerateUeventsForPath(path, callback) == RegenerationAction::kStop) return;
+ if (RegenerateUeventsForPath(path, callback) == ListenerAction::kStop) return;
}
}
-void UeventListener::DoPolling(PollCallback callback) const {
+void UeventListener::Poll(const ListenerCallback& callback,
+ const std::optional<std::chrono::milliseconds> relative_timeout) const {
+ using namespace std::chrono;
+
pollfd ufd;
ufd.events = POLLIN;
ufd.fd = device_fd_;
+ auto start_time = steady_clock::now();
+
while (true) {
ufd.revents = 0;
- int nr = poll(&ufd, 1, -1);
- if (nr <= 0) {
+
+ int timeout_ms = -1;
+ if (relative_timeout) {
+ auto now = steady_clock::now();
+ auto time_elapsed = duration_cast<milliseconds>(now - start_time);
+ if (time_elapsed > *relative_timeout) return;
+
+ auto remaining_timeout = *relative_timeout - time_elapsed;
+ timeout_ms = remaining_timeout.count();
+ }
+
+ int nr = poll(&ufd, 1, timeout_ms);
+ if (nr == 0) return;
+ if (nr < 0) {
+ PLOG(ERROR) << "poll() of uevent socket failed, continuing";
continue;
}
if (ufd.revents & POLLIN) {
- // We're non-blocking, so if we receive a poll event keep processing until there
+ // We're non-blocking, so if we receive a poll event keep processing until
// we have exhausted all uevent messages.
Uevent uevent;
while (ReadUevent(&uevent)) {
- callback(uevent);
+ if (callback(uevent) == ListenerAction::kStop) return;
}
}
}
diff --git a/init/uevent_listener.h b/init/uevent_listener.h
index ba31aaa..0dae102 100644
--- a/init/uevent_listener.h
+++ b/init/uevent_listener.h
@@ -19,7 +19,9 @@
#include <dirent.h>
+#include <chrono>
#include <functional>
+#include <optional>
#include <android-base/unique_fd.h>
@@ -27,26 +29,26 @@
#define UEVENT_MSG_LEN 2048
-enum class RegenerationAction {
+enum class ListenerAction {
kStop = 0, // Stop regenerating uevents as we've handled the one(s) we're interested in.
kContinue, // Continue regenerating uevents as we haven't seen the one(s) we're interested in.
};
-using RegenerateCallback = std::function<RegenerationAction(const Uevent&)>;
-using PollCallback = std::function<void(const Uevent&)>;
+using ListenerCallback = std::function<ListenerAction(const Uevent&)>;
class UeventListener {
public:
UeventListener();
- void RegenerateUevents(RegenerateCallback callback) const;
- RegenerationAction RegenerateUeventsForPath(const std::string& path,
- RegenerateCallback callback) const;
- void DoPolling(PollCallback callback) const;
+ void RegenerateUevents(const ListenerCallback& callback) const;
+ ListenerAction RegenerateUeventsForPath(const std::string& path,
+ const ListenerCallback& callback) const;
+ void Poll(const ListenerCallback& callback,
+ const std::optional<std::chrono::milliseconds> relative_timeout = {}) const;
private:
bool ReadUevent(Uevent* uevent) const;
- RegenerationAction RegenerateUeventsForDir(DIR* d, RegenerateCallback callback) const;
+ ListenerAction RegenerateUeventsForDir(DIR* d, const ListenerCallback& callback) const;
android::base::unique_fd device_fd_;
};
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index d121647..4982b77 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -128,15 +128,7 @@
void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) {
for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) {
auto& uevent = uevent_queue_[i];
- if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
- device_handler_.FixupSysPermissions(uevent.path, uevent.subsystem);
- }
-
- if (uevent.subsystem == "block") {
- device_handler_.HandleBlockDeviceEvent(uevent);
- } else {
- device_handler_.HandleGenericDeviceEvent(uevent);
- }
+ device_handler_.HandleDeviceEvent(uevent);
}
_exit(EXIT_SUCCESS);
}
@@ -145,16 +137,8 @@
uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
HandleFirmwareEvent(uevent);
- // This is the one mutable part of DeviceHandler, in which platform devices are
- // added to a vector for later reference. Since there is no communication after
- // fork()'ing subprocess handlers, all platform devices must be in the vector before
- // we fork, and therefore they must be handled in this loop.
- if (uevent.subsystem == "platform") {
- device_handler_.HandlePlatformDeviceEvent(uevent);
- }
-
uevent_queue_.emplace_back(std::move(uevent));
- return RegenerationAction::kContinue;
+ return ListenerAction::kContinue;
});
}
@@ -282,9 +266,10 @@
cold_boot.Run();
}
- uevent_listener.DoPolling([&device_handler](const Uevent& uevent) {
+ uevent_listener.Poll([&device_handler](const Uevent& uevent) {
HandleFirmwareEvent(uevent);
device_handler.HandleDeviceEvent(uevent);
+ return ListenerAction::kContinue;
});
return 0;
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
index 0792307..5a897a4 100644
--- a/libappfuse/FuseBridgeLoop.cc
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -173,13 +173,20 @@
}
FuseBridgeState ReadFromDevice(FuseBridgeLoopCallback* callback) {
+ // To observe APCT failures.
+ base::ScopedLogSeverity log_severity(base::VERBOSE);
+
LOG(VERBOSE) << "ReadFromDevice";
if (!buffer_.request.Read(device_fd_)) {
return FuseBridgeState::kClosing;
}
const uint32_t opcode = buffer_.request.header.opcode;
- LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
+ const uint64_t unique = buffer_.request.header.unique;
+ LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode << " unique=" << unique;
+ if (unique == 0) {
+ return FuseBridgeState::kWaitToReadEither;
+ }
switch (opcode) {
case FUSE_FORGET:
// Do not reply to FUSE_FORGET.
diff --git a/libappfuse/tests/FuseBridgeLoopTest.cc b/libappfuse/tests/FuseBridgeLoopTest.cc
index 51d6051..0a28451 100644
--- a/libappfuse/tests/FuseBridgeLoopTest.cc
+++ b/libappfuse/tests/FuseBridgeLoopTest.cc
@@ -67,6 +67,7 @@
memset(&request_, 0, sizeof(FuseRequest));
request_.header.opcode = opcode;
request_.header.len = sizeof(fuse_in_header);
+ request_.header.unique = 1;
ASSERT_TRUE(request_.Write(dev_sockets_[0]));
memset(&response_, 0, sizeof(FuseResponse));
diff --git a/libcutils/include/cutils/sched_policy.h b/libcutils/include/cutils/sched_policy.h
index 9683f91..4c1113b 100644
--- a/libcutils/include/cutils/sched_policy.h
+++ b/libcutils/include/cutils/sched_policy.h
@@ -34,7 +34,7 @@
* Check if Linux kernel enables SCHEDTUNE feature (only available in Android
* common kernel or Linaro LSK, not in mainline Linux as of v4.9)
*
- * Return value: 1 if Linux kernel CONFIG_SCHEDTUNE=y; 0 otherwise.
+ * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise.
*/
extern bool schedboost_enabled();
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index 3472a67..285eaff 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -137,7 +137,7 @@
/*
Similar to CONFIG_CPUSETS above, but with a different configuration
- CONFIG_SCHEDTUNE that's in Android common Linux kernel and Linaro
+ CONFIG_CGROUP_SCHEDTUNE that's in Android common Linux kernel and Linaro
Stable Kernel (LSK), but not in mainline Linux as of v4.9.
With runtime check using the following function, build time
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 4269eaa..cdac76b 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -23,7 +23,6 @@
cc_library_shared {
name: "libmemunreachable",
- vendor_available: true,
defaults: ["libmemunreachable_defaults"],
srcs: [
"Allocator.cpp",
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index b369c43..b869918 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -71,15 +71,17 @@
map_info->flags |= PROT_EXEC;
}
- map_info->name = &line[name_pos];
- size_t length = map_info->name.length() - 1;
- if (map_info->name[length] == '\n') {
- map_info->name.erase(length);
- }
- // Mark a device map in /dev/and not in /dev/ashmem/ specially.
- if (!map_info->name.empty() && map_info->name.substr(0, 5) == "/dev/" &&
- map_info->name.substr(5, 7) != "ashmem/") {
- map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
+ if (line[name_pos] != '\0') {
+ map_info->name = &line[name_pos];
+ size_t length = map_info->name.length() - 1;
+ if (map_info->name[length] == '\n') {
+ map_info->name.erase(length);
+ }
+
+ // Mark a device map in /dev/and not in /dev/ashmem/ specially.
+ if (map_info->name.substr(0, 5) == "/dev/" && map_info->name.substr(5, 7) != "ashmem/") {
+ map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
+ }
}
return true;
diff --git a/libunwindstack/tests/MapInfoTest.cpp b/libunwindstack/tests/MapInfoTest.cpp
index c846ad7..6e47dc0 100644
--- a/libunwindstack/tests/MapInfoTest.cpp
+++ b/libunwindstack/tests/MapInfoTest.cpp
@@ -75,7 +75,7 @@
// Make sure this test is valid.
info.end = 0x101;
memory.reset(info.CreateMemory(getpid()));
- ASSERT_FALSE(info.CreateMemory(getpid()) == nullptr);
+ ASSERT_TRUE(memory.get() != nullptr);
}
// Verify that if the offset is non-zero but there is no elf at the offset,
@@ -212,8 +212,8 @@
MapInfo info{.start = start, .end = start + 1024, .offset = 0, .name = ""};
// The map contains garbage, but this should still produce an elf object.
- Elf* elf = info.GetElf(getpid(), false);
- ASSERT_TRUE(elf != nullptr);
+ std::unique_ptr<Elf> elf(info.GetElf(getpid(), false));
+ ASSERT_TRUE(elf.get() != nullptr);
ASSERT_FALSE(elf->valid());
ASSERT_EQ(0, munmap(map, 1024));
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
index ee5ba01..469afcc 100644
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ b/libunwindstack/tests/MemoryRangeTest.cpp
@@ -26,21 +26,13 @@
#include "MemoryFake.h"
-class MemoryRangeTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_ = new MemoryFake;
- }
-
- MemoryFake* memory_;
-};
-
-TEST_F(MemoryRangeTest, read) {
+TEST(MemoryRangeTest, read) {
std::vector<uint8_t> src(1024);
memset(src.data(), 0x4c, 1024);
- memory_->SetMemory(9001, src);
+ MemoryFake* memory = new MemoryFake;
+ memory->SetMemory(9001, src);
- MemoryRange range(memory_, 9001, 9001 + src.size());
+ MemoryRange range(memory, 9001, 9001 + src.size());
std::vector<uint8_t> dst(1024);
ASSERT_TRUE(range.Read(0, dst.data(), src.size()));
@@ -49,12 +41,13 @@
}
}
-TEST_F(MemoryRangeTest, read_near_limit) {
+TEST(MemoryRangeTest, read_near_limit) {
std::vector<uint8_t> src(4096);
memset(src.data(), 0x4c, 4096);
- memory_->SetMemory(1000, src);
+ MemoryFake* memory = new MemoryFake;
+ memory->SetMemory(1000, src);
- MemoryRange range(memory_, 1000, 2024);
+ MemoryRange range(memory, 1000, 2024);
std::vector<uint8_t> dst(1024);
ASSERT_TRUE(range.Read(1020, dst.data(), 4));
@@ -71,7 +64,7 @@
ASSERT_TRUE(range.Read(1020, dst.data(), 4));
}
-TEST_F(MemoryRangeTest, read_overflow) {
+TEST(MemoryRangeTest, read_overflow) {
std::vector<uint8_t> buffer(100);
std::unique_ptr<MemoryRange> overflow(new MemoryRange(new MemoryFakeAlwaysReadZero, 100, 200));
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index c82eaca..a310a07 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -62,68 +62,6 @@
// The maximum number of bytes to scan backwards for the EOCD start.
static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
-static const char* kErrorMessages[] = {
- "Unknown return code.",
- "Iteration ended",
- "Zlib error",
- "Invalid file",
- "Invalid handle",
- "Duplicate entries in archive",
- "Empty archive",
- "Entry not found",
- "Invalid offset",
- "Inconsistent information",
- "Invalid entry name",
- "I/O Error",
- "File mapping failed"
-};
-
-static const int32_t kErrorMessageUpperBound = 0;
-
-static const int32_t kIterationEnd = -1;
-
-// We encountered a Zlib error when inflating a stream from this file.
-// Usually indicates file corruption.
-static const int32_t kZlibError = -2;
-
-// The input file cannot be processed as a zip archive. Usually because
-// it's too small, too large or does not have a valid signature.
-static const int32_t kInvalidFile = -3;
-
-// An invalid iteration / ziparchive handle was passed in as an input
-// argument.
-static const int32_t kInvalidHandle = -4;
-
-// The zip archive contained two (or possibly more) entries with the same
-// name.
-static const int32_t kDuplicateEntry = -5;
-
-// The zip archive contains no entries.
-static const int32_t kEmptyArchive = -6;
-
-// The specified entry was not found in the archive.
-static const int32_t kEntryNotFound = -7;
-
-// The zip archive contained an invalid local file header pointer.
-static const int32_t kInvalidOffset = -8;
-
-// The zip archive contained inconsistent entry information. This could
-// be because the central directory & local file header did not agree, or
-// if the actual uncompressed length or crc32 do not match their declared
-// values.
-static const int32_t kInconsistentInformation = -9;
-
-// An invalid entry name was encountered.
-static const int32_t kInvalidEntryName = -10;
-
-// An I/O related system call (read, lseek, ftruncate, map) failed.
-static const int32_t kIoError = -11;
-
-// We were not able to mmap the central directory or entry contents.
-static const int32_t kMmapFailed = -12;
-
-static const int32_t kErrorMessageLowerBound = -13;
-
/*
* A Read-only Zip archive.
*
@@ -1119,11 +1057,17 @@
}
const char* ErrorCodeString(int32_t error_code) {
- if (error_code > kErrorMessageLowerBound && error_code < kErrorMessageUpperBound) {
- return kErrorMessages[error_code * -1];
+ // Make sure that the number of entries in kErrorMessages and ErrorCodes
+ // match.
+ static_assert((-kLastErrorCode + 1) == arraysize(kErrorMessages),
+ "(-kLastErrorCode + 1) != arraysize(kErrorMessages)");
+
+ const uint32_t idx = -error_code;
+ if (idx < arraysize(kErrorMessages)) {
+ return kErrorMessages[idx];
}
- return kErrorMessages[0];
+ return "Unknown return code";
}
int GetFileDescriptor(const ZipArchiveHandle handle) {
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 971db4f..de93ecd 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -26,6 +26,69 @@
#include <utils/FileMap.h>
#include <ziparchive/zip_archive.h>
+#include "android-base/macros.h"
+
+static const char* kErrorMessages[] = {
+ "Success",
+ "Iteration ended",
+ "Zlib error",
+ "Invalid file",
+ "Invalid handle",
+ "Duplicate entries in archive",
+ "Empty archive",
+ "Entry not found",
+ "Invalid offset",
+ "Inconsistent information",
+ "Invalid entry name",
+ "I/O error",
+ "File mapping failed",
+};
+
+enum ErrorCodes : int32_t {
+ kIterationEnd = -1,
+
+ // We encountered a Zlib error when inflating a stream from this file.
+ // Usually indicates file corruption.
+ kZlibError = -2,
+
+ // The input file cannot be processed as a zip archive. Usually because
+ // it's too small, too large or does not have a valid signature.
+ kInvalidFile = -3,
+
+ // An invalid iteration / ziparchive handle was passed in as an input
+ // argument.
+ kInvalidHandle = -4,
+
+ // The zip archive contained two (or possibly more) entries with the same
+ // name.
+ kDuplicateEntry = -5,
+
+ // The zip archive contains no entries.
+ kEmptyArchive = -6,
+
+ // The specified entry was not found in the archive.
+ kEntryNotFound = -7,
+
+ // The zip archive contained an invalid local file header pointer.
+ kInvalidOffset = -8,
+
+ // The zip archive contained inconsistent entry information. This could
+ // be because the central directory & local file header did not agree, or
+ // if the actual uncompressed length or crc32 do not match their declared
+ // values.
+ kInconsistentInformation = -9,
+
+ // An invalid entry name was encountered.
+ kInvalidEntryName = -10,
+
+ // An I/O related system call (read, lseek, ftruncate, map) failed.
+ kIoError = -11,
+
+ // We were not able to mmap the central directory or entry contents.
+ kMmapFailed = -12,
+
+ kLastErrorCode = kMmapFailed,
+};
class MappedZipFile {
public:
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 7376725..47f4bbd 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "zip_archive_private.h"
+
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@@ -718,8 +720,7 @@
int32_t error_code = 0;
ExtractEntryToMemory(invalid_csize, &entry, &error_code);
- ASSERT_GT(0, error_code);
- ASSERT_STREQ("Inconsistent information", ErrorCodeString(error_code));
+ ASSERT_EQ(kInconsistentInformation, error_code);
std::vector<uint8_t> invalid_size = kDataDescriptorZipFile;
invalid_csize[kSizeOffset] = 0xfe;
@@ -728,8 +729,17 @@
entry.clear();
ExtractEntryToMemory(invalid_csize, &entry, &error_code);
- ASSERT_GT(0, error_code);
- ASSERT_STREQ("Inconsistent information", ErrorCodeString(error_code));
+ ASSERT_EQ(kInconsistentInformation, error_code);
+}
+
+TEST(ziparchive, ErrorCodeString) {
+ ASSERT_STREQ("Success", ErrorCodeString(0));
+
+ // Out of bounds.
+ ASSERT_STREQ("Unknown return code", ErrorCodeString(1));
+ ASSERT_STREQ("Unknown return code", ErrorCodeString(-13));
+
+ ASSERT_STREQ("I/O error", ErrorCodeString(kIoError));
}
int main(int argc, char** argv) {
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 8a6168c..c095315 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -40,7 +40,8 @@
#endif
#define MEMCG_SYSFS_PATH "/dev/memcg/"
-#define MEMPRESSURE_WATCH_LEVEL "low"
+#define MEMPRESSURE_WATCH_MEDIUM_LEVEL "medium"
+#define MEMPRESSURE_WATCH_CRITICAL_LEVEL "critical"
#define ZONEINFO_PATH "/proc/zoneinfo"
#define LINE_MAX 128
@@ -48,6 +49,7 @@
#define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+#define EIGHT_MEGA (1 << 23)
enum lmk_cmd {
LMK_TARGET,
@@ -66,15 +68,17 @@
static int use_inkernel_interface = 1;
/* memory pressure level medium event */
-static int mpevfd;
+static int mpevfd[2];
+#define CRITICAL_INDEX 1
+#define MEDIUM_INDEX 0
/* control socket listen and data */
static int ctrl_lfd;
static int ctrl_dfd = -1;
static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */
-/* 1 memory pressure level, 1 ctrl listen socket, 1 ctrl data socket */
-#define MAX_EPOLL_EVENTS 3
+/* 2 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */
+#define MAX_EPOLL_EVENTS 4
static int epollfd;
static int maxevents;
@@ -113,14 +117,6 @@
#define ADJTOSLOT(adj) ((adj) + -OOM_SCORE_ADJ_MIN)
static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1];
-/*
- * Wait 1-2 seconds for the death report of a killed process prior to
- * considering killing more processes.
- */
-#define KILL_TIMEOUT 2
-/* Time of last process kill we initiated, stop me before I kill again */
-static time_t kill_lasttime;
-
/* PAGE_SIZE / 1024 */
static long page_k;
@@ -241,6 +237,7 @@
struct proc *procp;
char path[80];
char val[20];
+ int soft_limit_mult;
if (oomadj < OOM_SCORE_ADJ_MIN || oomadj > OOM_SCORE_ADJ_MAX) {
ALOGE("Invalid PROCPRIO oomadj argument %d", oomadj);
@@ -254,6 +251,36 @@
if (use_inkernel_interface)
return;
+ if (oomadj >= 900) {
+ soft_limit_mult = 0;
+ } else if (oomadj >= 800) {
+ soft_limit_mult = 0;
+ } else if (oomadj >= 700) {
+ soft_limit_mult = 0;
+ } else if (oomadj >= 600) {
+ soft_limit_mult = 0;
+ } else if (oomadj >= 500) {
+ soft_limit_mult = 0;
+ } else if (oomadj >= 400) {
+ soft_limit_mult = 0;
+ } else if (oomadj >= 300) {
+ soft_limit_mult = 1;
+ } else if (oomadj >= 200) {
+ soft_limit_mult = 2;
+ } else if (oomadj >= 100) {
+ soft_limit_mult = 10;
+ } else if (oomadj >= 0) {
+ soft_limit_mult = 20;
+ } else {
+ // Persistent processes will have a large
+ // soft limit 512MB.
+ soft_limit_mult = 64;
+ }
+
+ snprintf(path, sizeof(path), "/dev/memcg/apps/uid_%d/pid_%d/memory.soft_limit_in_bytes", uid, pid);
+ snprintf(val, sizeof(val), "%d", soft_limit_mult * EIGHT_MEGA);
+ writefilestring(path, val);
+
procp = pid_lookup(pid);
if (!procp) {
procp = malloc(sizeof(struct proc));
@@ -278,7 +305,6 @@
return;
pid_remove(pid);
- kill_lasttime = 0;
}
static void cmd_target(int ntargets, int *params) {
@@ -574,7 +600,6 @@
first ? "" : "~", other_file * page_k, minfree * page_k, min_score_adj,
first ? "" : "~", other_free * page_k, other_free >= 0 ? "above" : "below");
r = kill(pid, SIGKILL);
- killProcessGroup(uid, pid, SIGKILL);
pid_remove(pid);
if (r) {
@@ -589,24 +614,12 @@
* Find a process to kill based on the current (possibly estimated) free memory
* and cached memory sizes. Returns the size of the killed processes.
*/
-static int find_and_kill_process(int other_free, int other_file, bool first)
+static int find_and_kill_process(int other_free, int other_file, bool first, int min_score_adj)
{
int i;
- int min_score_adj = OOM_SCORE_ADJ_MAX + 1;
int minfree = 0;
int killed_size = 0;
- for (i = 0; i < lowmem_targets_size; i++) {
- minfree = lowmem_minfree[i];
- if (other_free < minfree && other_file < minfree) {
- min_score_adj = lowmem_adj[i];
- break;
- }
- }
-
- if (min_score_adj == OOM_SCORE_ADJ_MAX + 1)
- return 0;
-
for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
struct proc *procp;
@@ -626,42 +639,33 @@
return 0;
}
-static void mp_event(uint32_t events __unused) {
+static void mp_event_common(bool is_critical) {
int ret;
unsigned long long evcount;
- struct sysmeminfo mi;
- int other_free;
- int other_file;
- int killed_size;
bool first = true;
+ int min_adj_score = is_critical ? 0 : 800;
+ int index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX;
- ret = read(mpevfd, &evcount, sizeof(evcount));
+ ret = read(mpevfd[index], &evcount, sizeof(evcount));
if (ret < 0)
ALOGE("Error reading memory pressure event fd; errno=%d",
errno);
- if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
- return;
-
- while (zoneinfo_parse(&mi) < 0) {
- // Failed to read /proc/zoneinfo, assume ENOMEM and kill something
- find_and_kill_process(0, 0, true);
+ if (find_and_kill_process(0, 0, first, min_adj_score) == 0) {
+ ALOGI("Nothing to kill");
}
-
- other_free = mi.nr_free_pages - mi.totalreserve_pages;
- other_file = mi.nr_file_pages - mi.nr_shmem;
-
- do {
- killed_size = find_and_kill_process(other_free, other_file, first);
- if (killed_size > 0) {
- first = false;
- other_free += killed_size;
- other_file += killed_size;
- }
- } while (killed_size > 0);
}
-static int init_mp(char *levelstr, void *event_handler)
+static void mp_event(uint32_t events __unused) {
+ mp_event_common(false);
+}
+
+static void mp_event_critical(uint32_t events __unused) {
+ ALOGI("Memory pressure critical");
+ mp_event_common(true);
+}
+
+static int init_mp_common(char *levelstr, void *event_handler, bool is_critical)
{
int mpfd;
int evfd;
@@ -669,6 +673,7 @@
char buf[256];
struct epoll_event epev;
int ret;
+ int mpevfd_index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX;
mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
if (mpfd < 0) {
@@ -709,7 +714,7 @@
goto err;
}
maxevents++;
- mpevfd = evfd;
+ mpevfd[mpevfd_index] = evfd;
return 0;
err:
@@ -722,6 +727,16 @@
return -1;
}
+static int init_mp_medium()
+{
+ return init_mp_common(MEMPRESSURE_WATCH_MEDIUM_LEVEL, (void *)&mp_event, false);
+}
+
+static int init_mp_critical()
+{
+ return init_mp_common(MEMPRESSURE_WATCH_CRITICAL_LEVEL, (void *)&mp_event_critical, true);
+}
+
static int init(void) {
struct epoll_event epev;
int i;
@@ -763,7 +778,8 @@
if (use_inkernel_interface) {
ALOGI("Using in-kernel low memory killer interface");
} else {
- ret = init_mp(MEMPRESSURE_WATCH_LEVEL, (void *)&mp_event);
+ ret = init_mp_medium();
+ ret |= init_mp_critical();
if (ret)
ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
}