Snap for 8426163 from 8c794ee2e5cdaeab0ee5f935865f0e8610b58e76 to mainline-tzdata2-release

Change-Id: Id6d1c5965819ec3154a66509f46233013d06eb4c
diff --git a/Android.bp b/Android.bp
index c8c1681..a1d6d9a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,20 +1,3 @@
-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
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/bpfloader/Android.bp b/bpfloader/Android.bp
index 7e7139f..0b4bbd4 100644
--- a/bpfloader/Android.bp
+++ b/bpfloader/Android.bp
@@ -17,14 +17,6 @@
 //
 // 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",
 
@@ -36,7 +28,6 @@
     ],
     sanitize: {
         integer_overflow: true,
-        memtag_heap: true,
     },
     clang: true,
     shared_libs: [
diff --git a/bpfloader/BpfLoader.cpp b/bpfloader/BpfLoader.cpp
index 7a68894..e67c469 100644
--- a/bpfloader/BpfLoader.cpp
+++ b/bpfloader/BpfLoader.cpp
@@ -51,37 +51,22 @@
 using android::base::EndsWith;
 using std::string;
 
-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 = "",
-        },
-};
+#define BPF_PROG_PATH "/system/etc/bpf/"
 
-int loadAllElfObjects(const char* const progDir, const char* const prefix) {
+int loadAllElfObjects(void) {
     int retVal = 0;
     DIR* dir;
     struct dirent* ent;
 
-    if ((dir = opendir(progDir)) != NULL) {
+    if ((dir = opendir(BPF_PROG_PATH)) != NULL) {
         while ((ent = readdir(dir)) != NULL) {
             string s = ent->d_name;
             if (!EndsWith(s, ".o")) continue;
 
-            string progPath(progDir);
-            progPath += s;
+            string progPath = BPF_PROG_PATH + s;
 
             bool critical;
-            int ret = android::bpf::loadProg(progPath.c_str(), &critical, prefix);
+            int ret = android::bpf::loadProg(progPath.c_str(), &critical);
             if (ret) {
                 if (critical) retVal = ret;
                 ALOGE("Failed to load object: %s, ret: %s", progPath.c_str(), std::strerror(-ret));
@@ -94,36 +79,17 @@
     return retVal;
 }
 
-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() {
+    if (!android::bpf::isBpfSupported()) return 0;
+
     // Load all ELF objects, create programs and maps, and pin them
-    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 (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;
     }
 
     if (android::base::SetProperty("bpf.progs_loaded", "1") == false) {
diff --git a/bpfloader/bpfloader.rc b/bpfloader/bpfloader.rc
index 3c56c43..04d9b81 100644
--- a/bpfloader/bpfloader.rc
+++ b/bpfloader/bpfloader.rc
@@ -7,6 +7,9 @@
 #   - /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
@@ -20,10 +23,10 @@
     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
-    exec_start bpfloader
+    start bpfloader
 
 service bpfloader /system/bin/bpfloader
-    capabilities CHOWN SYS_ADMIN NET_ADMIN
+    capabilities CHOWN SYS_ADMIN
     #
     # Set RLIMIT_MEMLOCK to 1GiB for bpfloader
     #
diff --git a/libbpf_android/Android.bp b/libbpf_android/Android.bp
index 06528c8..cd2342e 100644
--- a/libbpf_android/Android.bp
+++ b/libbpf_android/Android.bp
@@ -14,35 +14,22 @@
 // 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 09cd36c..b384c11 100644
--- a/libbpf_android/BpfLoadTest.cpp
+++ b/libbpf_android/BpfLoadTest.cpp
@@ -38,6 +38,8 @@
     int mProgFd;
 
     void SetUp() {
+        SKIP_IF_BPF_NOT_SUPPORTED;
+
         unlink(tp_prog_path);
         unlink(tp_map_path);
 
@@ -53,6 +55,8 @@
     }
 
     void TearDown() {
+        SKIP_IF_BPF_NOT_SUPPORTED;
+
         close(mProgFd);
         unlink(tp_prog_path);
         unlink(tp_map_path);
@@ -84,6 +88,8 @@
 };
 
 TEST_F(BpfLoadTest, bpfCheckMap) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
     checkMapNonZero();
 }
 
diff --git a/libbpf_android/BpfMapTest.cpp b/libbpf_android/BpfMapTest.cpp
index d0737b0..91b9bf3 100644
--- a/libbpf_android/BpfMapTest.cpp
+++ b/libbpf_android/BpfMapTest.cpp
@@ -54,6 +54,8 @@
     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));
@@ -61,6 +63,8 @@
     }
 
     void TearDown() {
+        SKIP_IF_BPF_NOT_SUPPORTED;
+
         if (!access(PINNED_MAP_PATH, R_OK)) {
             EXPECT_EQ(0, remove(PINNED_MAP_PATH));
         }
@@ -103,6 +107,8 @@
 };
 
 TEST_F(BpfMapTest, constructor) {
+    SKIP_IF_BPF_NOT_SUPPORTED;
+
     BpfMap<uint32_t, uint32_t> testMap1;
     checkMapInvalid(testMap1);
 
@@ -111,6 +117,8 @@
 }
 
 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;
@@ -125,6 +133,8 @@
 }
 
 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;
@@ -137,6 +147,8 @@
 }
 
 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);
@@ -147,6 +159,8 @@
 }
 
 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));
@@ -163,6 +177,8 @@
 }
 
 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;
@@ -181,6 +197,8 @@
 }
 
 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;
@@ -201,6 +219,8 @@
 }
 
 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;
@@ -231,6 +251,8 @@
 }
 
 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 8689192..3b6c764 100644
--- a/libbpf_android/BpfUtils.cpp
+++ b/libbpf_android/BpfUtils.cpp
@@ -34,6 +34,7 @@
 #include <sstream>
 #include <string>
 
+#include <android-base/properties.h>
 #include <android-base/unique_fd.h>
 #include <log/log.h>
 #include <processgroup/processgroup.h>
@@ -94,6 +95,8 @@
     return res;
 }
 
+#define KVER(a, b, c) ((a)*65536 + (b)*256 + (c))
+
 unsigned kernelVersion() {
     struct utsname buf;
     int ret = uname(&buf);
@@ -110,5 +113,52 @@
     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 259068a..da6a109 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -28,12 +28,8 @@
 #include <sys/utsname.h>
 #include <unistd.h>
 
-// This is BpfLoader v0.2
-#define BPFLOADER_VERSION_MAJOR 0u
-#define BPFLOADER_VERSION_MINOR 2u
-#define BPFLOADER_VERSION ((BPFLOADER_VERSION_MAJOR << 16) | BPFLOADER_VERSION_MINOR)
-
 #include "../progs/include/bpf_map_def.h"
+#include "LoaderUtils.h"
 #include "bpf/BpfUtils.h"
 #include "include/libbpf_android.h"
 
@@ -44,6 +40,7 @@
 #include <string>
 #include <vector>
 
+#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 
@@ -63,17 +60,6 @@
 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;
@@ -87,16 +73,15 @@
  * 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},
-        {"xdp", BPF_PROG_TYPE_XDP},
+    {"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},
 
-        /* End of table */
-        {"END", BPF_PROG_TYPE_UNSPEC},
+    /* End of table */
+    {"END", BPF_PROG_TYPE_UNSPEC},
 };
 
 typedef struct {
@@ -140,8 +125,11 @@
 /* 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 ret = readSectionHeadersAll(elfFile, shTable);
+    int entries, ret = 0;
+
+    ret = readSectionHeadersAll(elfFile, shTable);
     if (ret) return ret;
+    entries = shTable.size();
 
     elfFile.seekg(shTable[id].sh_offset);
     if (elfFile.fail()) return -1;
@@ -155,7 +143,9 @@
 /* Read whole section header string table */
 static int readSectionHeaderStrtab(ifstream& elfFile, vector<char>& strtab) {
     Elf64_Ehdr eh;
-    int ret = readElfHeader(elfFile, &eh);
+    int ret = 0;
+
+    ret = readElfHeader(elfFile, &eh);
     if (ret) return ret;
 
     ret = readSectionByIdx(elfFile, eh.e_shstrndx, strtab);
@@ -210,29 +200,6 @@
     return -2;
 }
 
-unsigned int readSectionUint(const char* name, ifstream& elfFile, unsigned int defVal) {
-    vector<char> theBytes;
-    int ret = readSectionByName(name, elfFile, theBytes);
-    if (ret) {
-        ALOGD("Couldn't find section %s (defaulting to %u [0x%x]).\n", name, defVal, defVal);
-        return defVal;
-    } else if (theBytes.size() < sizeof(unsigned int)) {
-        ALOGE("Section %s too short (defaulting to %u [0x%x]).\n", name, defVal, defVal);
-        return defVal;
-    } else {
-        // decode first 4 bytes as LE32 uint, there will likely be more bytes due to alignment.
-        unsigned int value = static_cast<unsigned char>(theBytes[3]);
-        value <<= 8;
-        value += static_cast<unsigned char>(theBytes[2]);
-        value <<= 8;
-        value += static_cast<unsigned char>(theBytes[1]);
-        value <<= 8;
-        value += static_cast<unsigned char>(theBytes[0]);
-        ALOGI("Section %s value is %u [0x%x]\n", name, value, value);
-        return value;
-    }
-}
-
 static int readSectionByType(ifstream& elfFile, int type, vector<char>& data) {
     int ret;
     vector<Elf64_Shdr> shTable;
@@ -289,7 +256,7 @@
 {
     for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++)
         if (sectionNameTypes[i].type == type)
-            return string(sectionNameTypes[i].name);
+            return std::string(sectionNameTypes[i].name);
 
     return NULL;
 }
@@ -301,7 +268,7 @@
 
         if (st.type != cs.type) continue;
 
-        if (StartsWith(name, string(".rel") + st.name + "/"))
+        if (StartsWith(name, std::string(".rel") + st.name + "/"))
             return true;
         else
             return false;
@@ -309,36 +276,14 @@
     return false;
 }
 
-static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd,
-                        size_t sizeOfBpfProgDef) {
+static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd) {
     vector<char> pdData;
     int ret = readSectionByName("progs", elfFile, pdData);
-    // Older file formats do not require a 'progs' section at all.
-    // (We should probably figure out whether this is behaviour which is safe to remove now.)
     if (ret == -2) return 0;
     if (ret) return ret;
 
-    if (pdData.size() % sizeOfBpfProgDef) {
-        ALOGE("readProgDefs failed due to improper sized progs section, %zu %% %zu != 0\n",
-              pdData.size(), sizeOfBpfProgDef);
-        return -1;
-    };
-
-    int progCount = pdData.size() / sizeOfBpfProgDef;
-    pd.resize(progCount);
-    size_t trimmedSize = std::min(sizeOfBpfProgDef, sizeof(struct bpf_prog_def));
-
-    const char* dataPtr = pdData.data();
-    for (auto& p : pd) {
-        // First we zero initialize
-        memset(&p, 0, sizeof(p));
-        // Then we set non-zero defaults
-        p.bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER;  // v1.0
-        // Then we copy over the structure prefix from the ELF file.
-        memcpy(&p, dataPtr, trimmedSize);
-        // Move to next struct in the ELF file
-        dataPtr += sizeOfBpfProgDef;
-    }
+    pd.resize(pdData.size() / sizeof(struct bpf_prog_def));
+    memcpy(pd.data(), pdData.data(), pdData.size());
     return 0;
 }
 
@@ -368,7 +313,7 @@
 
     /* No section found with matching name*/
     if (sec_idx == -1) {
-        ALOGW("No %s section could be found in elf object\n", sectionName.c_str());
+        ALOGE("No %s section could be found in elf object\n", sectionName.c_str());
         return -1;
     }
 
@@ -385,7 +330,7 @@
 }
 
 /* Read a section by its index - for ex to get sec hdr strtab blob */
-static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs, size_t sizeOfBpfProgDef) {
+static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs) {
     vector<Elf64_Shdr> shTable;
     int entries, ret = 0;
 
@@ -394,7 +339,7 @@
     entries = shTable.size();
 
     vector<struct bpf_prog_def> pd;
-    ret = readProgDefs(elfFile, pd, sizeOfBpfProgDef);
+    ret = readProgDefs(elfFile, pd);
     if (ret) return ret;
     vector<string> progDefNames;
     ret = getSectionSymNames(elfFile, "progs", progDefNames);
@@ -411,10 +356,7 @@
         enum bpf_prog_type ptype = getSectionType(name);
         if (ptype != BPF_PROG_TYPE_UNSPEC) {
             string oldName = name;
-
-            // convert all slashes to underscores
-            std::replace(name.begin(), name.end(), '/', '_');
-
+            deslash(name);
             cs_temp.type = ptype;
             cs_temp.name = name;
 
@@ -465,8 +407,7 @@
     return getSymName(elfFile, symtab[index].st_name, name);
 }
 
-static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds,
-                      const char* prefix, size_t sizeOfBpfMapDef) {
+static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds) {
     int ret;
     vector<char> mdData;
     vector<struct bpf_map_def> md;
@@ -476,105 +417,31 @@
     ret = readSectionByName("maps", elfFile, mdData);
     if (ret == -2) return 0;  // no maps to read
     if (ret) return ret;
-
-    if (mdData.size() % sizeOfBpfMapDef) {
-        ALOGE("createMaps failed due to improper sized maps section, %zu %% %zu != 0\n",
-              mdData.size(), sizeOfBpfMapDef);
-        return -1;
-    };
-
-    int mapCount = mdData.size() / sizeOfBpfMapDef;
-    md.resize(mapCount);
-    size_t trimmedSize = std::min(sizeOfBpfMapDef, sizeof(struct bpf_map_def));
-
-    const char* dataPtr = mdData.data();
-    for (auto& m : md) {
-        // First we zero initialize
-        memset(&m, 0, sizeof(m));
-        // Then we set non-zero defaults
-        m.bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER;  // v1.0
-        m.max_kver = 0xFFFFFFFFu;                         // matches KVER_INF from bpf_helpers.h
-        // Then we copy over the structure prefix from the ELF file.
-        memcpy(&m, dataPtr, trimmedSize);
-        // Move to next struct in the ELF file
-        dataPtr += sizeOfBpfMapDef;
-    }
+    md.resize(mdData.size() / sizeof(struct bpf_map_def));
+    memcpy(md.data(), mdData.data(), mdData.size());
 
     ret = getSectionSymNames(elfFile, "maps", mapNames);
     if (ret) return ret;
 
-    unsigned kvers = kernelVersion();
-
     for (int i = 0; i < (int)mapNames.size(); i++) {
-        if (BPFLOADER_VERSION < md[i].bpfloader_min_ver) {
-            ALOGI("skipping map %s which requires bpfloader min ver 0x%05x\n", mapNames[i].c_str(),
-                  md[i].bpfloader_min_ver);
-            mapFds.push_back(unique_fd());
-            continue;
-        }
-
-        if (BPFLOADER_VERSION >= md[i].bpfloader_max_ver) {
-            ALOGI("skipping map %s which requires bpfloader max ver 0x%05x\n", mapNames[i].c_str(),
-                  md[i].bpfloader_max_ver);
-            mapFds.push_back(unique_fd());
-            continue;
-        }
-
-        if (kvers < md[i].min_kver) {
-            ALOGI("skipping map %s which requires kernel version 0x%x >= 0x%x\n",
-                  mapNames[i].c_str(), kvers, md[i].min_kver);
-            mapFds.push_back(unique_fd());
-            continue;
-        }
-
-        if (kvers >= md[i].max_kver) {
-            ALOGI("skipping map %s which requires kernel version 0x%x < 0x%x\n",
-                  mapNames[i].c_str(), kvers, md[i].max_kver);
-            mapFds.push_back(unique_fd());
-            continue;
-        }
-
-        // Format of pin location is /sys/fs/bpf/<prefix>map_<filename>_<mapname>
-        string mapPinLoc =
-                string(BPF_FS_PATH) + prefix + "map_" + fname + "_" + string(mapNames[i]);
-        bool reuse = false;
         unique_fd fd;
-        int saved_errno;
+        // Format of pin location is /sys/fs/bpf/map_<filename>_<mapname>
+        string mapPinLoc;
+        bool reuse = false;
 
+        mapPinLoc = string(BPF_FS_PATH) + "map_" + fname + "_" + string(mapNames[i]);
         if (access(mapPinLoc.c_str(), F_OK) == 0) {
             fd.reset(bpf_obj_get(mapPinLoc.c_str()));
-            saved_errno = errno;
             ALOGD("bpf_create_map reusing map %s, ret: %d\n", mapNames[i].c_str(), fd.get());
             reuse = true;
         } else {
-            enum bpf_map_type type = md[i].type;
-            if (type == BPF_MAP_TYPE_DEVMAP && !isAtLeastKernelVersion(4, 14, 0)) {
-                // On Linux Kernels older than 4.14 this map type doesn't exist, but it can kind
-                // of be approximated: ARRAY has the same userspace api, though it is not usable
-                // by the same ebpf programs.  However, that's okay because the bpf_redirect_map()
-                // helper doesn't exist on 4.9 anyway (so the bpf program would fail to load,
-                // and thus needs to be tagged as 4.14+ either way), so there's nothing useful you
-                // could do with a DEVMAP anyway (that isn't already provided by an ARRAY)...
-                // Hence using an ARRAY instead of a DEVMAP simply makes life easier for userspace.
-                type = BPF_MAP_TYPE_ARRAY;
-            }
-            if (type == BPF_MAP_TYPE_DEVMAP_HASH && !isAtLeastKernelVersion(5, 4, 0)) {
-                // On Linux Kernels older than 5.4 this map type doesn't exist, but it can kind
-                // of be approximated: HASH has the same userspace visible api.
-                // However it cannot be used by ebpf programs in the same way.
-                // Since bpf_redirect_map() only requires 4.14, a program using a DEVMAP_HASH map
-                // would fail to load (due to trying to redirect to a HASH instead of DEVMAP_HASH).
-                // One must thus tag any BPF_MAP_TYPE_DEVMAP_HASH + bpf_redirect_map() using
-                // programs as being 5.4+...
-                type = BPF_MAP_TYPE_HASH;
-            }
-            fd.reset(bpf_create_map(type, mapNames[i].c_str(), md[i].key_size, md[i].value_size,
+            fd.reset(bpf_create_map(md[i].type, mapNames[i].c_str(), md[i].key_size, md[i].value_size,
                                     md[i].max_entries, md[i].map_flags));
-            saved_errno = errno;
             ALOGD("bpf_create_map name %s, ret: %d\n", mapNames[i].c_str(), fd.get());
         }
 
-        if (fd < 0) return -saved_errno;
+        if (fd < 0) return fd;
+        if (fd == 0) return -EINVAL;
 
         if (!reuse) {
             ret = bpf_obj_pin(fd, mapPinLoc.c_str());
@@ -664,8 +531,7 @@
     }
 }
 
-static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license,
-                            const char* prefix) {
+static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license) {
     unsigned kvers = kernelVersion();
     int ret, fd;
 
@@ -675,8 +541,6 @@
 
     for (int i = 0; i < (int)cs.size(); i++) {
         string name = cs[i].name;
-        unsigned bpfMinVer = DEFAULT_BPFLOADER_MIN_VER;  // v0.0
-        unsigned bpfMaxVer = DEFAULT_BPFLOADER_MAX_VER;  // v1.0
 
         if (cs[i].prog_def.has_value()) {
             unsigned min_kver = cs[i].prog_def->min_kver;
@@ -685,16 +549,8 @@
                   max_kver, kvers);
             if (kvers < min_kver) continue;
             if (kvers >= max_kver) continue;
-
-            bpfMinVer = cs[i].prog_def->bpfloader_min_ver;
-            bpfMaxVer = cs[i].prog_def->bpfloader_max_ver;
         }
 
-        ALOGD("cs[%d].name:%s requires bpfloader version [0x%05x,0x%05x)\n", i, name.c_str(),
-              bpfMinVer, bpfMaxVer);
-        if (BPFLOADER_VERSION < bpfMinVer) continue;
-        if (BPFLOADER_VERSION >= bpfMaxVer) continue;
-
         // strip any potential $foo suffix
         // this can be used to provide duplicate programs
         // conditionally loaded based on running kernel version
@@ -702,10 +558,8 @@
 
         bool reuse = false;
         // Format of pin location is
-        // /sys/fs/bpf/<prefix>prog_<filename>_<mapname>
-        string progPinLoc = BPF_FS_PATH;
-        progPinLoc += prefix;
-        progPinLoc += "prog_";
+        // /sys/fs/bpf/prog_<filename>_<mapname>
+        string progPinLoc = BPF_FS_PATH "prog_";
         progPinLoc += fname;
         progPinLoc += '_';
         progPinLoc += name;
@@ -724,7 +578,7 @@
                   cs[i].name.c_str(), fd, (fd < 0 ? std::strerror(errno) : "no error"));
 
             if (fd < 0) {
-                vector<string> lines = android::base::Split(log_buf.data(), "\n");
+                std::vector<std::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());
@@ -759,7 +613,7 @@
     return 0;
 }
 
-int loadProg(const char* elfPath, bool* isCritical, const char* prefix) {
+int loadProg(const char* elfPath, bool* isCritical) {
     vector<char> license;
     vector<char> critical;
     vector<codeSection> cs;
@@ -785,46 +639,7 @@
               elfPath, (char*)license.data());
     }
 
-    // the following default values are for bpfloader V0.0 format which does not include them
-    unsigned int bpfLoaderMinVer =
-            readSectionUint("bpfloader_min_ver", elfFile, DEFAULT_BPFLOADER_MIN_VER);
-    unsigned int bpfLoaderMaxVer =
-            readSectionUint("bpfloader_max_ver", elfFile, DEFAULT_BPFLOADER_MAX_VER);
-    size_t sizeOfBpfMapDef =
-            readSectionUint("size_of_bpf_map_def", elfFile, DEFAULT_SIZEOF_BPF_MAP_DEF);
-    size_t sizeOfBpfProgDef =
-            readSectionUint("size_of_bpf_prog_def", elfFile, DEFAULT_SIZEOF_BPF_PROG_DEF);
-
-    // inclusive lower bound check
-    if (BPFLOADER_VERSION < bpfLoaderMinVer) {
-        ALOGI("BpfLoader version 0x%05x ignoring ELF object %s with min ver 0x%05x\n",
-              BPFLOADER_VERSION, elfPath, bpfLoaderMinVer);
-        return 0;
-    }
-
-    // exclusive upper bound check
-    if (BPFLOADER_VERSION >= bpfLoaderMaxVer) {
-        ALOGI("BpfLoader version 0x%05x ignoring ELF object %s with max ver 0x%05x\n",
-              BPFLOADER_VERSION, elfPath, bpfLoaderMaxVer);
-        return 0;
-    }
-
-    ALOGI("BpfLoader version 0x%05x processing ELF object %s with ver [0x%05x,0x%05x)\n",
-          BPFLOADER_VERSION, elfPath, bpfLoaderMinVer, bpfLoaderMaxVer);
-
-    if (sizeOfBpfMapDef < DEFAULT_SIZEOF_BPF_MAP_DEF) {
-        ALOGE("sizeof(bpf_map_def) of %zu is too small (< %d)\n", sizeOfBpfMapDef,
-              DEFAULT_SIZEOF_BPF_MAP_DEF);
-        return -1;
-    }
-
-    if (sizeOfBpfProgDef < DEFAULT_SIZEOF_BPF_PROG_DEF) {
-        ALOGE("sizeof(bpf_prog_def) of %zu is too small (< %d)\n", sizeOfBpfProgDef,
-              DEFAULT_SIZEOF_BPF_PROG_DEF);
-        return -1;
-    }
-
-    ret = readCodeSections(elfFile, cs, sizeOfBpfProgDef);
+    ret = readCodeSections(elfFile, cs);
     if (ret) {
         ALOGE("Couldn't read all code sections in %s\n", elfPath);
         return ret;
@@ -833,7 +648,7 @@
     /* Just for future debugging */
     if (0) dumpAllCs(cs);
 
-    ret = createMaps(elfPath, elfFile, mapFds, prefix, sizeOfBpfMapDef);
+    ret = createMaps(elfPath, elfFile, mapFds);
     if (ret) {
         ALOGE("Failed to create maps: (ret=%d) in %s\n", ret, elfPath);
         return ret;
@@ -844,11 +659,28 @@
 
     applyMapRelo(elfFile, mapFds, cs);
 
-    ret = loadCodeSections(elfPath, cs, string(license.data()), prefix);
+    ret = loadCodeSections(elfPath, cs, string(license.data()));
     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
new file mode 100644
index 0000000..a5ff7fc
--- /dev/null
+++ b/libbpf_android/LoaderUtils.h
@@ -0,0 +1,37 @@
+/*
+ * 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 bdffc0f..3e7413e 100644
--- a/libbpf_android/include/bpf/BpfMap.h
+++ b/libbpf_android/include/bpf/BpfMap.h
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#pragma once
+#ifndef BPF_BPFMAP_H
+#define BPF_BPFMAP_H
 
 #include <linux/bpf.h>
 
@@ -133,11 +134,10 @@
         return *this;
     }
 
-    // Move assignment operator
-    BpfMap<Key, Value>& operator=(BpfMap<Key, Value>&& other) noexcept {
+    // Move constructor
+    void operator=(BpfMap<Key, Value>&& other) noexcept {
         mMapFd = std::move(other.mMapFd);
         other.reset(-1);
-        return *this;
     }
 
     void reset(base::unique_fd fd) = delete;
@@ -258,3 +258,5 @@
 
 }  // namespace bpf
 }  // namespace android
+
+#endif
diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h
index 8fd2a4a..6814f94 100644
--- a/libbpf_android/include/bpf/BpfUtils.h
+++ b/libbpf_android/include/bpf/BpfUtils.h
@@ -14,9 +14,12 @@
  * limitations under the License.
  */
 
-#pragma once
+#ifndef BPF_BPFUTILS_H
+#define BPF_BPFUTILS_H
 
+#include <linux/bpf.h>
 #include <linux/if_ether.h>
+#include <linux/unistd.h>
 #include <net/if.h>
 #include <stdlib.h>
 #include <string.h>
@@ -24,60 +27,174 @@
 
 #include <string>
 
-#include "BpfSyscallWrappers.h"
+#include "android-base/unique_fd.h"
+
+#define ptr_to_u64(x) ((uint64_t)(uintptr_t)(x))
 
 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();
-
-#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
-
 unsigned kernelVersion();
+std::string BpfLevelToString(BpfLevel BpfLevel);
+BpfLevel getBpfSupportLevel();
 
-static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) {
-    return kernelVersion() >= KVER(major, minor, sub);
+inline bool isBpfSupported() {
+    return getBpfSupportLevel() != BpfLevel::NONE;
 }
 
-#define SKIP_IF_BPF_SUPPORTED                                                    \
-    do {                                                                         \
-        if (android::bpf::isAtLeastKernelVersion(4, 9, 0)) {                     \
-            GTEST_LOG_(INFO) << "This test is skipped since bpf is supported\n"; \
-            return;                                                              \
-        }                                                                        \
-    } while (0)
-
 #define SKIP_IF_BPF_NOT_SUPPORTED                                                    \
     do {                                                                             \
-        if (!android::bpf::isAtLeastKernelVersion(4, 9, 0)) {                        \
-            GTEST_LOG_(INFO) << "This test is skipped since bpf is not supported\n"; \
+        if (!android::bpf::isBpfSupported()) {                                       \
+            GTEST_LOG_(INFO) << "This test is skipped since bpf is not available\n"; \
             return;                                                                  \
         }                                                                            \
     } while (0)
 
-#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;                                                               \
-        }                                                                         \
+#define SKIP_IF_BPF_SUPPORTED                       \
+    do {                                            \
+        if (android::bpf::isBpfSupported()) return; \
     } while (0)
 
-#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;                                              \
-        }                                                        \
+#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;                                                                       \
+        }                                                                                 \
     } while (0)
 
 }  // namespace bpf
 }  // namespace android
+
+#endif
diff --git a/libbpf_android/include/libbpf_android.h b/libbpf_android/include/libbpf_android.h
index 640f35b..3810d07 100644
--- a/libbpf_android/include/libbpf_android.h
+++ b/libbpf_android/include/libbpf_android.h
@@ -15,33 +15,22 @@
  * limitations under the License.
  */
 
-#pragma once
+#ifndef LIBBPF_SYSTEM_H
+#define LIBBPF_SYSTEM_H
 
 #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, const char* prefix = "");
-
-// Exposed for testing
-unsigned int readSectionUint(const char* name, std::ifstream& elfFile, unsigned int defVal);
+int loadProg(const char* elfPath, bool* isCritical);
 
 // Wait for bpfloader to load BPF programs.
-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);
-    }
-}
+void waitForProgsLoaded();
 
 }  // namespace bpf
 }  // namespace android
+
+#endif
diff --git a/progs/Android.bp b/progs/Android.bp
index aeb04a7..37feafd 100644
--- a/progs/Android.bp
+++ b/progs/Android.bp
@@ -14,14 +14,6 @@
 // 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 abd19c6..f09ec83 100644
--- a/progs/include/bpf_helpers.h
+++ b/progs/include/bpf_helpers.h
@@ -6,47 +6,11 @@
 
 #include "bpf_map_def.h"
 
-/******************************************************************************
- * WARNING: CHANGES TO THIS FILE OUTSIDE OF AOSP/MASTER ARE LIKELY TO BREAK   *
- * DEVICE COMPATIBILITY WITH MAINLINE MODULES SHIPPING EBPF CODE.             *
- *                                                                            *
- * THIS WILL LIKELY RESULT IN BRICKED DEVICES AT SOME ARBITRARY FUTURE TIME   *
- *                                                                            *
- * THAT GOES ESPECIALLY FOR THE 'SEC' 'LICENSE' AND 'CRITICAL' MACRO DEFINES  *
- *                                                                            *
- * We strongly suggest that if you need changes to bpfloader functionality    *
- * you get your changes reviewed and accepted into aosp/master.               *
- *                                                                            *
- ******************************************************************************/
-
 /* place things in different elf sections */
 #define SEC(NAME) __attribute__((section(NAME), used))
 
-/* Must be present in every program, example usage:
- *   LICENSE("GPL"); or LICENSE("Apache 2.0");
- *
- * We also take this opportunity to embed a bunch of other useful values in
- * the resulting .o (This is to enable some limited forward compatibility
- * with mainline module shipped ebpf programs)
- *
- * The bpfloader_{min/max}_ver defines the [min, max) range of bpfloader
- * versions that should load this .o file (bpfloaders outside of this range
- * will simply ignore/skip this *entire* .o)
- * The [inclusive,exclusive) matches what we do for kernel ver dependencies.
- *
- * The size_of_bpf_{map,prog}_def allow the bpfloader to load programs where
- * these structures have been extended with additional fields (they will of
- * course simply be ignored then).
- *
- * If missing, bpfloader_{min/max}_ver default to 0/0x10000 ie. [v0.0, v1.0),
- * while size_of_bpf_{map/prog}_def default to 32/20 which are the v0.0 sizes.
- */
-#define LICENSE(NAME)                                                                       \
-    unsigned int _bpfloader_min_ver SEC("bpfloader_min_ver") = DEFAULT_BPFLOADER_MIN_VER;   \
-    unsigned int _bpfloader_max_ver SEC("bpfloader_max_ver") = DEFAULT_BPFLOADER_MAX_VER;   \
-    size_t _size_of_bpf_map_def SEC("size_of_bpf_map_def") = sizeof(struct bpf_map_def);    \
-    size_t _size_of_bpf_prog_def SEC("size_of_bpf_prog_def") = sizeof(struct bpf_prog_def); \
-    char _license[] SEC("license") = (NAME)
+/* Example use: LICENSE("GPL"); or LICENSE("Apache 2.0"); */
+#define LICENSE(NAME) char _license[] SEC("license") = (NAME)
 
 /* flag the resulting bpf .o file as critical to system functionality,
  * loading all kernel version appropriate programs in it must succeed
@@ -59,10 +23,6 @@
  * implemented in the kernel sources.
  */
 
-#define KVER_NONE 0
-#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
-#define KVER_INF 0xFFFFFFFFu
-
 /* generic functions */
 
 /*
@@ -87,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 pointers to const map because from the C/eBPF point of view
+ * Note: these all take 'const void* 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 struct bpf_map_def* map,
+static void* (*bpf_map_lookup_elem_unsafe)(const void* map,
                                            const void* key) = (void*)BPF_FUNC_map_lookup_elem;
-static int (*bpf_map_update_elem_unsafe)(const struct bpf_map_def* map, const void* key,
-                                         const void* value, unsigned long long flags) = (void*)
+static int (*bpf_map_update_elem_unsafe)(const void* 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 struct bpf_map_def* map,
+static int (*bpf_map_delete_elem_unsafe)(const void* map,
                                          const void* key) = (void*)BPF_FUNC_map_delete_elem;
 
 /* type safe macro to declare a map and related accessor functions */
@@ -108,14 +68,9 @@
             .key_size = sizeof(TypeOfKey),                                                       \
             .value_size = sizeof(TypeOfValue),                                                   \
             .max_entries = (num_entries),                                                        \
-            .map_flags = 0,                                                                      \
             .uid = (usr),                                                                        \
             .gid = (grp),                                                                        \
             .mode = (md),                                                                        \
-            .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER,                                      \
-            .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER,                                      \
-            .min_kver = KVER_NONE,                                                               \
-            .max_kver = KVER_INF,                                                                \
     };                                                                                           \
                                                                                                  \
     static inline __always_inline __unused TypeOfValue* bpf_##the_map##_lookup_elem(             \
@@ -147,12 +102,17 @@
 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;
+// 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 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_INF 0xFFFFFFFF
+
 #define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
                                        opt)                                                        \
     const struct bpf_prog_def SEC("progs") the_prog##_def = {                                      \
@@ -161,8 +121,6 @@
             .min_kver = (min_kv),                                                                  \
             .max_kver = (max_kv),                                                                  \
             .optional = (opt),                                                                     \
-            .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER,                                        \
-            .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER,                                        \
     };                                                                                             \
     SEC(SECTION_NAME)                                                                              \
     int the_prog
diff --git a/progs/include/bpf_map_def.h b/progs/include/bpf_map_def.h
index 647c813..452b682 100644
--- a/progs/include/bpf_map_def.h
+++ b/progs/include/bpf_map_def.h
@@ -23,94 +23,9 @@
 #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>
 
-/******************************************************************************
- *                                                                            *
- *                          ! ! ! W A R N I N G ! ! !                         *
- *                                                                            *
- * CHANGES TO THESE STRUCTURE DEFINITIONS OUTSIDE OF AOSP/MASTER *WILL* BREAK *
- * MAINLINE MODULE COMPATIBILITY                                              *
- *                                                                            *
- * AND THUS MAY RESULT IN YOUR DEVICE BRICKING AT SOME ARBITRARY POINT IN     *
- * THE FUTURE                                                                 *
- *                                                                            *
- * (and even in aosp/master you may only append new fields at the very end,   *
- *  you may *never* delete fields, change their types, ordering, insert in    *
- *  the middle, etc.  If a mainline module using the old definition has       *
- *  already shipped (which happens roughly monthly), then it's set in stone)  *
- *                                                                            *
- ******************************************************************************/
-
-// These are the values used if these fields are missing
-#define DEFAULT_BPFLOADER_MIN_VER 0u        // v0.0 (this is inclusive ie. >= v0.0)
-#define DEFAULT_BPFLOADER_MAX_VER 0x10000u  // v1.0 (this is exclusive ie. < v1.0)
-#define DEFAULT_SIZEOF_BPF_MAP_DEF 32       // v0.0 struct: enum (uint sized) + 7 uint
-#define DEFAULT_SIZEOF_BPF_PROG_DEF 20      // v0.0 struct: 4 uint + bool + 3 byte alignment pad
-
-/*
- * The bpf_{map,prog}_def structures are compiled for different architectures.
- * Once by the BPF compiler for the BPF architecture, and once by a C++
- * compiler for the native Android architecture for the bpfloader.
- *
- * For things to work, their layout must be the same between the two.
- * The BPF architecture is platform independent ('64-bit LSB bpf').
- * So this effectively means these structures must be the same layout
- * on 5 architectures, all of them little endian:
- *   64-bit BPF, x86_64, arm  and  32-bit x86 and arm
- *
- * As such for any types we use inside of these structs we must make sure that
- * the size and alignment are the same, so the same amount of padding is used.
- *
- * Currently we only use: bool, enum bpf_map_type and unsigned int.
- * Additionally we use char for padding.
- *
- * !!! WARNING: HERE BE DRAGONS !!!
- *
- * Be particularly careful with 64-bit integers.
- * You will need to manually override their alignment to 8 bytes.
- *
- * To quote some parts of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69560
- *
- * Some types have weaker alignment requirements when they are structure members.
- *
- * unsigned long long on x86 is such a type.
- *
- * C distinguishes C11 _Alignof (the minimum alignment the type is guaranteed
- * to have in all contexts, so 4, see min_align_of_type) from GNU C __alignof
- * (the normal alignment of the type, so 8).
- *
- * alignof / _Alignof == minimum alignment required by target ABI
- * __alignof / __alignof__ == preferred alignment
- *
- * When in a struct, apparently the minimum alignment is used.
- */
-
-_Static_assert(sizeof(bool) == 1, "sizeof bool != 1");
-_Static_assert(__alignof__(bool) == 1, "__alignof__ bool != 1");
-_Static_assert(_Alignof(bool) == 1, "_Alignof bool != 1");
-
-_Static_assert(sizeof(char) == 1, "sizeof char != 1");
-_Static_assert(__alignof__(char) == 1, "__alignof__ char != 1");
-_Static_assert(_Alignof(char) == 1, "_Alignof char != 1");
-
-// This basically verifies that an enum is 'just' a 32-bit int
-_Static_assert(sizeof(enum bpf_map_type) == 4, "sizeof enum bpf_map_type != 4");
-_Static_assert(__alignof__(enum bpf_map_type) == 4, "__alignof__ enum bpf_map_type != 4");
-_Static_assert(_Alignof(enum bpf_map_type) == 4, "_Alignof enum bpf_map_type != 4");
-
-// Linux kernel requires sizeof(int) == 4, sizeof(void*) == sizeof(long), sizeof(long long) == 8
-_Static_assert(sizeof(unsigned int) == 4, "sizeof unsigned int != 4");
-_Static_assert(__alignof__(unsigned int) == 4, "__alignof__ unsigned int != 4");
-_Static_assert(_Alignof(unsigned int) == 4, "_Alignof unsigned int != 4");
-
-// We don't currently use any 64-bit types in these structs, so this is purely to document issue.
-// Here sizeof & __alignof__ are consistent, but _Alignof is not: compile for 'aosp_cf_x86_phone'
-_Static_assert(sizeof(unsigned long long) == 8, "sizeof unsigned long long != 8");
-_Static_assert(__alignof__(unsigned long long) == 8, "__alignof__ unsigned long long != 8");
-// BPF wants 8, but 32-bit x86 wants 4
-//_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8");
-
 /*
  * Map structure to be used by Android eBPF C programs. The Android eBPF loader
  * uses this structure from eBPF object to create maps at boot time.
@@ -137,41 +52,14 @@
     unsigned int uid;   // uid_t
     unsigned int gid;   // gid_t
     unsigned int mode;  // mode_t
-
-    // The following fields were added in version 0.1
-    unsigned int bpfloader_min_ver;  // if missing, defaults to 0, ie. v0.0
-    unsigned int bpfloader_max_ver;  // if missing, defaults to 0x10000, ie. v1.0
-
-    // The following fields were added in version 0.2
-    // kernelVersion() must be >= min_kver and < max_kver
-    unsigned int min_kver;
-    unsigned int max_kver;
 };
 
-// This needs to be updated whenever the above structure definition is expanded.
-_Static_assert(sizeof(struct bpf_map_def) == 48, "sizeof struct bpf_map_def != 48");
-_Static_assert(__alignof__(struct bpf_map_def) == 4, "__alignof__ struct bpf_map_def != 4");
-_Static_assert(_Alignof(struct bpf_map_def) == 4, "_Alignof struct bpf_map_def != 4");
-
 struct bpf_prog_def {
     unsigned int uid;
     unsigned int gid;
 
-    // kernelVersion() must be >= min_kver and < max_kver
-    unsigned int min_kver;
-    unsigned int max_kver;
+    unsigned int min_kver;  // KERNEL_MAJOR * 65536 + KERNEL_MINOR * 256 + KERNEL_SUB
+    unsigned int max_kver;  // ie. 0x40900 for Linux 4.9 - but beware of hexadecimal for >= 10
 
-    bool optional;  // program section (ie. function) may fail to load, continue onto next func.
-    char pad0[3];
-
-    // The following fields were added in version 0.1
-    unsigned int bpfloader_min_ver;  // if missing, defaults to 0, ie. v0.0
-    unsigned int bpfloader_max_ver;  // if missing, defaults to 0x10000, ie. v1.0
-
-    // No new fields in version 0.2
+    bool optional;  // program section (ie. function) may fail to load, continue onto next func. 
 };
-
-// This needs to be updated whenever the above structure definition is expanded.
-_Static_assert(sizeof(struct bpf_prog_def) == 28, "sizeof struct bpf_prog_def != 28");
-_Static_assert(__alignof__(struct bpf_prog_def) == 4, "__alignof__ struct bpf_prog_def != 4");
-_Static_assert(_Alignof(struct bpf_prog_def) == 4, "_Alignof struct bpf_prog_def != 4");
diff --git a/progs/include/bpf_timeinstate.h b/progs/include/bpf_timeinstate.h
index 1065b6e..6cbc4e1 100644
--- a/progs/include/bpf_timeinstate.h
+++ b/progs/include/bpf_timeinstate.h
@@ -15,14 +15,9 @@
  */
 
 #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
@@ -48,27 +43,3 @@
     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;