Support requesting and receiving wakeup events

Test: as follows
    - built
    - flashed
    - booted
    - ConnectivityServiceTest passes
Bug: 28806131

Change-Id: Ifc45260d5315479393da2c859ba4afed4e0e8c85
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7b4981e4..da9c966 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -214,6 +214,13 @@
     // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
     private final int mReleasePendingIntentDelayMs;
 
+    // Driver specific constants used to select packets received via
+    // WiFi that caused the phone to exit sleep state. Currently there
+    // is only one kernel implementation so we can get away with
+    // constants.
+    private static final int mWakeupPacketMark = 0x80000000;
+    private static final int mWakeupPacketMask = 0x80000000;
+
     private MockableSystemProperties mSystemProperties;
 
     private Tethering mTethering;
@@ -4480,7 +4487,7 @@
             networkAgent.clatd.fixupLinkProperties(oldLp);
         }
 
-        updateInterfaces(newLp, oldLp, netId);
+        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
         updateMtu(newLp, oldLp);
         // TODO - figure out what to do for clat
 //        for (LinkProperties lp : newLp.getStackedLinks()) {
@@ -4518,7 +4525,26 @@
         }
     }
 
-    private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId) {
+    private void wakeupAddInterface(String iface, NetworkCapabilities caps) throws RemoteException {
+        // Marks are only available on WiFi interaces. Checking for
+        // marks on unsupported interfaces is harmless.
+        if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+            return;
+        }
+        mNetd.getNetdService().wakeupAddInterface(
+            iface, "iface:" + iface, mWakeupPacketMark, mWakeupPacketMask);
+    }
+
+    private void wakeupDelInterface(String iface, NetworkCapabilities caps) throws RemoteException {
+        if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+            return;
+        }
+        mNetd.getNetdService().wakeupDelInterface(
+            iface, "iface:" + iface, mWakeupPacketMark, mWakeupPacketMask);
+    }
+
+    private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId,
+                                  NetworkCapabilities caps) {
         CompareResult<String> interfaceDiff = new CompareResult<String>();
         if (oldLp != null) {
             interfaceDiff = oldLp.compareAllInterfaceNames(newLp);
@@ -4529,6 +4555,7 @@
             try {
                 if (DBG) log("Adding iface " + iface + " to network " + netId);
                 mNetd.addInterfaceToNetwork(iface, netId);
+                wakeupAddInterface(iface, caps);
             } catch (Exception e) {
                 loge("Exception adding interface: " + e);
             }
@@ -4537,6 +4564,7 @@
             try {
                 if (DBG) log("Removing iface " + iface + " from network " + netId);
                 mNetd.removeInterfaceFromNetwork(iface, netId);
+                wakeupDelInterface(iface, caps);
             } catch (Exception e) {
                 loge("Exception removing interface: " + e);
             }