Mark ab/7061308 as merged in stage.

Bug: 180401296
Merged-In: I29e012cafcbadea5f0ce8f5b0348581afdd78339
Change-Id: Ie4bdf948f4c3a6e3758fdaf5a39091573b316fac
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/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 33208d1..7a68894 100644
--- a/bpfloader/BpfLoader.cpp
+++ b/bpfloader/BpfLoader.cpp
@@ -51,10 +51,23 @@
 using android::base::EndsWith;
 using std::string;
 
-#define BPF_PROG_PATH_MAINLINE_TETHERING "/apex/com.android.tethering/etc/bpf/"
-#define BPF_PROG_PATH_SYSTEM "/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(const char* progDir) {
+int loadAllElfObjects(const char* const progDir, const char* const prefix) {
     int retVal = 0;
     DIR* dir;
     struct dirent* ent;
@@ -68,7 +81,7 @@
             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));
@@ -81,13 +94,29 @@
     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
-    for (const auto dir : {BPF_PROG_PATH_MAINLINE_TETHERING, BPF_PROG_PATH_SYSTEM}) {
-        if (loadAllElfObjects(dir) != 0) {
-            ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", dir);
+    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.");
diff --git a/bpfloader/bpfloader.rc b/bpfloader/bpfloader.rc
index fec7530..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
diff --git a/libbpf_android/Android.bp b/libbpf_android/Android.bp
index 507ca18..06528c8 100644
--- a/libbpf_android/Android.bp
+++ b/libbpf_android/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: "libbpf_android_headers",
     vendor_available: false,
@@ -25,6 +33,9 @@
             enabled: true,
         },
     },
+    sdk_version: "30",
+    header_libs: ["bpf_syscall_wrappers"],
+    export_header_lib_headers: ["bpf_syscall_wrappers"],
 }
 
 cc_library {
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 47e6c67..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;
@@ -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 046d80f..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,181 +24,44 @@
 
 #include <string>
 
-#ifdef BPF_FD_JUST_USE_INT
-  #define BPF_FD_TYPE int
-  #define BPF_FD_TO_U32(x) static_cast<__u32>(x)
-#else
-  #include <android-base/unique_fd.h>
-  #define BPF_FD_TYPE base::unique_fd&
-  #define BPF_FD_TO_U32(x) static_cast<__u32>((x).get())
-#endif
-
-#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 BPF_FD_TYPE map_fd, const void* key, const void* value,
-                           uint64_t flags) {
-    return bpf(BPF_MAP_UPDATE_ELEM, {
-                                            .map_fd = BPF_FD_TO_U32(map_fd),
-                                            .key = ptr_to_u64(key),
-                                            .value = ptr_to_u64(value),
-                                            .flags = flags,
-                                    });
-}
-
-inline int findMapEntry(const BPF_FD_TYPE map_fd, const void* key, void* value) {
-    return bpf(BPF_MAP_LOOKUP_ELEM, {
-                                            .map_fd = BPF_FD_TO_U32(map_fd),
-                                            .key = ptr_to_u64(key),
-                                            .value = ptr_to_u64(value),
-                                    });
-}
-
-inline int deleteMapEntry(const BPF_FD_TYPE map_fd, const void* key) {
-    return bpf(BPF_MAP_DELETE_ELEM, {
-                                            .map_fd = BPF_FD_TO_U32(map_fd),
-                                            .key = ptr_to_u64(key),
-                                    });
-}
-
-inline int getNextMapKey(const BPF_FD_TYPE map_fd, const void* key, void* next_key) {
-    return bpf(BPF_MAP_GET_NEXT_KEY, {
-                                             .map_fd = BPF_FD_TO_U32(map_fd),
-                                             .key = ptr_to_u64(key),
-                                             .next_key = ptr_to_u64(next_key),
-                                     });
-}
-
-inline int getFirstMapKey(const BPF_FD_TYPE map_fd, void* firstKey) {
-    return getNextMapKey(map_fd, NULL, firstKey);
-}
-
-inline int bpfFdPin(const BPF_FD_TYPE map_fd, const char* pathname) {
-    return bpf(BPF_OBJ_PIN, {
-                                    .pathname = ptr_to_u64(pathname),
-                                    .bpf_fd = BPF_FD_TO_U32(map_fd),
-                            });
-}
-
-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 BPF_FD_TYPE prog_fd,
-                         const BPF_FD_TYPE cg_fd) {
-    return bpf(BPF_PROG_ATTACH, {
-                                        .target_fd = BPF_FD_TO_U32(cg_fd),
-                                        .attach_bpf_fd = BPF_FD_TO_U32(prog_fd),
-                                        .attach_type = type,
-                                });
-}
-
-inline int detachProgram(bpf_attach_type type, const BPF_FD_TYPE cg_fd) {
-    return bpf(BPF_PROG_DETACH, {
-                                        .target_fd = BPF_FD_TO_U32(cg_fd),
-                                        .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 9d22584..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,13 +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;
+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_timeinstate.h b/progs/include/bpf_timeinstate.h
index 7cb7baa..1065b6e 100644
--- a/progs/include/bpf_timeinstate.h
+++ b/progs/include/bpf_timeinstate.h
@@ -19,6 +19,10 @@
 
 #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