NetBpfLoad: change condition for when we execute platform bpfloader

Note that 'true iff U QPR3 or V+' comment is subtle.

netbpfload.35rc runs netbpfload as 'root' uid, so V+ is obvious.

However, netbpfload.33rc runs netbpfload as 'system' uid, so one
would think that this isn't true on T/U.

However the U QPR2 and U QPR3 'service bpfloader' actually run
platform netbpfload, and the U QPR3 platform netbpfload immediately
executes the apex provided netbpfload...

Once the apex netbpfload finishes mainline init is considered
'done', and thus we won't (need to) start service mdnsd_netbpfload.

As a result even on U QPR3, we never run netbpfload as system uid.

Test: TreeHugger
Change-Id: I02661dff07c317394a9d8ba3d48e4cb9cd694fd0
Signed-off-by: Maciej Żenczykowski <maze@google.com>
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index 38f4a4e..15a4fef 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -34,6 +34,7 @@
 namespace net {
 
 using base::unique_fd;
+using base::WaitForProperty;
 using bpf::getSocketCookie;
 using bpf::retrieveProgram;
 using netdutils::Status;
@@ -140,39 +141,47 @@
 BpfHandler::BpfHandler(uint32_t perUidLimit, uint32_t totalLimit)
     : mPerUidStatsEntriesLimit(perUidLimit), mTotalUidStatsEntriesLimit(totalLimit) {}
 
+static bool mainlineNetBpfLoadDone() {
+    return !access("/sys/fs/bpf/netd_shared/mainline_done", F_OK);
+}
+
 // copied with minor changes from waitForProgsLoaded()
 // p/m/C's staticlibs/native/bpf_headers/include/bpf/WaitForProgsLoaded.h
 static inline void waitForNetProgsLoaded() {
     // 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 (base::WaitForProperty("init.svc.bpfloader", "stopped", std::chrono::seconds(delay))
-            && !access("/sys/fs/bpf/netd_shared", F_OK))
+        if (WaitForProperty("init.svc.mdnsd_netbpfload", "stopped", std::chrono::seconds(delay))
+            && mainlineNetBpfLoadDone())
             return;
-        ALOGW("Waited %ds for init.svc.bpfloader=stopped, still waiting...", delay);
+        ALOGW("Waited %ds for init.svc.mdnsd_netbpfload=stopped, still waiting...", delay);
     }
 }
 
 Status BpfHandler::init(const char* cg2_path) {
+    // Note: netd *can* be restarted, so this might get called a second time after boot is complete
+    // at which point we don't need to (and shouldn't) wait for (more importantly start) loading bpf
+
     if (base::GetProperty("bpf.progs_loaded", "") != "1") {
-        // Make sure BPF programs are loaded before doing anything
-        ALOGI("Waiting for BPF programs");
-
-        // TODO: use !modules::sdklevel::IsAtLeastV() once api finalized
-        if (android_get_device_api_level() < __ANDROID_API_V__) {
-            waitForNetProgsLoaded();
-            ALOGI("Networking BPF programs are loaded");
-
-            if (!base::SetProperty("ctl.start", "mdnsd_netbpfload")) {
-                ALOGE("Failed to set property ctl.start=mdnsd_netbpfload, see dmesg for reason.");
-                abort();
-            }
-
-            ALOGI("Waiting for remaining BPF programs");
-        }
-
+        // AOSP platform netd & mainline don't need this (at least prior to U QPR3),
+        // but there could be platform provided (xt_)bpf programs that oem/vendor
+        // modified netd (which calls us during init) depends on...
+        ALOGI("Waiting for platform BPF programs");
         android::bpf::waitForProgsLoaded();
     }
+
+    if (!mainlineNetBpfLoadDone()) {
+        // we're on < U QPR3 & it's the first time netd is starting up (unless crashlooping)
+        if (!base::SetProperty("ctl.start", "mdnsd_netbpfload")) {
+            ALOGE("Failed to set property ctl.start=mdnsd_netbpfload, see dmesg for reason.");
+            abort();
+        }
+
+        ALOGI("Waiting for Networking BPF programs");
+        waitForNetProgsLoaded();
+        ALOGI("Networking BPF programs are loaded");
+    }
+
     ALOGI("BPF programs are loaded");
 
     RETURN_IF_NOT_OK(initPrograms(cg2_path));