Snap for 8146243 from c0c59c6244381f2ed369e47c18a94d4a43d0c0b2 to mainline-neuralnetworks-release

Change-Id: I5077d0dd85cfea5294a45288c8b2a91dd0a16f46
diff --git a/init/init.cpp b/init/init.cpp
index a7325ca..942feb9 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -27,6 +27,7 @@
 #include <sys/mount.h>
 #include <sys/signalfd.h>
 #include <sys/types.h>
+#include <sys/utsname.h>
 #include <unistd.h>
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
@@ -554,6 +555,19 @@
     }
 }
 
+/// Set ro.kernel.version property to contain the major.minor pair as returned
+/// by uname(2).
+static void SetKernelVersion() {
+    struct utsname uts;
+    unsigned int major, minor;
+
+    if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) {
+        LOG(ERROR) << "Could not parse the kernel version from uname";
+        return;
+    }
+    SetProperty("ro.kernel.version", android::base::StringPrintf("%u.%u", major, minor));
+}
+
 static void HandleSigtermSignal(const signalfd_siginfo& siginfo) {
     if (siginfo.ssi_pid != 0) {
         // Drop any userspace SIGTERM requests.
@@ -824,6 +838,7 @@
     export_oem_lock_status();
     MountHandler mount_handler(&epoll);
     SetUsbController();
+    SetKernelVersion();
 
     const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
     Action::set_function_map(&function_map);
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 68b21c6..f1333dd 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -156,7 +156,6 @@
     },
     srcs: [
         "config_utils.cpp",
-        "canned_fs_config.cpp",
         "iosched_policy.cpp",
         "load_file.cpp",
         "native_handle.cpp",
@@ -173,6 +172,7 @@
         not_windows: {
             srcs: libcutils_nonwindows_sources + [
                 "ashmem-host.cpp",
+                "canned_fs_config.cpp",
                 "fs_config.cpp",
                 "trace-host.cpp",
             ],
@@ -193,6 +193,7 @@
             srcs: libcutils_nonwindows_sources + [
                 "android_reboot.cpp",
                 "ashmem-dev.cpp",
+                "canned_fs_config.cpp",
                 "fs_config.cpp",
                 "klog.cpp",
                 "partition_utils.cpp",
diff --git a/libcutils/canned_fs_config.cpp b/libcutils/canned_fs_config.cpp
index 2772ef0..b677949 100644
--- a/libcutils/canned_fs_config.cpp
+++ b/libcutils/canned_fs_config.cpp
@@ -18,6 +18,8 @@
 #include <private/canned_fs_config.h>
 #include <private/fs_config.h>
 
+#include <android-base/strings.h>
+
 #include <errno.h>
 #include <inttypes.h>
 #include <limits.h>
@@ -25,104 +27,107 @@
 #include <stdlib.h>
 #include <string.h>
 
-typedef struct {
-    const char* path;
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+
+using android::base::ConsumePrefix;
+using android::base::StartsWith;
+using android::base::Tokenize;
+
+struct Entry {
+    std::string path;
     unsigned uid;
     unsigned gid;
     unsigned mode;
     uint64_t capabilities;
-} Path;
+};
 
-static Path* canned_data = NULL;
-static int canned_alloc = 0;
-static int canned_used = 0;
-
-static int path_compare(const void* a, const void* b) {
-    return strcmp(((Path*)a)->path, ((Path*)b)->path);
-}
+static std::vector<Entry> canned_data;
 
 int load_canned_fs_config(const char* fn) {
-    char buf[PATH_MAX + 200];
-    FILE* f;
-
-    f = fopen(fn, "r");
-    if (f == NULL) {
-        fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno));
-        return -1;
-    }
-
-    while (fgets(buf, sizeof(buf), f)) {
-        Path* p;
-        char* token;
-        char* line = buf;
-        bool rootdir;
-
-        while (canned_used >= canned_alloc) {
-            canned_alloc = (canned_alloc+1) * 2;
-            canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
+    std::ifstream input(fn);
+    for (std::string line; std::getline(input, line);) {
+        // Historical: the root dir can be represented as a space character.
+        // e.g. " 1000 1000 0755" is parsed as
+        // path = " ", uid = 1000, gid = 1000, mode = 0755.
+        // But at the same time, we also have accepted
+        // "/ 1000 1000 0755".
+        if (StartsWith(line, " ")) {
+            line.insert(line.begin(), '/');
         }
-        p = canned_data + canned_used;
-        if (line[0] == '/') line++;
-        rootdir = line[0] == ' ';
-        p->path = strdup(rootdir ? "" : strtok(line, " "));
-        p->uid = atoi(strtok(rootdir ? line : NULL, " "));
-        p->gid = atoi(strtok(NULL, " "));
-        p->mode = strtol(strtok(NULL, " "), NULL, 8);   // mode is in octal
-        p->capabilities = 0;
 
-        do {
-            token = strtok(NULL, " ");
-            if (token && strncmp(token, "capabilities=", 13) == 0) {
-                p->capabilities = strtoll(token+13, NULL, 0);
+        std::vector<std::string> tokens = Tokenize(line, " ");
+        if (tokens.size() < 4) {
+            std::cerr << "Ill-formed line: " << line << " in " << fn << std::endl;
+            return -1;
+        }
+
+        // Historical: remove the leading '/' if exists.
+        std::string path(tokens[0].front() == '/' ? std::string(tokens[0], 1) : tokens[0]);
+
+        Entry e{
+                .path = std::move(path),
+                .uid = static_cast<unsigned int>(atoi(tokens[1].c_str())),
+                .gid = static_cast<unsigned int>(atoi(tokens[2].c_str())),
+                // mode is in octal
+                .mode = static_cast<unsigned int>(strtol(tokens[3].c_str(), nullptr, 8)),
+                .capabilities = 0,
+        };
+
+        for (size_t i = 4; i < tokens.size(); i++) {
+            std::string_view sv = tokens[i];
+            if (ConsumePrefix(&sv, "capabilities=")) {
+                e.capabilities = strtoll(std::string(sv).c_str(), nullptr, 0);
                 break;
             }
-        } while (token);
+            // Historical: there can be tokens like "selabel=..." here. They have been ignored.
+            // It's not an error because selabels are applied separately in e2fsdroid using the
+            // file_contexts files set via -S option.
+            std::cerr << "info: ignored token \"" << sv << "\" in " << fn << std::endl;
+        }
 
-        canned_used++;
+        canned_data.emplace_back(std::move(e));
     }
 
-    fclose(f);
+    // Note: we used to sort the entries by path names. This was to improve the lookup performance
+    // by doing binary search. However, this is no longer the case. The lookup performance is not
+    // critical because this tool runs on the host, not on the device. Now, there can be multiple
+    // entries for the same path. Then the one that comes the last wins. This is to allow overriding
+    // platform provided fs_config with a user provided fs_config by appending the latter to the
+    // former.
+    //
+    // To implement the strategy, reverse the entries order, and search from the top.
+    std::reverse(canned_data.begin(), canned_data.end());
 
-    qsort(canned_data, canned_used, sizeof(Path), path_compare);
-    printf("loaded %d fs_config entries\n", canned_used);
-
+    std::cout << "loaded " << canned_data.size() << " fs_config entries" << std::endl;
     return 0;
 }
 
-static const int kDebugCannedFsConfig = 0;
+void canned_fs_config(const char* path, [[maybe_unused]] int dir,
+                      [[maybe_unused]] const char* target_out_path, unsigned* uid, unsigned* gid,
+                      unsigned* mode, uint64_t* capabilities) {
+    if (path != nullptr && path[0] == '/') path++;  // canned paths lack the leading '/'
 
-void canned_fs_config(const char* path, int dir, const char* target_out_path,
-                      unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) {
-    Path key, *p;
+    const Entry* found = nullptr;
+    // canned_data is already reversed. First match wins.
+    for (const auto& entry : canned_data) {
+        if (path == entry.path) {
+            found = &entry;
+            break;
+        }
+        continue;
+    }
 
-    key.path = path;
-    if (path[0] == '/') key.path++; // canned paths lack the leading '/'
-    p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare);
-    if (p == NULL) {
-        fprintf(stderr, "failed to find [%s] in canned fs_config\n", path);
+    if (found == nullptr) {
+        std::cerr << "failed to find " << path << " in canned fs_config" << std::endl;
         exit(1);
     }
-    *uid = p->uid;
-    *gid = p->gid;
-    *mode = p->mode;
-    *capabilities = p->capabilities;
 
-    if (kDebugCannedFsConfig) {
-        // for debugging, run the built-in fs_config and compare the results.
-
-        unsigned c_uid, c_gid, c_mode;
-        uint64_t c_capabilities;
-
-        fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities);
-
-        if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid);
-        if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid);
-        if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode);
-        if (c_capabilities != *capabilities) {
-            printf("%s capabilities %" PRIx64 " %" PRIx64 "\n",
-                path,
-                *capabilities,
-                c_capabilities);
-        }
-    }
+    *uid = found->uid;
+    *gid = found->gid;
+    *mode = found->mode;
+    *capabilities = found->capabilities;
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 376a678..4515950 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -590,9 +590,23 @@
     # Load trusted keys from dm-verity protected partitions
     exec -- /system/bin/fsverity_init --load-verified-keys
 
+# Only enable the bootreceiver tracing instance for kernels 5.10 and above.
+on late-fs && property:ro.kernel.version=4.9
+    setprop bootreceiver.enable 0
+on late-fs && property:ro.kernel.version=4.14
+    setprop bootreceiver.enable 0
+on late-fs && property:ro.kernel.version=4.19
+    setprop bootreceiver.enable 0
+on late-fs && property:ro.kernel.version=5.4
+    setprop bootreceiver.enable 0
+on late-fs
+    # Bootreceiver tracing instance is enabled by default.
+    setprop bootreceiver.enable ${bootreceiver.enable:-1}
+
+on property:ro.product.cpu.abilist64=* && property:bootreceiver.enable=1
     # Set up a tracing instance for system_server to monitor error_report_end events.
     # These are sent by kernel tools like KASAN and KFENCE when a memory corruption
-    # is detected.
+    # is detected. This is only needed for 64-bit systems.
     mkdir /sys/kernel/tracing/instances/bootreceiver 0700 system system
     restorecon_recursive /sys/kernel/tracing/instances/bootreceiver
     write /sys/kernel/tracing/instances/bootreceiver/buffer_size_kb 1