Merge "Add ctl.apex_(un)load properties to (un)load apex"
diff --git a/init/init.cpp b/init/init.cpp
index 4955bc5..0658942 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -442,6 +442,19 @@
return {};
}
+static 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");
+}
+
+static void DoLoadApex(const std::string& apex_name) {
+ std::string prop_name = "init.apex." + apex_name;
+ // TODO(b/232799709) read .rc files from the apex
+ SetProperty(prop_name, "loaded");
+}
+
enum class ControlTarget {
SERVICE, // function gets called for the named service
INTERFACE, // action gets called for every service that holds this interface
@@ -465,6 +478,20 @@
return control_message_functions;
}
+static bool HandleApexControlMessage(std::string_view action, const std::string& name,
+ std::string_view message) {
+ if (action == "load") {
+ DoLoadApex(name);
+ return true;
+ } else if (action == "unload") {
+ DoUnloadApex(name);
+ return true;
+ } else {
+ LOG(ERROR) << "Unknown control msg '" << message << "'";
+ return false;
+ }
+}
+
static bool HandleControlMessage(std::string_view message, const std::string& name,
pid_t from_pid) {
std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);
@@ -476,8 +503,12 @@
process_cmdline = "unknown process";
}
- Service* service = nullptr;
auto action = message;
+ if (ConsumePrefix(&action, "apex_")) {
+ return HandleApexControlMessage(action, name, message);
+ }
+
+ Service* service = nullptr;
if (ConsumePrefix(&action, "interface_")) {
service = ServiceList::GetInstance().FindInterface(name);
} else {
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 0dc6ff6..5651a83 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -35,6 +35,10 @@
#include "util.h"
using android::base::GetIntProperty;
+using android::base::GetProperty;
+using android::base::SetProperty;
+using android::base::WaitForProperty;
+using namespace std::literals;
namespace android {
namespace init {
@@ -334,6 +338,20 @@
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";