Versioning for apex init.rc files
Support an "init.#rc" versioning scheme for apex init files. chooses highest # <= current system sdk. ".rc" (aka the old init.rc) is treated as sdk 0 Document these semantics in README.md Bug: 198186200 Test: booting, lots of logcat output Change-Id: I2d0405be73dae9bafa6f22535b29ed6b053ddbc4
This commit is contained in:
parent
132f2341f9
commit
35ffd69db5
2 changed files with 93 additions and 5 deletions
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
@ -42,6 +43,7 @@
|
|||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include <ApexProperties.sysprop.h>
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
success &= parser.ParseConfigFile(c);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
for (const auto& m : script_map) {
|
||||
success &= parser.ParseConfigFile(m.second.first);
|
||||
}
|
||||
ServiceList::GetInstance().MarkServicesUpdate();
|
||||
if (success) {
|
||||
|
|
Loading…
Reference in a new issue