diff --git a/init/init.cpp b/init/init.cpp index 4955bc5f2..06589422b 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -442,6 +442,19 @@ static Result DoControlRestart(Service* service) { 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 @@ static const std::map>& GetCont 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 @@ static bool HandleControlMessage(std::string_view message, const std::string& na 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 0dc6ff640..5651a835d 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 @@ TEST(init, LazilyLoadedActionsCanBeTriggeredByTheNextTrigger) { 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";