[automerged blank] bpf_helpers - hardcode declaration of bpf_ktime_get_boot_ns() 2p: 8c794ee2e5

Blank merge reason: Change-Id I87f344c779d89cebe9a0d09dc466966ca7fda1a6 with SHA-1 6b28299441 is in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/system/bpf/+/13674371

Change-Id: I65c5958ba9f8577f8988606f09c77c106fa0bf93
diff --git a/Android.bp b/Android.bp
index a1d6d9a..c8c1681 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,20 @@
+package {
+    default_applicable_licenses: ["system_bpf_license"],
+}
+
+// Added automatically by a large-scale-change
+// http://go/android-license-faq
+license {
+    name: "system_bpf_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_defaults {
     name: "bpf_defaults",
     cflags: [
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/bpfloader/Android.bp b/bpfloader/Android.bp
index 0b4bbd4..7a6a4c4 100644
--- a/bpfloader/Android.bp
+++ b/bpfloader/Android.bp
@@ -17,6 +17,14 @@
 //
 // bpfLoad binary
 //
+package {
+    // http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // the below license kinds from "system_bpf_license":
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_bpf_license"],
+}
+
 cc_binary {
     name: "bpfloader",
 
diff --git a/bpfloader/BpfLoader.cpp b/bpfloader/BpfLoader.cpp
index e67c469..7a68894 100644
--- a/bpfloader/BpfLoader.cpp
+++ b/bpfloader/BpfLoader.cpp
@@ -51,22 +51,37 @@
 using android::base::EndsWith;
 using std::string;
 
-#define BPF_PROG_PATH "/system/etc/bpf/"
+struct {
+    const char* const dir;
+    const char* const prefix;
+} locations[] = {
+        // Tethering mainline module
+        {
+                .dir = "/apex/com.android.tethering/etc/bpf/",
+                .prefix = "tethering/",
+        },
+        // Core operating system
+        {
+                .dir = "/system/etc/bpf/",
+                .prefix = "",
+        },
+};
 
-int loadAllElfObjects(void) {
+int loadAllElfObjects(const char* const progDir, const char* const prefix) {
     int retVal = 0;
     DIR* dir;
     struct dirent* ent;
 
-    if ((dir = opendir(BPF_PROG_PATH)) != NULL) {
+    if ((dir = opendir(progDir)) != NULL) {
         while ((ent = readdir(dir)) != NULL) {
             string s = ent->d_name;
             if (!EndsWith(s, ".o")) continue;
 
-            string progPath = BPF_PROG_PATH + s;
+            string progPath(progDir);
+            progPath += s;
 
             bool critical;
-            int ret = android::bpf::loadProg(progPath.c_str(), &critical);
+            int ret = android::bpf::loadProg(progPath.c_str(), &critical, prefix);
             if (ret) {
                 if (critical) retVal = ret;
                 ALOGE("Failed to load object: %s, ret: %s", progPath.c_str(), std::strerror(-ret));
@@ -79,17 +94,36 @@
     return retVal;
 }
 
-int main() {
-    if (!android::bpf::isBpfSupported()) return 0;
+void createSysFsBpfSubDir(const char* const prefix) {
+    if (*prefix) {
+        mode_t prevUmask = umask(0);
 
+        string s = "/sys/fs/bpf/";
+        s += prefix;
+
+        errno = 0;
+        int ret = mkdir(s.c_str(), S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
+        if (ret && errno != EEXIST) {
+            ALOGW("Failed to create directory: %s, ret: %s", s.c_str(), std::strerror(errno));
+        }
+
+        umask(prevUmask);
+    }
+}
+
+int main() {
     // Load all ELF objects, create programs and maps, and pin them
-    if (loadAllElfObjects() != 0) {
-        ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS ===");
-        ALOGE("If this triggers reliably, you're probably missing kernel options or patches.");
-        ALOGE("If this triggers randomly, you might be hitting some memory allocation problems or "
-              "startup script race.");
-        ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---");
-        return 2;
+    for (const auto location : locations) {
+        createSysFsBpfSubDir(location.prefix);
+        if (loadAllElfObjects(location.dir, location.prefix) != 0) {
+            ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", location.dir);
+            ALOGE("If this triggers reliably, you're probably missing kernel options or patches.");
+            ALOGE("If this triggers randomly, you might be hitting some memory allocation "
+                  "problems or startup script race.");
+            ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---");
+            sleep(20);
+            return 2;
+        }
     }
 
     if (android::base::SetProperty("bpf.progs_loaded", "1") == false) {
diff --git a/bpfloader/bpfloader.rc b/bpfloader/bpfloader.rc
index 04d9b81..9a9482c 100644
--- a/bpfloader/bpfloader.rc
+++ b/bpfloader/bpfloader.rc
@@ -7,9 +7,6 @@
 #   - /sys/fs/bpf is already mounted,
 #   - apex (incl. rollback) is initialized (so that in the future we can load bpf
 #     programs shipped as part of apex mainline modules)
-#   - system properties have been set, this is because isBpfSupported() calls
-#     getUncachedBpfSupportLevel() which depends on
-#     ro.kernel.ebpf.supported, ro.product.first_api_level & ro.build.version.sdk
 #   - logd is ready for us to log stuff
 #
 # At the same time we want to be as early as possible to reduce races and thus
@@ -23,7 +20,7 @@
     write /proc/sys/net/core/bpf_jit_enable 1
     # Enable JIT kallsyms export for privileged users only
     write /proc/sys/net/core/bpf_jit_kallsyms 1
-    start bpfloader
+    exec_start bpfloader
 
 service bpfloader /system/bin/bpfloader
     capabilities CHOWN SYS_ADMIN
diff --git a/libbpf_android/Android.bp b/libbpf_android/Android.bp
index cd2342e..06528c8 100644
--- a/libbpf_android/Android.bp
+++ b/libbpf_android/Android.bp
@@ -14,22 +14,35 @@
 // limitations under the License.
 //
 
+package {
+    // http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // the below license kinds from "system_bpf_license":
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_bpf_license"],
+}
+
 cc_library_headers {
     name: "libbpf_android_headers",
     vendor_available: false,
     host_supported: false,
+    native_bridge_supported: true,
     export_include_dirs: ["include"],
     target: {
         linux_bionic: {
             enabled: true,
         },
     },
+    sdk_version: "30",
+    header_libs: ["bpf_syscall_wrappers"],
+    export_header_lib_headers: ["bpf_syscall_wrappers"],
 }
 
 cc_library {
     name: "libbpf_android",
     vendor_available: false,
     host_supported: false,
+    native_bridge_supported: true,
     target: {
         android: {
             srcs: [
diff --git a/libbpf_android/BpfLoadTest.cpp b/libbpf_android/BpfLoadTest.cpp
index b384c11..09cd36c 100644
--- a/libbpf_android/BpfLoadTest.cpp
+++ b/libbpf_android/BpfLoadTest.cpp
@@ -38,8 +38,6 @@
     int mProgFd;
 
     void SetUp() {
-        SKIP_IF_BPF_NOT_SUPPORTED;
-
         unlink(tp_prog_path);
         unlink(tp_map_path);
 
@@ -55,8 +53,6 @@
     }
 
     void TearDown() {
-        SKIP_IF_BPF_NOT_SUPPORTED;
-
         close(mProgFd);
         unlink(tp_prog_path);
         unlink(tp_map_path);
@@ -88,8 +84,6 @@
 };
 
 TEST_F(BpfLoadTest, bpfCheckMap) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
     checkMapNonZero();
 }
 
diff --git a/libbpf_android/BpfMapTest.cpp b/libbpf_android/BpfMapTest.cpp
index 91b9bf3..d0737b0 100644
--- a/libbpf_android/BpfMapTest.cpp
+++ b/libbpf_android/BpfMapTest.cpp
@@ -54,8 +54,6 @@
     BpfMapTest() {}
 
     void SetUp() {
-        SKIP_IF_BPF_NOT_SUPPORTED;
-
         EXPECT_EQ(0, setrlimitForTest());
         if (!access(PINNED_MAP_PATH, R_OK)) {
             EXPECT_EQ(0, remove(PINNED_MAP_PATH));
@@ -63,8 +61,6 @@
     }
 
     void TearDown() {
-        SKIP_IF_BPF_NOT_SUPPORTED;
-
         if (!access(PINNED_MAP_PATH, R_OK)) {
             EXPECT_EQ(0, remove(PINNED_MAP_PATH));
         }
@@ -107,8 +103,6 @@
 };
 
 TEST_F(BpfMapTest, constructor) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
     BpfMap<uint32_t, uint32_t> testMap1;
     checkMapInvalid(testMap1);
 
@@ -117,8 +111,6 @@
 }
 
 TEST_F(BpfMapTest, basicHelpers) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
     BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
     uint32_t key = TEST_KEY1;
     uint32_t value_write = TEST_VALUE1;
@@ -133,8 +125,6 @@
 }
 
 TEST_F(BpfMapTest, reset) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
     BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
     uint32_t key = TEST_KEY1;
     uint32_t value_write = TEST_VALUE1;
@@ -147,8 +137,6 @@
 }
 
 TEST_F(BpfMapTest, moveConstructor) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
     BpfMap<uint32_t, uint32_t> testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
     BpfMap<uint32_t, uint32_t> testMap2;
     testMap2 = std::move(testMap1);
@@ -159,8 +147,6 @@
 }
 
 TEST_F(BpfMapTest, SetUpMap) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
     EXPECT_NE(0, access(PINNED_MAP_PATH, R_OK));
     BpfMap<uint32_t, uint32_t> testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
     ASSERT_EQ(0, bpfFdPin(testMap1.getMap(), PINNED_MAP_PATH));
@@ -177,8 +163,6 @@
 }
 
 TEST_F(BpfMapTest, iterate) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
     BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
     populateMap(TEST_MAP_SIZE, testMap);
     int totalCount = 0;
@@ -197,8 +181,6 @@
 }
 
 TEST_F(BpfMapTest, iterateWithValue) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
     BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
     populateMap(TEST_MAP_SIZE, testMap);
     int totalCount = 0;
@@ -219,8 +201,6 @@
 }
 
 TEST_F(BpfMapTest, mapIsEmpty) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
     BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
     expectMapEmpty(testMap);
     uint32_t key = TEST_KEY1;
@@ -251,8 +231,6 @@
 }
 
 TEST_F(BpfMapTest, mapClear) {
-    SKIP_IF_BPF_NOT_SUPPORTED;
-
     BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
     populateMap(TEST_MAP_SIZE, testMap);
     Result<bool> isEmpty = testMap.isEmpty();
diff --git a/libbpf_android/BpfUtils.cpp b/libbpf_android/BpfUtils.cpp
index 3b6c764..8689192 100644
--- a/libbpf_android/BpfUtils.cpp
+++ b/libbpf_android/BpfUtils.cpp
@@ -34,7 +34,6 @@
 #include <sstream>
 #include <string>
 
-#include <android-base/properties.h>
 #include <android-base/unique_fd.h>
 #include <log/log.h>
 #include <processgroup/processgroup.h>
@@ -95,8 +94,6 @@
     return res;
 }
 
-#define KVER(a, b, c) ((a)*65536 + (b)*256 + (c))
-
 unsigned kernelVersion() {
     struct utsname buf;
     int ret = uname(&buf);
@@ -113,52 +110,5 @@
     return KVER(kver_major, kver_minor, kver_sub);
 }
 
-std::string BpfLevelToString(BpfLevel bpfLevel) {
-    switch (bpfLevel) {
-        case BpfLevel::NONE:
-            return "None [pre-4.9 or pre-P]";
-        case BpfLevel::BASIC_4_9:
-            return "Basic [4.9 P+]";
-        case BpfLevel::EXTENDED_4_14:
-            return "Extended [4.14]";
-        case BpfLevel::EXTENDED_4_19:
-            return "Extended [4.19]";
-        case BpfLevel::EXTENDED_5_4:
-            return "Extended [5.4+]";
-            // No default statement. We want to see errors of the form:
-            // "enumeration value 'BPF_LEVEL_xxx' not handled in switch [-Werror,-Wswitch]".
-    }
-}
-
-static BpfLevel getUncachedBpfSupportLevel() {
-    unsigned kver = kernelVersion();
-
-    if (kver >= KVER(5, 4, 0)) return BpfLevel::EXTENDED_5_4;
-    if (kver >= KVER(4, 19, 0)) return BpfLevel::EXTENDED_4_19;
-    if (kver >= KVER(4, 14, 0)) return BpfLevel::EXTENDED_4_14;
-
-    // Override for devices launched with O but now on a 4.9-P+ kernel.
-    bool ebpf_supported = base::GetBoolProperty("ro.kernel.ebpf.supported", false);
-    if (ebpf_supported) return BpfLevel::BASIC_4_9;
-
-    uint64_t api_level = base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
-    if (api_level == 0) {
-        ALOGE("Cannot determine initial API level of the device");
-        api_level = base::GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
-    }
-
-    // Check if the device is shipped originally with android P.
-    if (api_level < MINIMUM_API_REQUIRED) return BpfLevel::NONE;
-
-    if (kver >= KVER(4, 9, 0)) return BpfLevel::BASIC_4_9;
-
-    return BpfLevel::NONE;
-}
-
-BpfLevel getBpfSupportLevel() {
-    static BpfLevel cache = getUncachedBpfSupportLevel();
-    return cache;
-}
-
 }  // namespace bpf
 }  // namespace android
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp
index da6a109..01f8964 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -29,7 +29,6 @@
 #include <unistd.h>
 
 #include "../progs/include/bpf_map_def.h"
-#include "LoaderUtils.h"
 #include "bpf/BpfUtils.h"
 #include "include/libbpf_android.h"
 
@@ -40,7 +39,6 @@
 #include <string>
 #include <vector>
 
-#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 
@@ -60,6 +58,17 @@
 namespace android {
 namespace bpf {
 
+static string pathToFilename(const string& path, bool noext = false) {
+    vector<string> spath = android::base::Split(path, "/");
+    string ret = spath.back();
+
+    if (noext) {
+        size_t lastindex = ret.find_last_of('.');
+        return ret.substr(0, lastindex);
+    }
+    return ret;
+}
+
 typedef struct {
     const char* name;
     enum bpf_prog_type type;
@@ -73,15 +82,16 @@
  * is the name of the program, and tracepoint is the type.
  */
 sectionType sectionNameTypes[] = {
-    {"kprobe", BPF_PROG_TYPE_KPROBE},
-    {"tracepoint", BPF_PROG_TYPE_TRACEPOINT},
-    {"skfilter", BPF_PROG_TYPE_SOCKET_FILTER},
-    {"cgroupskb", BPF_PROG_TYPE_CGROUP_SKB},
-    {"schedcls", BPF_PROG_TYPE_SCHED_CLS},
-    {"cgroupsock", BPF_PROG_TYPE_CGROUP_SOCK},
+        {"kprobe", BPF_PROG_TYPE_KPROBE},
+        {"tracepoint", BPF_PROG_TYPE_TRACEPOINT},
+        {"skfilter", BPF_PROG_TYPE_SOCKET_FILTER},
+        {"cgroupskb", BPF_PROG_TYPE_CGROUP_SKB},
+        {"schedcls", BPF_PROG_TYPE_SCHED_CLS},
+        {"cgroupsock", BPF_PROG_TYPE_CGROUP_SOCK},
+        {"xdp", BPF_PROG_TYPE_XDP},
 
-    /* End of table */
-    {"END", BPF_PROG_TYPE_UNSPEC},
+        /* End of table */
+        {"END", BPF_PROG_TYPE_UNSPEC},
 };
 
 typedef struct {
@@ -125,11 +135,8 @@
 /* Read a section by its index - for ex to get sec hdr strtab blob */
 static int readSectionByIdx(ifstream& elfFile, int id, vector<char>& sec) {
     vector<Elf64_Shdr> shTable;
-    int entries, ret = 0;
-
-    ret = readSectionHeadersAll(elfFile, shTable);
+    int ret = readSectionHeadersAll(elfFile, shTable);
     if (ret) return ret;
-    entries = shTable.size();
 
     elfFile.seekg(shTable[id].sh_offset);
     if (elfFile.fail()) return -1;
@@ -143,9 +150,7 @@
 /* Read whole section header string table */
 static int readSectionHeaderStrtab(ifstream& elfFile, vector<char>& strtab) {
     Elf64_Ehdr eh;
-    int ret = 0;
-
-    ret = readElfHeader(elfFile, &eh);
+    int ret = readElfHeader(elfFile, &eh);
     if (ret) return ret;
 
     ret = readSectionByIdx(elfFile, eh.e_shstrndx, strtab);
@@ -256,7 +261,7 @@
 {
     for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++)
         if (sectionNameTypes[i].type == type)
-            return std::string(sectionNameTypes[i].name);
+            return string(sectionNameTypes[i].name);
 
     return NULL;
 }
@@ -268,7 +273,7 @@
 
         if (st.type != cs.type) continue;
 
-        if (StartsWith(name, std::string(".rel") + st.name + "/"))
+        if (StartsWith(name, string(".rel") + st.name + "/"))
             return true;
         else
             return false;
@@ -313,7 +318,7 @@
 
     /* No section found with matching name*/
     if (sec_idx == -1) {
-        ALOGE("No %s section could be found in elf object\n", sectionName.c_str());
+        ALOGW("No %s section could be found in elf object\n", sectionName.c_str());
         return -1;
     }
 
@@ -356,7 +361,10 @@
         enum bpf_prog_type ptype = getSectionType(name);
         if (ptype != BPF_PROG_TYPE_UNSPEC) {
             string oldName = name;
-            deslash(name);
+
+            // convert all slashes to underscores
+            std::replace(name.begin(), name.end(), '/', '_');
+
             cs_temp.type = ptype;
             cs_temp.name = name;
 
@@ -407,7 +415,8 @@
     return getSymName(elfFile, symtab[index].st_name, name);
 }
 
-static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds) {
+static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds,
+                      const char* prefix) {
     int ret;
     vector<char> mdData;
     vector<struct bpf_map_def> md;
@@ -425,11 +434,11 @@
 
     for (int i = 0; i < (int)mapNames.size(); i++) {
         unique_fd fd;
-        // Format of pin location is /sys/fs/bpf/map_<filename>_<mapname>
+        // Format of pin location is /sys/fs/bpf/<prefix>map_<filename>_<mapname>
         string mapPinLoc;
         bool reuse = false;
 
-        mapPinLoc = string(BPF_FS_PATH) + "map_" + fname + "_" + string(mapNames[i]);
+        mapPinLoc = string(BPF_FS_PATH) + prefix + "map_" + fname + "_" + string(mapNames[i]);
         if (access(mapPinLoc.c_str(), F_OK) == 0) {
             fd.reset(bpf_obj_get(mapPinLoc.c_str()));
             ALOGD("bpf_create_map reusing map %s, ret: %d\n", mapNames[i].c_str(), fd.get());
@@ -531,7 +540,8 @@
     }
 }
 
-static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license) {
+static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license,
+                            const char* prefix) {
     unsigned kvers = kernelVersion();
     int ret, fd;
 
@@ -558,8 +568,10 @@
 
         bool reuse = false;
         // Format of pin location is
-        // /sys/fs/bpf/prog_<filename>_<mapname>
-        string progPinLoc = BPF_FS_PATH "prog_";
+        // /sys/fs/bpf/<prefix>prog_<filename>_<mapname>
+        string progPinLoc = BPF_FS_PATH;
+        progPinLoc += prefix;
+        progPinLoc += "prog_";
         progPinLoc += fname;
         progPinLoc += '_';
         progPinLoc += name;
@@ -578,7 +590,7 @@
                   cs[i].name.c_str(), fd, (fd < 0 ? std::strerror(errno) : "no error"));
 
             if (fd < 0) {
-                std::vector<std::string> lines = android::base::Split(log_buf.data(), "\n");
+                vector<string> lines = android::base::Split(log_buf.data(), "\n");
 
                 ALOGW("bpf_prog_load - BEGIN log_buf contents:");
                 for (const auto& line : lines) ALOGW("%s", line.c_str());
@@ -613,7 +625,7 @@
     return 0;
 }
 
-int loadProg(const char* elfPath, bool* isCritical) {
+int loadProg(const char* elfPath, bool* isCritical, const char* prefix) {
     vector<char> license;
     vector<char> critical;
     vector<codeSection> cs;
@@ -648,7 +660,7 @@
     /* Just for future debugging */
     if (0) dumpAllCs(cs);
 
-    ret = createMaps(elfPath, elfFile, mapFds);
+    ret = createMaps(elfPath, elfFile, mapFds, prefix);
     if (ret) {
         ALOGE("Failed to create maps: (ret=%d) in %s\n", ret, elfPath);
         return ret;
@@ -659,28 +671,11 @@
 
     applyMapRelo(elfFile, mapFds, cs);
 
-    ret = loadCodeSections(elfPath, cs, string(license.data()));
+    ret = loadCodeSections(elfPath, cs, string(license.data()), prefix);
     if (ret) ALOGE("Failed to load programs, loadCodeSections ret=%d\n", ret);
 
     return ret;
 }
 
-static bool waitSecondsForProgsLoaded(int seconds) {
-    bool ok =
-            android::base::WaitForProperty("bpf.progs_loaded", "1", std::chrono::seconds(seconds));
-    if (!ok) ALOGW("Waited %ds for bpf.progs_loaded, still waiting...", seconds);
-    return ok;
-}
-
-void waitForProgsLoaded() {
-    if (!android::bpf::isBpfSupported()) return;
-
-    if (waitSecondsForProgsLoaded(5)) return;
-    if (waitSecondsForProgsLoaded(10)) return;
-    if (waitSecondsForProgsLoaded(20)) return;
-    while (!waitSecondsForProgsLoaded(60))
-        ;  // loop until success
-}
-
 }  // namespace bpf
 }  // namespace android
diff --git a/libbpf_android/LoaderUtils.h b/libbpf_android/LoaderUtils.h
deleted file mode 100644
index a5ff7fc..0000000
--- a/libbpf_android/LoaderUtils.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include <android-base/strings.h>
-
-static std::string pathToFilename(const std::string& path, bool noext = false) {
-    std::vector<std::string> spath = android::base::Split(path, "/");
-    std::string ret = spath.back();
-
-    if (noext) {
-        size_t lastindex = ret.find_last_of('.');
-        return ret.substr(0, lastindex);
-    }
-    return ret;
-}
-
-static void deslash(std::string& s) {
-    std::replace(s.begin(), s.end(), '/', '_');
-}
diff --git a/libbpf_android/include/bpf/BpfMap.h b/libbpf_android/include/bpf/BpfMap.h
index 3e7413e..bdffc0f 100644
--- a/libbpf_android/include/bpf/BpfMap.h
+++ b/libbpf_android/include/bpf/BpfMap.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef BPF_BPFMAP_H
-#define BPF_BPFMAP_H
+#pragma once
 
 #include <linux/bpf.h>
 
@@ -134,10 +133,11 @@
         return *this;
     }
 
-    // Move constructor
-    void operator=(BpfMap<Key, Value>&& other) noexcept {
+    // Move assignment operator
+    BpfMap<Key, Value>& operator=(BpfMap<Key, Value>&& other) noexcept {
         mMapFd = std::move(other.mMapFd);
         other.reset(-1);
+        return *this;
     }
 
     void reset(base::unique_fd fd) = delete;
@@ -258,5 +258,3 @@
 
 }  // namespace bpf
 }  // namespace android
-
-#endif
diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h
index 6814f94..9671b8a 100644
--- a/libbpf_android/include/bpf/BpfUtils.h
+++ b/libbpf_android/include/bpf/BpfUtils.h
@@ -14,12 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef BPF_BPFUTILS_H
-#define BPF_BPFUTILS_H
+#pragma once
 
-#include <linux/bpf.h>
 #include <linux/if_ether.h>
-#include <linux/unistd.h>
 #include <net/if.h>
 #include <stdlib.h>
 #include <string.h>
@@ -27,174 +24,44 @@
 
 #include <string>
 
-#include "android-base/unique_fd.h"
-
-#define ptr_to_u64(x) ((uint64_t)(uintptr_t)(x))
+#include "BpfSyscallWrappers.h"
 
 namespace android {
 namespace bpf {
 
-enum class BpfLevel {
-    // Devices shipped before P or kernel version is lower than 4.9 do not
-    // have eBPF enabled.
-    NONE,
-    // Devices shipped in P with android 4.9 kernel only have the basic eBPF
-    // functionalities such as xt_bpf and cgroup skb filter.
-    BASIC_4_9,
-    // For devices that have 4.14 kernel. It supports advanced features like
-    // map_in_map and cgroup socket filter.
-    EXTENDED_4_14,
-    EXTENDED_4_19,
-    EXTENDED_5_4,
-};
-
 constexpr const int OVERFLOW_COUNTERSET = 2;
 
 constexpr const uint64_t NONEXISTENT_COOKIE = 0;
 
-constexpr const int MINIMUM_API_REQUIRED = 28;
-
-/* Note: bpf_attr is a union which might have a much larger size then the anonymous struct portion
- * of it that we are using.  The kernel's bpf() system call will perform a strict check to ensure
- * all unused portions are zero.  It will fail with E2BIG if we don't fully zero bpf_attr.
- */
-
-inline int bpf(int cmd, const bpf_attr& attr) {
-    return syscall(__NR_bpf, cmd, &attr, sizeof(attr));
-}
-
-inline int createMap(bpf_map_type map_type, uint32_t key_size, uint32_t value_size,
-                     uint32_t max_entries, uint32_t map_flags) {
-    return bpf(BPF_MAP_CREATE, {
-                                       .map_type = map_type,
-                                       .key_size = key_size,
-                                       .value_size = value_size,
-                                       .max_entries = max_entries,
-                                       .map_flags = map_flags,
-                               });
-}
-
-inline int writeToMapEntry(const base::unique_fd& map_fd, const void* key, const void* value,
-                           uint64_t flags) {
-    return bpf(BPF_MAP_UPDATE_ELEM, {
-                                            .map_fd = static_cast<__u32>(map_fd.get()),
-                                            .key = ptr_to_u64(key),
-                                            .value = ptr_to_u64(value),
-                                            .flags = flags,
-                                    });
-}
-
-inline int findMapEntry(const base::unique_fd& map_fd, const void* key, void* value) {
-    return bpf(BPF_MAP_LOOKUP_ELEM, {
-                                            .map_fd = static_cast<__u32>(map_fd.get()),
-                                            .key = ptr_to_u64(key),
-                                            .value = ptr_to_u64(value),
-                                    });
-}
-
-inline int deleteMapEntry(const base::unique_fd& map_fd, const void* key) {
-    return bpf(BPF_MAP_DELETE_ELEM, {
-                                            .map_fd = static_cast<__u32>(map_fd.get()),
-                                            .key = ptr_to_u64(key),
-                                    });
-}
-
-inline int getNextMapKey(const base::unique_fd& map_fd, const void* key, void* next_key) {
-    return bpf(BPF_MAP_GET_NEXT_KEY, {
-                                             .map_fd = static_cast<__u32>(map_fd.get()),
-                                             .key = ptr_to_u64(key),
-                                             .next_key = ptr_to_u64(next_key),
-                                     });
-}
-
-inline int getFirstMapKey(const base::unique_fd& map_fd, void* firstKey) {
-    return getNextMapKey(map_fd, NULL, firstKey);
-}
-
-inline int bpfFdPin(const base::unique_fd& map_fd, const char* pathname) {
-    return bpf(BPF_OBJ_PIN, {
-                                    .pathname = ptr_to_u64(pathname),
-                                    .bpf_fd = static_cast<__u32>(map_fd.get()),
-                            });
-}
-
-inline int bpfFdGet(const char* pathname, uint32_t flag) {
-    return bpf(BPF_OBJ_GET, {
-                                    .pathname = ptr_to_u64(pathname),
-                                    .file_flags = flag,
-                            });
-}
-
-inline int mapRetrieve(const char* pathname, uint32_t flag) {
-    return bpfFdGet(pathname, flag);
-}
-
-inline int mapRetrieveRW(const char* pathname) {
-    return mapRetrieve(pathname, 0);
-}
-
-inline int mapRetrieveRO(const char* pathname) {
-    return mapRetrieve(pathname, BPF_F_RDONLY);
-}
-
-inline int mapRetrieveWO(const char* pathname) {
-    return mapRetrieve(pathname, BPF_F_WRONLY);
-}
-
-inline int retrieveProgram(const char* pathname) {
-    return bpfFdGet(pathname, BPF_F_RDONLY);
-}
-
-inline int attachProgram(bpf_attach_type type, const base::unique_fd& prog_fd,
-                         const base::unique_fd& cg_fd) {
-    return bpf(BPF_PROG_ATTACH, {
-                                        .target_fd = static_cast<__u32>(cg_fd.get()),
-                                        .attach_bpf_fd = static_cast<__u32>(prog_fd.get()),
-                                        .attach_type = type,
-                                });
-}
-
-inline int detachProgram(bpf_attach_type type, const base::unique_fd& cg_fd) {
-    return bpf(BPF_PROG_DETACH, {
-                                        .target_fd = static_cast<__u32>(cg_fd.get()),
-                                        .attach_type = type,
-                                });
-}
-
 uint64_t getSocketCookie(int sockFd);
 int synchronizeKernelRCU();
 int setrlimitForTest();
-unsigned kernelVersion();
-std::string BpfLevelToString(BpfLevel BpfLevel);
-BpfLevel getBpfSupportLevel();
 
-inline bool isBpfSupported() {
-    return getBpfSupportLevel() != BpfLevel::NONE;
+#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
+
+unsigned kernelVersion();
+
+static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) {
+    return kernelVersion() >= KVER(major, minor, sub);
 }
 
-#define SKIP_IF_BPF_NOT_SUPPORTED                                                    \
-    do {                                                                             \
-        if (!android::bpf::isBpfSupported()) {                                       \
-            GTEST_LOG_(INFO) << "This test is skipped since bpf is not available\n"; \
-            return;                                                                  \
-        }                                                                            \
+#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED                                        \
+    do {                                                                          \
+        if (!android::bpf::isAtLeastKernelVersion(4, 14, 0)) {                    \
+            GTEST_LOG_(INFO) << "This test is skipped since extended bpf feature" \
+                             << "not supported\n";                                \
+            return;                                                               \
+        }                                                                         \
     } while (0)
 
-#define SKIP_IF_BPF_SUPPORTED                       \
-    do {                                            \
-        if (android::bpf::isBpfSupported()) return; \
-    } while (0)
-
-#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED                                                \
-    do {                                                                                  \
-        if (android::bpf::getBpfSupportLevel() < android::bpf::BpfLevel::EXTENDED_4_14) { \
-            GTEST_LOG_(INFO) << "This test is skipped since extended bpf feature"         \
-                             << "not supported\n";                                        \
-            return;                                                                       \
-        }                                                                                 \
+#define SKIP_IF_XDP_NOT_SUPPORTED                                \
+    do {                                                         \
+        if (!android::bpf::isAtLeastKernelVersion(5, 9, 0)) {    \
+            GTEST_LOG_(INFO) << "This test is skipped since xdp" \
+                             << "not supported\n";               \
+            return;                                              \
+        }                                                        \
     } while (0)
 
 }  // namespace bpf
 }  // namespace android
-
-#endif
diff --git a/libbpf_android/include/libbpf_android.h b/libbpf_android/include/libbpf_android.h
index 3810d07..90c9906 100644
--- a/libbpf_android/include/libbpf_android.h
+++ b/libbpf_android/include/libbpf_android.h
@@ -15,22 +15,30 @@
  * limitations under the License.
  */
 
-#ifndef LIBBPF_SYSTEM_H
-#define LIBBPF_SYSTEM_H
+#pragma once
 
 #include <libbpf.h>
 #include <linux/bpf.h>
+#include <log/log.h>
+
+#include <android-base/properties.h>
 
 namespace android {
 namespace bpf {
 
 // BPF loader implementation. Loads an eBPF ELF object
-int loadProg(const char* elfPath, bool* isCritical);
+int loadProg(const char* elfPath, bool* isCritical, const char* prefix = "");
 
 // Wait for bpfloader to load BPF programs.
-void waitForProgsLoaded();
+static inline void waitForProgsLoaded() {
+    // infinite loop until success with 5/10/20/40/60/60/60... delay
+    for (int delay = 5;; delay *= 2) {
+        if (delay > 60) delay = 60;
+        if (android::base::WaitForProperty("bpf.progs_loaded", "1", std::chrono::seconds(delay)))
+            return;
+        ALOGW("Waited %ds for bpf.progs_loaded, still waiting...", delay);
+    }
+}
 
 }  // namespace bpf
 }  // namespace android
-
-#endif
diff --git a/progs/Android.bp b/progs/Android.bp
index 37feafd..aeb04a7 100644
--- a/progs/Android.bp
+++ b/progs/Android.bp
@@ -14,6 +14,14 @@
 // limitations under the License.
 //
 
+package {
+    // http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // the below license kinds from "system_bpf_license":
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_bpf_license"],
+}
+
 cc_library_headers {
     name: "bpf_prog_headers",
     export_include_dirs: ["include"],
diff --git a/progs/include/bpf_helpers.h b/progs/include/bpf_helpers.h
index f09ec83..075ea94 100644
--- a/progs/include/bpf_helpers.h
+++ b/progs/include/bpf_helpers.h
@@ -47,18 +47,18 @@
  * This will make sure that if you change the type of a map you'll get compile
  * errors at any spots you forget to update with the new type.
  *
- * Note: these all take 'const void* map' because from the C/eBPF point of view
+ * Note: these all take pointers to const map because from the C/eBPF point of view
  * the map struct is really just a readonly map definition of the in kernel object.
  * Runtime modification of the map defining struct is meaningless, since
  * the contents is only ever used during bpf program loading & map creation
  * by the bpf loader, and not by the eBPF program itself.
  */
-static void* (*bpf_map_lookup_elem_unsafe)(const void* map,
+static void* (*bpf_map_lookup_elem_unsafe)(const struct bpf_map_def* map,
                                            const void* key) = (void*)BPF_FUNC_map_lookup_elem;
-static int (*bpf_map_update_elem_unsafe)(const void* map, const void* key, const void* value,
-                                         unsigned long long flags) = (void*)
+static int (*bpf_map_update_elem_unsafe)(const struct bpf_map_def* map, const void* key,
+                                         const void* value, unsigned long long flags) = (void*)
         BPF_FUNC_map_update_elem;
-static int (*bpf_map_delete_elem_unsafe)(const void* map,
+static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map,
                                          const void* key) = (void*)BPF_FUNC_map_delete_elem;
 
 /* type safe macro to declare a map and related accessor functions */
@@ -102,15 +102,14 @@
 static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read;
 static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str;
 static unsigned long long (*bpf_ktime_get_ns)(void) = (void*) BPF_FUNC_ktime_get_ns;
-// TODO: change to BPF_FUNC_ktime_get_boot_ns in sc-mainline-prod.
-static unsigned long long (*bpf_ktime_get_boot_ns)(void) = (void*)125;
+static unsigned long long (*bpf_ktime_get_boot_ns)(void) = (void*)BPF_FUNC_ktime_get_boot_ns;
 static int (*bpf_trace_printk)(const char* fmt, int fmt_size, ...) = (void*) BPF_FUNC_trace_printk;
 static unsigned long long (*bpf_get_current_pid_tgid)(void) = (void*) BPF_FUNC_get_current_pid_tgid;
 static unsigned long long (*bpf_get_current_uid_gid)(void) = (void*) BPF_FUNC_get_current_uid_gid;
 static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_get_smp_processor_id;
 
 #define KVER_NONE 0
-#define KVER(a, b, c) ((a)*65536 + (b)*256 + (c))
+#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
 #define KVER_INF 0xFFFFFFFF
 
 #define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
diff --git a/progs/include/bpf_map_def.h b/progs/include/bpf_map_def.h
index 452b682..8523c36 100644
--- a/progs/include/bpf_map_def.h
+++ b/progs/include/bpf_map_def.h
@@ -23,7 +23,6 @@
 #include <linux/bpf.h>
 
 // Pull in AID_* constants from //system/core/libcutils/include/private/android_filesystem_config.h
-#define EXCLUDE_FS_CONFIG_STRUCTURES
 #include <private/android_filesystem_config.h>
 
 /*
diff --git a/progs/include/bpf_timeinstate.h b/progs/include/bpf_timeinstate.h
index 6cbc4e1..1065b6e 100644
--- a/progs/include/bpf_timeinstate.h
+++ b/progs/include/bpf_timeinstate.h
@@ -15,9 +15,14 @@
  */
 
 #include <inttypes.h>
+#include <sys/types.h>
 
 #define BPF_FS_PATH "/sys/fs/bpf/"
 
+// Number of frequencies tracked in the array with total time. If some CPUs have
+// more than 64 freqs
+// // available, the overflow is stored in the last entry.
+#define MAX_FREQS_FOR_TOTAL 64
 // Number of frequencies for which a UID's times can be tracked in a single map entry. If some CPUs
 // have more than 32 freqs available, a single UID is tracked using 2 or more entries.
 #define FREQS_PER_ENTRY 32
@@ -43,3 +48,27 @@
     uint32_t policy;
     uint32_t freq;
 } freq_idx_key_t;
+
+// Maximum number of processes whose thread CPU time-in-state can be tracked simultaneously.
+#define MAX_TRACKED_PIDS 8
+
+// Indicates that the pid_tracked_map item is unused and further items in the array are also
+// unused
+#define TRACKED_PID_STATE_UNUSED 0
+// Indicates that the pid_tracked_map item contains a PID that is currently tracked
+#define TRACKED_PID_STATE_ACTIVE 1
+// Indicates that the pid_tracked_map item is vacant, but further items in the array may
+// contain tracked PIDs
+#define TRACKED_PID_STATE_EXITED 2
+
+typedef struct {
+    pid_t pid;
+    // TRACKED_PID_STATE_UNUSED, TRACKED_PID_STATE_ACTIVE or TRACKED_PID_STATE_EXITED
+    uint8_t state;
+} tracked_pid_t;
+
+typedef struct {
+    pid_t tgid;
+    uint16_t aggregation_key;
+    uint16_t bucket;
+} aggregated_task_tis_key_t;