Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74646e87 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Versioning for apex init.rc files"

parents d2ddb2a2 35ffd69d
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -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
+56 −5
Original line number Diff line number Diff line
@@ -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;
        }

        // 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) {