Merge "adb-remount-test: Refactor raw remount & remount from scratch test"
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index c15146b..1c89472 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -14,9 +14,15 @@
"-Wno-nullability-completeness",
"-Os",
"-fno-finite-loops",
+ "-DANDROID_DEBUGGABLE=0",
],
local_include_dirs: ["include"],
+ product_variables: {
+ debuggable: {
+ cflags: ["-UANDROID_DEBUGGABLE", "-DANDROID_DEBUGGABLE=1"],
+ }
+ },
}
cc_library_headers {
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index bc08327..68b2e67 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -62,10 +62,11 @@
#define DEBUGGER_SIGNAL BIONIC_SIGNAL_DEBUGGER
static void __attribute__((__unused__)) debuggerd_register_handlers(struct sigaction* action) {
+ bool enabled = true;
+#if ANDROID_DEBUGGABLE
char value[PROP_VALUE_MAX] = "";
- bool enabled =
- !(__system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1") &&
- __system_property_get("debug.debuggerd.disable", value) > 0 && !strcmp(value, "1"));
+ enabled = !(__system_property_get("debug.debuggerd.disable", value) > 0 && !strcmp(value, "1"));
+#endif
if (enabled) {
sigaction(SIGABRT, action, nullptr);
sigaction(SIGBUS, action, nullptr);
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 354d02a..57762e6 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -100,13 +100,12 @@
return false;
}
-bool fs_mgr_overlayfs_setup(const char*, bool* change, bool) {
- if (change) *change = false;
+bool fs_mgr_overlayfs_setup(const char*, bool*, bool) {
+ LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds";
return false;
}
-bool fs_mgr_overlayfs_teardown(const char*, bool* change) {
- if (change) *change = false;
+bool fs_mgr_overlayfs_teardown(const char*, bool*) {
return false;
}
@@ -372,77 +371,97 @@
constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";
-bool fs_mgr_overlayfs_setup_dir(const std::string& dir, std::string* overlay, bool* change) {
- auto ret = true;
- auto top = dir + kOverlayTopDir;
- if (setfscreatecon(kOverlayfsFileContext)) {
- ret = false;
- PERROR << "setfscreatecon " << kOverlayfsFileContext;
- }
- auto save_errno = errno;
- if (!mkdir(top.c_str(), 0755)) {
- if (change) *change = true;
- } else if (errno != EEXIST) {
- ret = false;
- PERROR << "mkdir " << top;
- } else {
- errno = save_errno;
- }
- setfscreatecon(nullptr);
+class AutoSetFsCreateCon final {
+ public:
+ AutoSetFsCreateCon() {}
+ AutoSetFsCreateCon(const std::string& context) { Set(context); }
+ ~AutoSetFsCreateCon() { Restore(); }
- if (overlay) *overlay = std::move(top);
- return ret;
+ bool Ok() const { return ok_; }
+ bool Set(const std::string& context) {
+ if (setfscreatecon(context.c_str())) {
+ PLOG(ERROR) << "setfscreatecon " << context;
+ return false;
+ }
+ ok_ = true;
+ return true;
+ }
+ bool Restore() {
+ if (restored_ || !ok_) {
+ return true;
+ }
+ if (setfscreatecon(nullptr)) {
+ PLOG(ERROR) << "setfscreatecon null";
+ return false;
+ }
+ restored_ = true;
+ return true;
+ }
+
+ private:
+ bool ok_ = false;
+ bool restored_ = false;
+};
+
+std::string fs_mgr_overlayfs_setup_dir(const std::string& dir) {
+ auto top = dir + kOverlayTopDir;
+
+ AutoSetFsCreateCon createcon(kOverlayfsFileContext);
+ if (!createcon.Ok()) {
+ return {};
+ }
+ if (mkdir(top.c_str(), 0755) != 0 && errno != EEXIST) {
+ PERROR << "mkdir " << top;
+ return {};
+ }
+ if (!createcon.Restore()) {
+ return {};
+ }
+ return top;
}
bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& mount_point,
- bool* change) {
- auto ret = true;
- if (fs_mgr_overlayfs_already_mounted(mount_point)) return ret;
+ bool* want_reboot) {
+ if (fs_mgr_overlayfs_already_mounted(mount_point)) {
+ return true;
+ }
auto fsrec_mount_point = overlay + "/" + android::base::Basename(mount_point) + "/";
- if (setfscreatecon(kOverlayfsFileContext)) {
- ret = false;
- PERROR << "setfscreatecon " << kOverlayfsFileContext;
+ AutoSetFsCreateCon createcon(kOverlayfsFileContext);
+ if (!createcon.Ok()) {
+ return false;
}
- auto save_errno = errno;
- if (!mkdir(fsrec_mount_point.c_str(), 0755)) {
- if (change) *change = true;
- } else if (errno != EEXIST) {
- ret = false;
+ if (mkdir(fsrec_mount_point.c_str(), 0755) != 0 && errno != EEXIST) {
PERROR << "mkdir " << fsrec_mount_point;
- } else {
- errno = save_errno;
+ return false;
+ }
+ if (mkdir((fsrec_mount_point + kWorkName).c_str(), 0755) != 0 && errno != EEXIST) {
+ PERROR << "mkdir " << fsrec_mount_point << kWorkName;
+ return false;
+ }
+ if (!createcon.Restore()) {
+ return false;
}
- save_errno = errno;
- if (!mkdir((fsrec_mount_point + kWorkName).c_str(), 0755)) {
- if (change) *change = true;
- } else if (errno != EEXIST) {
- ret = false;
- PERROR << "mkdir " << fsrec_mount_point << kWorkName;
- } else {
- errno = save_errno;
- }
- setfscreatecon(nullptr);
+ createcon = {};
auto new_context = fs_mgr_get_context(mount_point);
- if (!new_context.empty() && setfscreatecon(new_context.c_str())) {
- ret = false;
- PERROR << "setfscreatecon " << new_context;
+ if (new_context.empty() || !createcon.Set(new_context)) {
+ return false;
}
- auto upper = fsrec_mount_point + kUpperName;
- save_errno = errno;
- if (!mkdir(upper.c_str(), 0755)) {
- if (change) *change = true;
- } else if (errno != EEXIST) {
- ret = false;
- PERROR << "mkdir " << upper;
- } else {
- errno = save_errno;
- }
- if (!new_context.empty()) setfscreatecon(nullptr);
- return ret;
+ auto upper = fsrec_mount_point + kUpperName;
+ if (mkdir(upper.c_str(), 0755) != 0 && errno != EEXIST) {
+ PERROR << "mkdir " << upper;
+ return false;
+ }
+ if (!createcon.Restore()) {
+ return false;
+ }
+
+ if (want_reboot) *want_reboot = true;
+
+ return true;
}
uint32_t fs_mgr_overlayfs_slot_number() {
@@ -729,21 +748,23 @@
}
// use as the bound directory in /dev.
+ AutoSetFsCreateCon createcon;
auto new_context = fs_mgr_get_context(entry.mount_point);
- if (!new_context.empty() && setfscreatecon(new_context.c_str())) {
- PERROR << "setfscreatecon " << new_context;
+ if (new_context.empty() || !createcon.Set(new_context)) {
+ continue;
}
move_entry new_entry = {std::move(entry.mount_point), "/dev/TemporaryDir-XXXXXX",
entry.shared_flag};
const auto target = mkdtemp(new_entry.dir.data());
+ if (!createcon.Restore()) {
+ return false;
+ }
if (!target) {
retval = false;
save_errno = errno;
PERROR << "temporary directory for MS_BIND";
- setfscreatecon(nullptr);
continue;
}
- setfscreatecon(nullptr);
if (!parent_private && !parent_made_private) {
parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false);
@@ -814,20 +835,29 @@
bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type,
bool readonly = false) {
if (readonly) {
- if (!fs_mgr_access(device_path)) return false;
- } else {
- if (!fs_mgr_rw_access(device_path)) return false;
+ if (!fs_mgr_access(device_path)) {
+ LOG(ERROR) << "Path does not exist: " << device_path;
+ return false;
+ }
+ } else if (!fs_mgr_rw_access(device_path)) {
+ LOG(ERROR) << "Path does not exist or is not readwrite: " << device_path;
+ return false;
}
auto f2fs = fs_mgr_is_f2fs(device_path);
auto ext4 = fs_mgr_is_ext4(device_path);
- if (!f2fs && !ext4) return false;
+ if (!f2fs && !ext4) {
+ LOG(ERROR) << "Scratch partition is not f2fs or ext4";
+ return false;
+ }
- if (setfscreatecon(kOverlayfsFileContext)) {
- PERROR << "setfscreatecon " << kOverlayfsFileContext;
+ AutoSetFsCreateCon createcon(kOverlayfsFileContext);
+ if (!createcon.Ok()) {
+ return false;
}
if (mkdir(kScratchMountPoint.c_str(), 0755) && (errno != EEXIST)) {
PERROR << "create " << kScratchMountPoint;
+ return false;
}
FstabEntry entry;
@@ -859,7 +889,6 @@
if (fs_mgr_overlayfs_already_mounted("/data", false)) {
entry.fs_mgr_flags.check = true;
}
- auto save_errno = errno;
if (mounted) mounted = fs_mgr_do_mount_one(entry) == 0;
if (!mounted) {
if ((entry.fs_type == "f2fs") && ext4) {
@@ -869,12 +898,15 @@
entry.fs_type = "f2fs";
mounted = fs_mgr_do_mount_one(entry) == 0;
}
- if (!mounted) save_errno = errno;
}
- setfscreatecon(nullptr);
- if (!mounted) rmdir(kScratchMountPoint.c_str());
- errno = save_errno;
- return mounted;
+ if (!createcon.Restore()) {
+ return false;
+ }
+ if (!mounted) {
+ rmdir(kScratchMountPoint.c_str());
+ return false;
+ }
+ return true;
}
const std::string kMkF2fs("/system/bin/make_f2fs");
@@ -962,7 +994,6 @@
} else if (mnt_type == "ext4") {
command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
} else {
- errno = ESRCH;
LERROR << mnt_type << " has no mkfs cookbook";
return false;
}
@@ -995,8 +1026,7 @@
}
// Create or update a scratch partition within super.
-static bool CreateDynamicScratch(std::string* scratch_device, bool* partition_exists,
- bool* change) {
+static bool CreateDynamicScratch(std::string* scratch_device, bool* partition_exists) {
const auto partition_name = android::base::Basename(kScratchMountPoint);
auto& dm = DeviceMapper::Instance();
@@ -1069,8 +1099,6 @@
LERROR << "add partition " << partition_name;
return false;
}
-
- if (change) *change = true;
}
if (changed || partition_create) {
@@ -1084,8 +1112,6 @@
if (!CreateLogicalPartition(params, scratch_device)) {
return false;
}
-
- if (change) *change = true;
} else if (scratch_device->empty()) {
*scratch_device = GetBootScratchDevice();
}
@@ -1115,9 +1141,8 @@
return ideal_size;
}
-static bool CreateScratchOnData(std::string* scratch_device, bool* partition_exists, bool* change) {
+static bool CreateScratchOnData(std::string* scratch_device, bool* partition_exists) {
*partition_exists = false;
- if (change) *change = false;
auto images = IImageManager::Open("remount", 10s);
if (!images) {
@@ -1130,8 +1155,6 @@
return true;
}
- if (change) *change = true;
-
// Note: calling RemoveDisabledImages here ensures that we do not race with
// clean_scratch_files and accidentally try to map an image that will be
// deleted.
@@ -1173,12 +1196,11 @@
}
bool fs_mgr_overlayfs_create_scratch(const Fstab& fstab, std::string* scratch_device,
- bool* partition_exists, bool* change) {
+ bool* partition_exists) {
// Use the DSU scratch device managed by gsid if within a DSU system.
if (fs_mgr_is_dsu_running()) {
*scratch_device = GetDsuScratchDevice();
*partition_exists = !scratch_device->empty();
- *change = false;
return *partition_exists;
}
@@ -1194,22 +1216,24 @@
if (CanUseSuperPartition(fstab, &is_virtual_ab)) {
bool can_use_data = false;
if (is_virtual_ab && FilesystemHasReliablePinning("/data", &can_use_data) && can_use_data) {
- return CreateScratchOnData(scratch_device, partition_exists, change);
+ return CreateScratchOnData(scratch_device, partition_exists);
}
- return CreateDynamicScratch(scratch_device, partition_exists, change);
+ return CreateDynamicScratch(scratch_device, partition_exists);
}
- errno = ENXIO;
return false;
}
// Create and mount kScratchMountPoint storage if we have logical partitions
-bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab, bool* change) {
- if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
+bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab) {
+ if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
+ return true;
+ }
std::string scratch_device;
bool partition_exists;
- if (!fs_mgr_overlayfs_create_scratch(fstab, &scratch_device, &partition_exists, change)) {
+ if (!fs_mgr_overlayfs_create_scratch(fstab, &scratch_device, &partition_exists)) {
+ LOG(ERROR) << "Failed to create scratch partition";
return false;
}
@@ -1217,22 +1241,19 @@
auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
if (partition_exists) {
if (fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type)) {
- if (!fs_mgr_access(kScratchMountPoint + kOverlayTopDir) &&
- !fs_mgr_filesystem_has_space(kScratchMountPoint)) {
- // declare it useless, no overrides and no free space
- fs_mgr_overlayfs_umount_scratch();
- } else {
- if (change) *change = true;
+ if (fs_mgr_access(kScratchMountPoint + kOverlayTopDir) ||
+ fs_mgr_filesystem_has_space(kScratchMountPoint)) {
return true;
}
+ // declare it useless, no overrides and no free space
+ fs_mgr_overlayfs_umount_scratch();
}
- // partition existed, but was not initialized; fall through to make it.
- errno = 0;
}
- if (!fs_mgr_overlayfs_make_scratch(scratch_device, mnt_type)) return false;
-
- if (change) *change = true;
+ if (!fs_mgr_overlayfs_make_scratch(scratch_device, mnt_type)) {
+ LOG(ERROR) << "Failed to format scratch partition";
+ return false;
+ }
return fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type);
}
@@ -1355,24 +1376,23 @@
return ret;
}
-// Returns false if setup not permitted, errno set to last error.
-// If something is altered, set *change.
-bool fs_mgr_overlayfs_setup(const char* mount_point, bool* change, bool force) {
- if (change) *change = false;
- auto ret = false;
- if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret;
- if (!fs_mgr_boot_completed()) {
- errno = EBUSY;
- PERROR << "setup";
- return ret;
- }
-
- auto save_errno = errno;
- Fstab fstab;
- if (!ReadDefaultFstab(&fstab)) {
+bool fs_mgr_overlayfs_setup(const char* mount_point, bool* want_reboot, bool just_disabled_verity) {
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
+ LOG(ERROR) << "Overlayfs is not supported";
return false;
}
- errno = save_errno;
+
+ if (!fs_mgr_boot_completed()) {
+ LOG(ERROR) << "Cannot setup overlayfs before persistent properties are ready";
+ return false;
+ }
+
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
+ LOG(ERROR) << "Could not read fstab";
+ return false;
+ }
+
auto candidates = fs_mgr_overlayfs_candidate_list(fstab);
for (auto it = candidates.begin(); it != candidates.end();) {
if (mount_point &&
@@ -1380,9 +1400,8 @@
it = candidates.erase(it);
continue;
}
- save_errno = errno;
- auto verity_enabled = !force && fs_mgr_is_verity_enabled(*it);
- if (errno == ENOENT || errno == ENXIO) errno = save_errno;
+
+ auto verity_enabled = !just_disabled_verity && fs_mgr_is_verity_enabled(*it);
if (verity_enabled) {
it = candidates.erase(it);
continue;
@@ -1390,12 +1409,20 @@
++it;
}
- if (candidates.empty()) return ret;
+ if (candidates.empty()) {
+ if (mount_point) {
+ LOG(ERROR) << "No overlayfs candidate was found for " << mount_point;
+ return false;
+ }
+ return true;
+ }
std::string dir;
for (const auto& overlay_mount_point : OverlayMountPoints()) {
if (overlay_mount_point == kScratchMountPoint) {
- if (!fs_mgr_overlayfs_setup_scratch(fstab, change)) continue;
+ if (!fs_mgr_overlayfs_setup_scratch(fstab)) {
+ continue;
+ }
} else {
if (GetEntryForMountPoint(&fstab, overlay_mount_point) == nullptr) {
continue;
@@ -1405,17 +1432,21 @@
break;
}
if (dir.empty()) {
- if (change && *change) errno = ESRCH;
- if (errno == EPERM) errno = save_errno;
- return ret;
+ LOG(ERROR) << "Could not allocate backing storage for overlays";
+ return false;
}
- std::string overlay;
- ret |= fs_mgr_overlayfs_setup_dir(dir, &overlay, change);
- for (const auto& entry : candidates) {
- ret |= fs_mgr_overlayfs_setup_one(overlay, fs_mgr_mount_point(entry.mount_point), change);
+ const auto overlay = fs_mgr_overlayfs_setup_dir(dir);
+ if (overlay.empty()) {
+ return false;
}
- return ret;
+
+ bool ok = true;
+ for (const auto& entry : candidates) {
+ auto fstab_mount_point = fs_mgr_mount_point(entry.mount_point);
+ ok &= fs_mgr_overlayfs_setup_one(overlay, fstab_mount_point, want_reboot);
+ }
+ return ok;
}
struct MapInfo {
@@ -1736,6 +1767,7 @@
std::string fs_mgr_get_context(const std::string& mount_point) {
char* ctx = nullptr;
if (getfilecon(mount_point.c_str(), &ctx) == -1) {
+ PLOG(ERROR) << "getfilecon " << mount_point;
return "";
}
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 4a927d0..2202fda 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -317,15 +317,15 @@
}
if (fs_mgr_wants_overlayfs(&entry)) {
- bool change = false;
+ bool want_reboot = false;
bool force = result->disabled_verity;
- if (!fs_mgr_overlayfs_setup(mount_point.c_str(), &change, force)) {
+ if (!fs_mgr_overlayfs_setup(mount_point.c_str(), &want_reboot, force)) {
LOG(ERROR) << "Overlayfs setup for " << mount_point << " failed, skipping";
status = BAD_OVERLAY;
it = partitions->erase(it);
continue;
}
- if (change) {
+ if (want_reboot) {
LOG(INFO) << "Using overlayfs for " << mount_point;
result->reboot_later = true;
result->setup_overlayfs = true;
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index ec1d78f..590f66b 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -28,14 +28,20 @@
bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry);
bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab);
-bool fs_mgr_overlayfs_setup(const char* mount_point = nullptr, bool* change = nullptr,
- bool force = true);
bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
bool fs_mgr_overlayfs_is_setup();
bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev);
bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true);
std::string fs_mgr_get_context(const std::string& mount_point);
+// If "mount_point" is non-null, set up exactly one overlay.
+// If "mount_point" is null, setup any overlays.
+//
+// If |want_reboot| is non-null, and a reboot is needed to apply overlays, then
+// it will be true on return. The caller is responsible for initializing it.
+bool fs_mgr_overlayfs_setup(const char* mount_point = nullptr, bool* want_reboot = nullptr,
+ bool just_disabled_verity = true);
+
enum class OverlayfsValidResult {
kNotSupported = 0,
kOk,
diff --git a/healthd/Android.bp b/healthd/Android.bp
index f180006..a090b74 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -342,20 +342,20 @@
],
}
-// /vendor/etc/res/images/charger/battery_fail.png
+// /vendor/etc/res/images/default/charger/battery_fail.png
prebuilt_etc {
name: "system_core_charger_res_images_battery_fail.png_default_vendor",
src: "images/battery_fail.png",
- relative_install_path: "res/images/charger/default",
+ relative_install_path: "res/images/default/charger",
vendor: true,
filename: "battery_fail.png",
}
-// /vendor/etc/res/images/charger/battery_scale.png
+// /vendor/etc/res/images/default/charger/battery_scale.png
prebuilt_etc {
name: "system_core_charger_res_images_battery_scale.png_default_vendor",
src: "images/battery_scale.png",
- relative_install_path: "res/images/charger/default",
+ relative_install_path: "res/images/default/charger",
vendor: true,
filename: "battery_scale.png",
}
diff --git a/init/Android.bp b/init/Android.bp
index 856fe3e..dfc90da 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -53,6 +53,7 @@
"util.cpp",
]
init_device_sources = [
+ "apex_init_util.cpp",
"block_dev_initializer.cpp",
"bootchart.cpp",
"builtins.cpp",
@@ -217,6 +218,7 @@
"selinux_policy_version",
],
srcs: init_common_sources + init_device_sources,
+ export_include_dirs: ["."],
generated_sources: [
"apex-info-list",
],
@@ -246,6 +248,10 @@
],
},
},
+ visibility: [
+ "//system/apex/apexd",
+ "//frameworks/native/cmds/installd",
+ ],
}
phony {
diff --git a/init/action_manager.h b/init/action_manager.h
index 2746a7c..68912a8 100644
--- a/init/action_manager.h
+++ b/init/action_manager.h
@@ -49,6 +49,7 @@
bool HasMoreCommands() const;
void DumpState() const;
void ClearQueue();
+ auto size() const { return actions_.size(); }
private:
ActionManager(ActionManager const&) = delete;
diff --git a/init/apex_init_util.cpp b/init/apex_init_util.cpp
new file mode 100644
index 0000000..d618a6e
--- /dev/null
+++ b/init/apex_init_util.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 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 "apex_init_util.h"
+
+#include <glob.h>
+
+#include <map>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/result.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+
+#include "action_manager.h"
+#include "init.h"
+#include "parser.h"
+#include "service_list.h"
+#include "util.h"
+
+namespace android {
+namespace init {
+
+static Result<std::vector<std::string>> CollectApexConfigs(const std::string& apex_name) {
+ glob_t glob_result;
+ std::string glob_pattern = apex_name.empty() ?
+ "/apex/*/etc/*rc" : "/apex/" + apex_name + "/etc/*rc";
+
+ const int ret = glob(glob_pattern.c_str(), GLOB_MARK, nullptr, &glob_result);
+ if (ret != 0 && ret != GLOB_NOMATCH) {
+ globfree(&glob_result);
+ return Error() << "Glob pattern '" << glob_pattern << "' failed";
+ }
+ std::vector<std::string> configs;
+ for (size_t i = 0; i < glob_result.gl_pathc; i++) {
+ std::string path = glob_result.gl_pathv[i];
+ // Filter-out /apex/<name>@<ver> paths. The paths are bind-mounted to
+ // /apex/<name> paths, so unless we filter them out, we will parse the
+ // same file twice.
+ std::vector<std::string> paths = android::base::Split(path, "/");
+ if (paths.size() >= 3 && paths[2].find('@') != std::string::npos) {
+ continue;
+ }
+ // Filter directories
+ if (path.back() == '/') {
+ continue;
+ }
+ configs.push_back(path);
+ }
+ globfree(&glob_result);
+ return configs;
+}
+
+static Result<void> ParseConfigs(const std::vector<std::string>& configs) {
+ Parser parser = CreateApexConfigParser(ActionManager::GetInstance(),
+ ServiceList::GetInstance());
+ bool success = true;
+ for (const auto& c : configs) {
+ success &= parser.ParseConfigFile(c);
+ }
+
+ if (success) {
+ return {};
+ } else {
+ return Error() << "Unable to parse apex configs";
+ }
+}
+
+Result<void> ParseApexConfigs(const std::string& apex_name) {
+ auto configs = OR_RETURN(CollectApexConfigs(apex_name));
+
+ if (configs.empty()) {
+ return {};
+ }
+
+ auto filtered_configs = FilterVersionedConfigs(configs,
+ android::base::GetIntProperty("ro.build.version.sdk", INT_MAX));
+ return ParseConfigs(filtered_configs);
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/apex_init_util.h b/init/apex_init_util.h
new file mode 100644
index 0000000..43f8ad5
--- /dev/null
+++ b/init/apex_init_util.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "result.h"
+
+namespace android {
+namespace init {
+
+// Parse all config files for a given apex.
+// If apex name is empty(""), config files for all apexes will be parsed.
+Result<void> ParseApexConfigs(const std::string& apex_name);
+
+} // namespace init
+} // namespace android
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 38f6f39..c8cb253 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -69,6 +69,7 @@
#include <system/thread_defs.h>
#include "action_manager.h"
+#include "apex_init_util.h"
#include "bootchart.h"
#include "builtin_arguments.h"
#include "fscrypt_init_extensions.h"
@@ -1279,48 +1280,6 @@
return GenerateLinkerConfiguration();
}
-static Result<void> parse_apex_configs() {
- glob_t glob_result;
- static constexpr char glob_pattern[] = "/apex/*/etc/*rc";
- const int ret = glob(glob_pattern, GLOB_MARK, nullptr, &glob_result);
- if (ret != 0 && ret != GLOB_NOMATCH) {
- globfree(&glob_result);
- return Error() << "glob pattern '" << glob_pattern << "' failed";
- }
- std::vector<std::string> configs;
- Parser parser =
- CreateApexConfigParser(ActionManager::GetInstance(), ServiceList::GetInstance());
- for (size_t i = 0; i < glob_result.gl_pathc; i++) {
- std::string path = glob_result.gl_pathv[i];
- // Filter-out /apex/<name>@<ver> paths. The paths are bind-mounted to
- // /apex/<name> paths, so unless we filter them out, we will parse the
- // same file twice.
- std::vector<std::string> paths = android::base::Split(path, "/");
- if (paths.size() >= 3 && paths[2].find('@') != std::string::npos) {
- continue;
- }
- // Filter directories
- if (path.back() == '/') {
- continue;
- }
- configs.push_back(path);
- }
- globfree(&glob_result);
-
- int active_sdk = android::base::GetIntProperty("ro.build.version.sdk", INT_MAX);
-
- bool success = true;
- for (const auto& c : parser.FilterVersionedConfigs(configs, active_sdk)) {
- success &= parser.ParseConfigFile(c);
- }
- ServiceList::GetInstance().MarkServicesUpdate();
- if (success) {
- return {};
- } else {
- return Error() << "Could not parse apex configs";
- }
-}
-
/*
* Creates a directory under /data/misc/apexdata/ for each APEX.
*/
@@ -1351,7 +1310,8 @@
if (!create_dirs.ok()) {
return create_dirs.error();
}
- auto parse_configs = parse_apex_configs();
+ auto parse_configs = ParseApexConfigs(/*apex_name=*/"");
+ ServiceList::GetInstance().MarkServicesUpdate();
if (!parse_configs.ok()) {
return parse_configs.error();
}
diff --git a/init/init.cpp b/init/init.cpp
index be99a1c..ce668d7 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -63,8 +63,10 @@
#include <selinux/android.h>
#include <unwindstack/AndroidUnwinder.h>
+#include "action.h"
+#include "action_manager.h"
#include "action_parser.h"
-#include "builtins.h"
+#include "apex_init_util.h"
#include "epoll.h"
#include "first_stage_init.h"
#include "first_stage_mount.h"
@@ -82,6 +84,7 @@
#include "selabel.h"
#include "selinux.h"
#include "service.h"
+#include "service_list.h"
#include "service_parser.h"
#include "sigchld_handler.h"
#include "snapuserd_transition.h"
@@ -446,11 +449,47 @@
return {};
}
+int StopServicesFromApex(const std::string& apex_name) {
+ auto services = ServiceList::GetInstance().FindServicesByApexName(apex_name);
+ if (services.empty()) {
+ LOG(INFO) << "No service found for APEX: " << apex_name;
+ return 0;
+ }
+ std::set<std::string> service_names;
+ for (const auto& service : services) {
+ service_names.emplace(service->name());
+ }
+ constexpr std::chrono::milliseconds kServiceStopTimeout = 10s;
+ int still_running = StopServicesAndLogViolations(service_names, kServiceStopTimeout,
+ true /*SIGTERM*/);
+ // Send SIGKILL to ones that didn't terminate cleanly.
+ if (still_running > 0) {
+ still_running = StopServicesAndLogViolations(service_names, 0ms, false /*SIGKILL*/);
+ }
+ return still_running;
+}
+
+void RemoveServiceAndActionFromApex(const std::string& apex_name) {
+ // Remove services and actions that match apex name
+ ActionManager::GetInstance().RemoveActionIf([&](const std::unique_ptr<Action>& action) -> bool {
+ if (GetApexNameFromFileName(action->filename()) == apex_name) {
+ return true;
+ }
+ return false;
+ });
+ ServiceList::GetInstance().RemoveServiceIf([&](const std::unique_ptr<Service>& s) -> bool {
+ if (GetApexNameFromFileName(s->filename()) == apex_name) {
+ return true;
+ }
+ return false;
+ });
+}
+
static Result<void> DoUnloadApex(const std::string& apex_name) {
- std::string prop_name = "init.apex." + apex_name;
- // TODO(b/232114573) remove services and actions read from the apex
- // TODO(b/232799709) kill services from the apex
- SetProperty(prop_name, "unloaded");
+ if (StopServicesFromApex(apex_name) > 0) {
+ return Error() << "Unable to stop all service from " << apex_name;
+ }
+ RemoveServiceAndActionFromApex(apex_name);
return {};
}
@@ -474,14 +513,14 @@
}
static Result<void> DoLoadApex(const std::string& apex_name) {
- std::string prop_name = "init.apex." + apex_name;
- // TODO(b/232799709) read .rc files from the apex
+ if(auto result = ParseApexConfigs(apex_name); !result.ok()) {
+ return result.error();
+ }
if (auto result = UpdateApexLinkerConfig(apex_name); !result.ok()) {
return result.error();
}
- SetProperty(prop_name, "loaded");
return {};
}
diff --git a/init/init.h b/init/init.h
index 5220535..063632a 100644
--- a/init/init.h
+++ b/init/init.h
@@ -46,5 +46,9 @@
int SecondStageMain(int argc, char** argv);
+int StopServicesFromApex(const std::string& apex_name);
+
+void RemoveServiceAndActionFromApex(const std::string& apex_name);
+
} // namespace init
} // namespace android
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 5651a83..05cf3fd 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -15,11 +15,14 @@
*/
#include <functional>
+#include <string_view>
+#include <type_traits>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <gtest/gtest.h>
+#include <selinux/selinux.h>
#include "action.h"
#include "action_manager.h"
@@ -27,6 +30,7 @@
#include "builtin_arguments.h"
#include "builtins.h"
#include "import_parser.h"
+#include "init.h"
#include "keyword_map.h"
#include "parser.h"
#include "service.h"
@@ -37,6 +41,7 @@
using android::base::GetIntProperty;
using android::base::GetProperty;
using android::base::SetProperty;
+using android::base::StringReplace;
using android::base::WaitForProperty;
using namespace std::literals;
@@ -188,6 +193,198 @@
EXPECT_TRUE(service->is_override());
}
+static std::string GetSecurityContext() {
+ char* ctx;
+ if (getcon(&ctx) == -1) {
+ ADD_FAILURE() << "Failed to call getcon : " << strerror(errno);
+ }
+ std::string result = std::string(ctx);
+ freecon(ctx);
+ return result;
+}
+
+void TestStartApexServices(const std::vector<std::string>& service_names,
+ const std::string& apex_name) {
+ for (auto const& svc : service_names) {
+ auto service = ServiceList::GetInstance().FindService(svc);
+ ASSERT_NE(nullptr, service);
+ ASSERT_RESULT_OK(service->Start());
+ ASSERT_TRUE(service->IsRunning());
+ LOG(INFO) << "Service " << svc << " is running";
+ if (!apex_name.empty()) {
+ service->set_filename("/apex/" + apex_name + "/init_test.rc");
+ } else {
+ service->set_filename("");
+ }
+ }
+ if (!apex_name.empty()) {
+ auto apex_services = ServiceList::GetInstance().FindServicesByApexName(apex_name);
+ EXPECT_EQ(service_names.size(), apex_services.size());
+ }
+}
+
+void TestStopApexServices(const std::vector<std::string>& service_names, bool expect_to_run) {
+ for (auto const& svc : service_names) {
+ auto service = ServiceList::GetInstance().FindService(svc);
+ ASSERT_NE(nullptr, service);
+ EXPECT_EQ(expect_to_run, service->IsRunning());
+ }
+}
+
+void TestRemoveApexService(const std::vector<std::string>& service_names, bool exist) {
+ for (auto const& svc : service_names) {
+ auto service = ServiceList::GetInstance().FindService(svc);
+ ASSERT_EQ(exist, service != nullptr);
+ }
+}
+
+void InitApexService(const std::string_view& init_template) {
+ std::string init_script = StringReplace(init_template, "$selabel",
+ GetSecurityContext(), true);
+
+ TestInitText(init_script, BuiltinFunctionMap(), {}, &ActionManager::GetInstance(),
+ &ServiceList::GetInstance());
+}
+
+void TestApexServicesInit(const std::vector<std::string>& apex_services,
+ const std::vector<std::string>& other_apex_services,
+ const std::vector<std::string> non_apex_services) {
+ auto num_svc = apex_services.size() + other_apex_services.size() + non_apex_services.size();
+ ASSERT_EQ(num_svc, ServiceList::GetInstance().size());
+
+ TestStartApexServices(apex_services, "com.android.apex.test_service");
+ TestStartApexServices(other_apex_services, "com.android.other_apex.test_service");
+ TestStartApexServices(non_apex_services, /*apex_anme=*/ "");
+
+ StopServicesFromApex("com.android.apex.test_service");
+ TestStopApexServices(apex_services, /*expect_to_run=*/ false);
+ TestStopApexServices(other_apex_services, /*expect_to_run=*/ true);
+ TestStopApexServices(non_apex_services, /*expect_to_run=*/ true);
+
+ RemoveServiceAndActionFromApex("com.android.apex.test_service");
+ ASSERT_EQ(other_apex_services.size() + non_apex_services.size(),
+ ServiceList::GetInstance().size());
+
+ // TODO(b/244232142): Add test to check if actions are removed
+ TestRemoveApexService(apex_services, /*exist*/ false);
+ TestRemoveApexService(other_apex_services, /*exist*/ true);
+ TestRemoveApexService(non_apex_services, /*exist*/ true);
+
+ ServiceList::GetInstance().RemoveServiceIf([&](const std::unique_ptr<Service>& s) -> bool {
+ return true;
+ });
+
+ ActionManager::GetInstance().RemoveActionIf([&](const std::unique_ptr<Action>& s) -> bool {
+ return true;
+ });
+}
+
+TEST(init, StopServiceByApexName) {
+ std::string_view script_template = R"init(
+service apex_test_service /system/bin/yes
+ user shell
+ group shell
+ seclabel $selabel
+)init";
+ InitApexService(script_template);
+ TestApexServicesInit({"apex_test_service"}, {}, {});
+}
+
+TEST(init, StopMultipleServicesByApexName) {
+ std::string_view script_template = R"init(
+service apex_test_service_multiple_a /system/bin/yes
+ user shell
+ group shell
+ seclabel $selabel
+service apex_test_service_multiple_b /system/bin/id
+ user shell
+ group shell
+ seclabel $selabel
+)init";
+ InitApexService(script_template);
+ TestApexServicesInit({"apex_test_service_multiple_a",
+ "apex_test_service_multiple_b"}, {}, {});
+}
+
+TEST(init, StopServicesFromMultipleApexes) {
+ std::string_view apex_script_template = R"init(
+service apex_test_service_multi_apex_a /system/bin/yes
+ user shell
+ group shell
+ seclabel $selabel
+service apex_test_service_multi_apex_b /system/bin/id
+ user shell
+ group shell
+ seclabel $selabel
+)init";
+ InitApexService(apex_script_template);
+
+ std::string_view other_apex_script_template = R"init(
+service apex_test_service_multi_apex_c /system/bin/yes
+ user shell
+ group shell
+ seclabel $selabel
+)init";
+ InitApexService(other_apex_script_template);
+
+ TestApexServicesInit({"apex_test_service_multi_apex_a",
+ "apex_test_service_multi_apex_b"}, {"apex_test_service_multi_apex_c"}, {});
+}
+
+TEST(init, StopServicesFromApexAndNonApex) {
+ std::string_view apex_script_template = R"init(
+service apex_test_service_apex_a /system/bin/yes
+ user shell
+ group shell
+ seclabel $selabel
+service apex_test_service_apex_b /system/bin/id
+ user shell
+ group shell
+ seclabel $selabel
+)init";
+ InitApexService(apex_script_template);
+
+ std::string_view non_apex_script_template = R"init(
+service apex_test_service_non_apex /system/bin/yes
+ user shell
+ group shell
+ seclabel $selabel
+)init";
+ InitApexService(non_apex_script_template);
+
+ TestApexServicesInit({"apex_test_service_apex_a",
+ "apex_test_service_apex_b"}, {}, {"apex_test_service_non_apex"});
+}
+
+TEST(init, StopServicesFromApexMixed) {
+ std::string_view script_template = R"init(
+service apex_test_service_mixed_a /system/bin/yes
+ user shell
+ group shell
+ seclabel $selabel
+)init";
+ InitApexService(script_template);
+
+ std::string_view other_apex_script_template = R"init(
+service apex_test_service_mixed_b /system/bin/yes
+ user shell
+ group shell
+ seclabel $selabel
+)init";
+ InitApexService(other_apex_script_template);
+
+ std::string_view non_apex_script_template = R"init(
+service apex_test_service_mixed_c /system/bin/yes
+ user shell
+ group shell
+ seclabel $selabel
+)init";
+ InitApexService(non_apex_script_template);
+
+ TestApexServicesInit({"apex_test_service_mixed_a"},
+ {"apex_test_service_mixed_b"}, {"apex_test_service_mixed_c"});
+}
+
TEST(init, EventTriggerOrderMultipleFiles) {
// 6 total files, which should have their triggers executed in the following order:
// 1: start - original script parsed
@@ -338,20 +535,6 @@
EXPECT_EQ(2, num_executed);
}
-TEST(init, RespondToCtlApexMessages) {
- if (getuid() != 0) {
- GTEST_SKIP() << "Skipping test, must be run as root.";
- return;
- }
-
- std::string apex_name = "com.android.apex.cts.shim";
- SetProperty("ctl.apex_unload", apex_name);
- EXPECT_TRUE(WaitForProperty("init.apex." + apex_name, "unloaded", 10s));
-
- SetProperty("ctl.apex_load", apex_name);
- EXPECT_TRUE(WaitForProperty("init.apex." + apex_name, "loaded", 10s));
-}
-
TEST(init, RejectsCriticalAndOneshotService) {
if (GetIntProperty("ro.product.first_api_level", 10000) < 30) {
GTEST_SKIP() << "Test only valid for devices launching with R or later";
diff --git a/init/parser.cpp b/init/parser.cpp
index abc2017..0a388db 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -156,58 +156,6 @@
return true;
}
-std::vector<std::string> Parser::FilterVersionedConfigs(const std::vector<std::string>& configs,
- int active_sdk) {
- std::vector<std::string> filtered_configs;
-
- std::map<std::string, std::pair<std::string, int>> script_map;
- for (const auto& c : configs) {
- int sdk = 0;
- const std::vector<std::string> parts = android::base::Split(c, ".");
- std::string base;
- if (parts.size() < 2) {
- continue;
- }
-
- // parts[size()-1], aka the suffix, should be "rc" or "#rc"
- // any other pattern gets discarded
-
- const auto& suffix = parts[parts.size() - 1];
- if (suffix == "rc") {
- sdk = 0;
- } else {
- char trailer[9] = {0};
- int r = sscanf(suffix.c_str(), "%d%8s", &sdk, trailer);
- if (r != 2) {
- continue;
- }
- if (strlen(trailer) > 2 || strcmp(trailer, "rc") != 0) {
- continue;
- }
- }
-
- if (sdk < 0 || sdk > active_sdk) {
- continue;
- }
-
- base = parts[0];
- for (unsigned int i = 1; i < parts.size() - 1; i++) {
- base = base + "." + parts[i];
- }
-
- // is this preferred over what we already have
- auto it = script_map.find(base);
- if (it == script_map.end() || it->second.second < sdk) {
- script_map[base] = std::make_pair(c, sdk);
- }
- }
-
- for (const auto& m : script_map) {
- filtered_configs.push_back(m.second.first);
- }
- return filtered_configs;
-}
-
bool Parser::ParseConfigDir(const std::string& path) {
LOG(INFO) << "Parsing directory " << path << "...";
std::unique_ptr<DIR, decltype(&closedir)> config_dir(opendir(path.c_str()), closedir);
diff --git a/init/parser.h b/init/parser.h
index 2f4108f..95b0cd7 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -76,12 +76,6 @@
void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
void AddSingleLineParser(const std::string& prefix, LineCallback callback);
- // Compare all files */path.#rc and */path.rc with the same path prefix.
- // Keep the one with the highest # that doesn't exceed the system's SDK.
- // (.rc == .0rc for ranking purposes)
- std::vector<std::string> FilterVersionedConfigs(const std::vector<std::string>& configs,
- int active_sdk);
-
// Host init verifier check file permissions.
bool ParseConfigFileInsecure(const std::string& path);
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp
index 716f62e..d33a6b8 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -155,19 +155,33 @@
return *file_contents;
}
+Result<PersistentProperties> ParsePersistentPropertyFile(const std::string& file_contents) {
+ PersistentProperties persistent_properties;
+ if (!persistent_properties.ParseFromString(file_contents)) {
+ return Error() << "Unable to parse persistent property file: Could not parse protobuf";
+ }
+ for (auto& prop : persistent_properties.properties()) {
+ if (!StartsWith(prop.name(), "persist.")) {
+ return Error() << "Unable to load persistent property file: property '" << prop.name()
+ << "' doesn't start with 'persist.'";
+ }
+ }
+ return persistent_properties;
+}
+
} // namespace
Result<PersistentProperties> LoadPersistentPropertyFile() {
auto file_contents = ReadPersistentPropertyFile();
if (!file_contents.ok()) return file_contents.error();
- PersistentProperties persistent_properties;
- if (persistent_properties.ParseFromString(*file_contents)) return persistent_properties;
-
- // If the file cannot be parsed in either format, then we don't have any recovery
- // mechanisms, so we delete it to allow for future writes to take place successfully.
- unlink(persistent_property_filename.c_str());
- return Error() << "Unable to parse persistent property file: Could not parse protobuf";
+ auto persistent_properties = ParsePersistentPropertyFile(*file_contents);
+ if (!persistent_properties.ok()) {
+ // If the file cannot be parsed in either format, then we don't have any recovery
+ // mechanisms, so we delete it to allow for future writes to take place successfully.
+ unlink(persistent_property_filename.c_str());
+ }
+ return persistent_properties;
}
Result<void> WritePersistentPropertyFile(const PersistentProperties& persistent_properties) {
diff --git a/init/persistent_properties_test.cpp b/init/persistent_properties_test.cpp
index 60cecde..e5d26db 100644
--- a/init/persistent_properties_test.cpp
+++ b/init/persistent_properties_test.cpp
@@ -155,5 +155,28 @@
EXPECT_FALSE(it == read_back_properties.properties().end());
}
+TEST(persistent_properties, RejectNonPersistProperty) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ persistent_property_filename = tf.path;
+
+ WritePersistentProperty("notpersist.sys.locale", "pt-BR");
+
+ auto read_back_properties = LoadPersistentProperties();
+ EXPECT_EQ(read_back_properties.properties().size(), 0);
+
+ WritePersistentProperty("persist.sys.locale", "pt-BR");
+
+ read_back_properties = LoadPersistentProperties();
+ EXPECT_GT(read_back_properties.properties().size(), 0);
+
+ auto it = std::find_if(read_back_properties.properties().begin(),
+ read_back_properties.properties().end(), [](const auto& entry) {
+ return entry.name() == "persist.sys.locale" &&
+ entry.value() == "pt-BR";
+ });
+ EXPECT_FALSE(it == read_back_properties.properties().end());
+}
+
} // namespace init
} // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 4e4bfd8..880674c 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -491,7 +491,7 @@
return ErrnoError() << "zram_backing_dev: swapoff (" << backing_dev << ")"
<< " failed";
}
- LOG(INFO) << "swapoff() took " << swap_timer;;
+ LOG(INFO) << "swapoff() took " << swap_timer;
if (!WriteStringToFile("1", ZRAM_RESET)) {
return Error() << "zram_backing_dev: reset (" << backing_dev << ")"
diff --git a/init/service.h b/init/service.h
index c14b312..6d9a0ca 100644
--- a/init/service.h
+++ b/init/service.h
@@ -143,6 +143,8 @@
}
}
Subcontext* subcontext() const { return subcontext_; }
+ const std::string& filename() const { return filename_; }
+ void set_filename(const std::string& name) { filename_ = name; }
private:
void NotifyStateChange(const std::string& new_state) const;
diff --git a/init/service_list.h b/init/service_list.h
index 555da25..f858bc3 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -16,10 +16,14 @@
#pragma once
+#include <iterator>
#include <memory>
#include <vector>
+#include <android-base/logging.h>
+
#include "service.h"
+#include "util.h"
namespace android {
namespace init {
@@ -52,6 +56,17 @@
return nullptr;
}
+ std::vector<Service*> FindServicesByApexName(const std::string& apex_name) const {
+ CHECK(!apex_name.empty()) << "APEX name cannot be empty";
+ std::vector<Service*> matches;
+ for (const auto& svc : services_) {
+ if (GetApexNameFromFileName(svc->filename()) == apex_name) {
+ matches.emplace_back(svc.get());
+ }
+ }
+ return matches;
+ }
+
Service* FindInterface(const std::string& interface_name) {
for (const auto& svc : services_) {
if (svc->interfaces().count(interface_name) > 0) {
@@ -79,6 +94,8 @@
services_update_finished_ = false;
}
+ auto size() const { return services_.size(); }
+
private:
std::vector<std::unique_ptr<Service>> services_;
diff --git a/init/util.cpp b/init/util.cpp
index bfc3fb6..2d40142 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -30,6 +30,7 @@
#include <time.h>
#include <unistd.h>
+#include <map>
#include <thread>
#include <android-base/file.h>
@@ -748,5 +749,57 @@
return "";
}
+std::vector<std::string> FilterVersionedConfigs(const std::vector<std::string>& configs,
+ int active_sdk) {
+ std::vector<std::string> filtered_configs;
+
+ std::map<std::string, std::pair<std::string, int>> script_map;
+ for (const auto& c : configs) {
+ int sdk = 0;
+ const std::vector<std::string> parts = android::base::Split(c, ".");
+ std::string base;
+ if (parts.size() < 2) {
+ continue;
+ }
+
+ // parts[size()-1], aka the suffix, should be "rc" or "#rc"
+ // any other pattern gets discarded
+
+ const auto& suffix = parts[parts.size() - 1];
+ if (suffix == "rc") {
+ sdk = 0;
+ } else {
+ char trailer[9] = {0};
+ int r = sscanf(suffix.c_str(), "%d%8s", &sdk, trailer);
+ if (r != 2) {
+ continue;
+ }
+ if (strlen(trailer) > 2 || strcmp(trailer, "rc") != 0) {
+ continue;
+ }
+ }
+
+ if (sdk < 0 || sdk > active_sdk) {
+ continue;
+ }
+
+ base = parts[0];
+ for (unsigned int i = 1; i < parts.size() - 1; i++) {
+ base = base + "." + parts[i];
+ }
+
+ // is this preferred over what we already have
+ auto it = script_map.find(base);
+ if (it == script_map.end() || it->second.second < sdk) {
+ script_map[base] = std::make_pair(c, sdk);
+ }
+ }
+
+ for (const auto& m : script_map) {
+ filtered_configs.push_back(m.second.first);
+ }
+ return filtered_configs;
+}
+
} // namespace init
} // namespace android
diff --git a/init/util.h b/init/util.h
index daec470..0181bf0 100644
--- a/init/util.h
+++ b/init/util.h
@@ -109,5 +109,11 @@
bool Has32BitAbi();
std::string GetApexNameFromFileName(const std::string& path);
+
+// Compare all files */path.#rc and */path.rc with the same path prefix.
+// Keep the one with the highest # that doesn't exceed the system's SDK.
+// (.rc == .0rc for ranking purposes)
+std::vector<std::string> FilterVersionedConfigs(const std::vector<std::string>& configs,
+ int active_sdk);
} // namespace init
} // namespace android
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index bdb8075..da5005c 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -41,9 +41,11 @@
*/
#define AID_ROOT 0 /* traditional unix root user */
-/* The following are for LTP and should only be used for testing */
-#define AID_DAEMON 1 /* traditional unix daemon owner */
-#define AID_BIN 2 /* traditional unix binaries owner */
+
+/* The following are for tests like LTP and should only be used for testing. */
+#define AID_DAEMON 1 /* Traditional unix daemon owner. */
+#define AID_BIN 2 /* Traditional unix binaries owner. */
+#define AID_SYS 3 /* A group with the same gid on Linux/macOS/Android. */
#define AID_SYSTEM 1000 /* system server */
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 8589a8d..15f95fc 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -76,6 +76,21 @@
"Name": "FreezerState",
"Controller": "freezer",
"File": "cgroup.freeze"
+ },
+ {
+ "Name": "BfqWeight",
+ "Controller": "io",
+ "File": "io.bfq.weight"
+ },
+ {
+ "Name": "CfqGroupIdle",
+ "Controller": "io",
+ "File": "io.group_idle"
+ },
+ {
+ "Name": "CfqWeight",
+ "Controller": "io",
+ "File": "io.weight"
}
],
@@ -444,6 +459,33 @@
{
"Controller": "blkio",
"Path": "background"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "BfqWeight",
+ "Value": "10",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqGroupIdle",
+ "Value": "0",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqWeight",
+ "Value": "200",
+ "Optional": "true"
}
}
]
@@ -457,6 +499,33 @@
{
"Controller": "blkio",
"Path": ""
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "BfqWeight",
+ "Value": "100",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqGroupIdle",
+ "Value": "0",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqWeight",
+ "Value": "1000",
+ "Optional": "true"
}
}
]
@@ -470,6 +539,33 @@
{
"Controller": "blkio",
"Path": ""
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "BfqWeight",
+ "Value": "100",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqGroupIdle",
+ "Value": "0",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqWeight",
+ "Value": "1000",
+ "Optional": "true"
}
}
]
@@ -483,6 +579,33 @@
{
"Controller": "blkio",
"Path": ""
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "BfqWeight",
+ "Value": "100",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqGroupIdle",
+ "Value": "0",
+ "Optional": "true"
+ }
+ },
+ {
+ "Name": "SetAttribute",
+ "Params":
+ {
+ "Name": "CfqWeight",
+ "Value": "1000",
+ "Optional": "true"
}
}
]
diff --git a/libutils/include/utils/LruCache.h b/libutils/include/utils/LruCache.h
index 36775d0..b4243a3 100644
--- a/libutils/include/utils/LruCache.h
+++ b/libutils/include/utils/LruCache.h
@@ -84,13 +84,13 @@
const TKey& getKey() const final { return key; }
};
- struct HashForEntry : public std::unary_function<KeyedEntry*, hash_t> {
+ struct HashForEntry {
size_t operator() (const KeyedEntry* entry) const {
return hash_type(entry->getKey());
};
};
- struct EqualityForHashedEntries : public std::unary_function<KeyedEntry*, hash_t> {
+ struct EqualityForHashedEntries {
bool operator() (const KeyedEntry* lhs, const KeyedEntry* rhs) const {
return lhs->getKey() == rhs->getKey();
};
diff --git a/set-verity-state/set-verity-state.cpp b/set-verity-state/set-verity-state.cpp
index de9a452..3c0df79 100644
--- a/set-verity-state/set-verity-state.cpp
+++ b/set-verity-state/set-verity-state.cpp
@@ -80,17 +80,17 @@
}
bool overlayfs_setup(bool enable) {
- auto change = false;
+ auto want_reboot = false;
errno = 0;
- if (enable ? fs_mgr_overlayfs_setup(nullptr, &change)
- : fs_mgr_overlayfs_teardown(nullptr, &change)) {
- if (change) {
+ if (enable ? fs_mgr_overlayfs_setup(nullptr, &want_reboot)
+ : fs_mgr_overlayfs_teardown(nullptr, &want_reboot)) {
+ if (want_reboot) {
LOG(INFO) << (enable ? "Enabled" : "Disabled") << " overlayfs";
}
} else {
LOG(ERROR) << "Failed to " << (enable ? "enable" : "disable") << " overlayfs";
}
- return change;
+ return want_reboot;
}
struct SetVerityStateResult {