Loading init/README.md +37 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,43 @@ monolithic init .rc files. This additionally will aid in merge conflict resolution when multiple services are added to the system, as each one will go into a separate file. Versioned RC files within APEXs ------------------------------- With the arrival of mainline on Android Q, the individual mainline modules carry their own init.rc files within their boundaries. Init processes these files according to the naming pattern `/apex/*/etc/*rc`. Because APEX modules must run on more than one release of Android, they may require different parameters as part of the services they define. This is achieved, starting in Android T, by incorporating the SDK version information in the name of the init file. The suffix is changed from `.rc` to `.#rc` where # is the first SDK where that RC file is accepted. An init file specific to SDK=31 might be named `init.31rc`. With this scheme, an APEX may include multiple init files. An example is appropriate. For an APEX module with the following files in /apex/sample-module/apex/etc/: 1. init.rc 2. init.32rc 4. init.35rc The selection rule chooses the highest `.#rc` value that does not exceed the SDK of the currently running system. The unadorned `.rc` is interpreted as sdk=0. When this APEX is installed on a device with SDK <=31, the system will process init.rc. When installed on a device running SDK 32, 33, or 34, it will use init.32rc. When installed on a device running SDKs >= 35, it will choose init.35rc This versioning scheme is used only for the init files within APEX modules; it does not apply to the init files stored in /system/etc/init, /vendor/etc/init, or other directories. This naming scheme is available after Android S. Actions ------- Actions are named sequences of commands. Actions have a trigger which Loading init/builtins.cpp +56 −5 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include <net/if.h> #include <sched.h> #include <signal.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> Loading @@ -42,6 +43,7 @@ #include <sys/wait.h> #include <unistd.h> #include <map> #include <memory> #include <ApexProperties.sysprop.h> Loading Loading @@ -1313,7 +1315,7 @@ static Result<void> do_update_linker_config(const BuiltinArguments&) { static Result<void> parse_apex_configs() { glob_t glob_result; static constexpr char glob_pattern[] = "/apex/*/etc/*.rc"; 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); Loading @@ -1330,17 +1332,66 @@ static Result<void> parse_apex_configs() { if (paths.size() >= 3 && paths[2].find('@') != std::string::npos) { continue; } // Filter directories if (path.back() == '/') { continue; } configs.push_back(path); } globfree(&glob_result); bool success = true; // Compare all files /apex/path.#rc and /apex/path.rc with the same "/apex/path" prefix, // choosing the one with the highest # that doesn't exceed the system's SDK. // (.rc == .0rc for ranking purposes) // int active_sdk = android::base::GetIntProperty("ro.build.version.sdk", INT_MAX); std::map<std::string, std::pair<std::string, int>> script_map; for (const auto& c : configs) { if (c.back() == '/') { // skip if directory 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; } success &= parser.ParseConfigFile(c); } 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); } } bool success = true; for (const auto& m : script_map) { success &= parser.ParseConfigFile(m.second.first); } ServiceList::GetInstance().MarkServicesUpdate(); if (success) { Loading Loading
init/README.md +37 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,43 @@ monolithic init .rc files. This additionally will aid in merge conflict resolution when multiple services are added to the system, as each one will go into a separate file. Versioned RC files within APEXs ------------------------------- With the arrival of mainline on Android Q, the individual mainline modules carry their own init.rc files within their boundaries. Init processes these files according to the naming pattern `/apex/*/etc/*rc`. Because APEX modules must run on more than one release of Android, they may require different parameters as part of the services they define. This is achieved, starting in Android T, by incorporating the SDK version information in the name of the init file. The suffix is changed from `.rc` to `.#rc` where # is the first SDK where that RC file is accepted. An init file specific to SDK=31 might be named `init.31rc`. With this scheme, an APEX may include multiple init files. An example is appropriate. For an APEX module with the following files in /apex/sample-module/apex/etc/: 1. init.rc 2. init.32rc 4. init.35rc The selection rule chooses the highest `.#rc` value that does not exceed the SDK of the currently running system. The unadorned `.rc` is interpreted as sdk=0. When this APEX is installed on a device with SDK <=31, the system will process init.rc. When installed on a device running SDK 32, 33, or 34, it will use init.32rc. When installed on a device running SDKs >= 35, it will choose init.35rc This versioning scheme is used only for the init files within APEX modules; it does not apply to the init files stored in /system/etc/init, /vendor/etc/init, or other directories. This naming scheme is available after Android S. Actions ------- Actions are named sequences of commands. Actions have a trigger which Loading
init/builtins.cpp +56 −5 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include <net/if.h> #include <sched.h> #include <signal.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> Loading @@ -42,6 +43,7 @@ #include <sys/wait.h> #include <unistd.h> #include <map> #include <memory> #include <ApexProperties.sysprop.h> Loading Loading @@ -1313,7 +1315,7 @@ static Result<void> do_update_linker_config(const BuiltinArguments&) { static Result<void> parse_apex_configs() { glob_t glob_result; static constexpr char glob_pattern[] = "/apex/*/etc/*.rc"; 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); Loading @@ -1330,17 +1332,66 @@ static Result<void> parse_apex_configs() { if (paths.size() >= 3 && paths[2].find('@') != std::string::npos) { continue; } // Filter directories if (path.back() == '/') { continue; } configs.push_back(path); } globfree(&glob_result); bool success = true; // Compare all files /apex/path.#rc and /apex/path.rc with the same "/apex/path" prefix, // choosing the one with the highest # that doesn't exceed the system's SDK. // (.rc == .0rc for ranking purposes) // int active_sdk = android::base::GetIntProperty("ro.build.version.sdk", INT_MAX); std::map<std::string, std::pair<std::string, int>> script_map; for (const auto& c : configs) { if (c.back() == '/') { // skip if directory 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; } success &= parser.ParseConfigFile(c); } 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); } } bool success = true; for (const auto& m : script_map) { success &= parser.ParseConfigFile(m.second.first); } ServiceList::GetInstance().MarkServicesUpdate(); if (success) { Loading