Merge "WifiController: remove wifi inactive code"
diff --git a/service/java/com/android/server/wifi/WifiLockManager.java b/service/java/com/android/server/wifi/WifiLockManager.java
index df9586f..b1b3f11 100644
--- a/service/java/com/android/server/wifi/WifiLockManager.java
+++ b/service/java/com/android/server/wifi/WifiLockManager.java
@@ -157,13 +157,14 @@
 
         long ident = Binder.clearCallingIdentity();
         try {
-            // TODO: Introduce a noteFullWifiLockChangedFromSource() so that this logic can be
-            // handled properly in BatteryStats rather than here. This would ensure there are no
-            // "holes" in the reported data due to a "release" event occurring before an
-            // "acquire" event.
+            // Log the acquire before the release to avoid "holes" in the collected data due to
+            // an acquire event immediately after a release in the case where newWorkSource and
+            // wl.mWorkSource share one or more attribution UIDs. BatteryStats can correctly match
+            // "nested" acquire / release pairs.
+            mBatteryStats.noteFullWifiLockAcquiredFromSource(newWorkSource);
             mBatteryStats.noteFullWifiLockReleasedFromSource(wl.mWorkSource);
+
             wl.mWorkSource = newWorkSource;
-            mBatteryStats.noteFullWifiLockAcquiredFromSource(wl.mWorkSource);
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
index 16275c1..5dd87f1 100644
--- a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
+++ b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wifi.rtt;
 
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -44,6 +46,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.os.WorkSource.WorkChain;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.SparseIntArray;
@@ -286,6 +289,9 @@
         mWifiPermissionsUtil.enforceLocationPermission(callingPackage, uid);
         if (workSource != null) {
             enforceLocationHardware();
+            // We only care about UIDs in the incoming worksources and not their associated
+            // tags. Clear names so that other operations involving wakesources become simpler.
+            workSource.clearNames();
         }
 
         // register for binder death
@@ -310,7 +316,7 @@
 
         mRttServiceSynchronized.mHandler.post(() -> {
             WorkSource sourceToUse = workSource;
-            if (workSource == null || workSource.size() == 0 || workSource.get(0) == 0) {
+            if (workSource == null || workSource.isEmpty()) {
                 sourceToUse = new WorkSource(uid);
             }
             mRttServiceSynchronized.queueRangingRequest(uid, sourceToUse, binder, dr,
@@ -322,8 +328,13 @@
     public void cancelRanging(WorkSource workSource) throws RemoteException {
         if (VDBG) Log.v(TAG, "cancelRanging: workSource=" + workSource);
         enforceLocationHardware();
+        if (workSource != null) {
+            // We only care about UIDs in the incoming worksources and not their associated
+            // tags. Clear names so that other operations involving wakesources become simpler.
+            workSource.clearNames();
+        }
 
-        if (workSource == null || workSource.size() == 0 || workSource.get(0) == 0) {
+        if (workSource == null || workSource.isEmpty()) {
             Log.e(TAG, "cancelRanging: invalid work-source -- " + workSource);
             return;
         }
@@ -454,13 +465,8 @@
 
                 boolean match = rri.uid == uid; // original UID will never be 0
                 if (rri.workSource != null && workSource != null) {
-                    try {
-                        rri.workSource.remove(workSource);
-                    } catch (IllegalArgumentException e) {
-                        Log.e(TAG, "Invalid WorkSource specified in the start or cancel requests: "
-                                + e);
-                    }
-                    if (rri.workSource.size() == 0) {
+                    rri.workSource.remove(workSource);
+                    if (rri.workSource.isEmpty()) {
                         match = true;
                     }
                 }
@@ -557,6 +563,14 @@
                     int uid = rri.workSource.get(i);
                     counts.put(uid, counts.get(uid) + 1);
                 }
+
+                final ArrayList<WorkChain> workChains = rri.workSource.getWorkChains();
+                if (workChains != null) {
+                    for (int i = 0; i < workChains.size(); ++i) {
+                        final int uid = workChains.get(i).getAttributionUid();
+                        counts.put(uid, counts.get(uid) + 1);
+                    }
+                }
             }
 
             for (int i = 0; i < ws.size(); ++i) {
@@ -565,6 +579,16 @@
                 }
             }
 
+            final ArrayList<WorkChain> workChains = ws.getWorkChains();
+            if (workChains != null) {
+                for (int i = 0; i < workChains.size(); ++i) {
+                    final int uid = workChains.get(i).getAttributionUid();
+                    if (counts.get(uid) < MAX_QUEUED_PER_UID) {
+                        return false;
+                    }
+                }
+            }
+
             if (mDbg) {
                 Log.v(TAG, "isRequestorSpamming: ws=" + ws + ", someone is spamming: " + counts);
             }
@@ -677,13 +701,29 @@
                     Log.v(TAG, "preExecThrottleCheck: uid=" + ws.get(i) + " -> importance="
                             + uidImportance);
                 }
-                if (uidImportance
-                        <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
+                if (uidImportance <= IMPORTANCE_FOREGROUND_SERVICE) {
                     allUidsInBackground = false;
                     break;
                 }
             }
 
+            final ArrayList<WorkChain> workChains = ws.getWorkChains();
+            if (allUidsInBackground && workChains != null) {
+                for (int i = 0; i < workChains.size(); ++i) {
+                    final WorkChain wc = workChains.get(i);
+                    int uidImportance = mActivityManager.getUidImportance(wc.getAttributionUid());
+                    if (VDBG) {
+                        Log.v(TAG, "preExecThrottleCheck: workChain=" + wc + " -> importance="
+                                + uidImportance);
+                    }
+
+                    if (uidImportance <= IMPORTANCE_FOREGROUND_SERVICE) {
+                        allUidsInBackground = false;
+                        break;
+                    }
+                }
+            }
+
             // if all UIDs are in background then check timestamp since last execution and see if
             // any is permitted (infrequent enough)
             boolean allowExecution = false;
@@ -697,6 +737,18 @@
                         break;
                     }
                 }
+
+                if (workChains != null & !allowExecution) {
+                    for (int i = 0; i < workChains.size(); ++i) {
+                        final WorkChain wc = workChains.get(i);
+                        RttRequesterInfo info = mRttRequesterInfo.get(wc.getAttributionUid());
+                        if (info == null
+                                || info.lastRangingExecuted < mostRecentExecutionPermitted) {
+                            allowExecution = true;
+                            break;
+                        }
+                    }
+                }
             } else {
                 allowExecution = true;
             }
@@ -711,6 +763,18 @@
                     }
                     info.lastRangingExecuted = mClock.getElapsedSinceBootMillis();
                 }
+
+                if (workChains != null) {
+                    for (int i = 0; i < workChains.size(); ++i) {
+                        final WorkChain wc = workChains.get(i);
+                        RttRequesterInfo info = mRttRequesterInfo.get(wc.getAttributionUid());
+                        if (info == null) {
+                            info = new RttRequesterInfo();
+                            mRttRequesterInfo.put(wc.getAttributionUid(), info);
+                        }
+                        info.lastRangingExecuted = mClock.getElapsedSinceBootMillis();
+                    }
+                }
             }
 
             return allowExecution;
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
index 1cc9479..9c2d30b 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
@@ -259,8 +259,8 @@
 
         mWifiLockManager.updateWifiLockWorkSource(mBinder, updated);
         InOrder inOrder = inOrder(mBatteryStats);
-        inOrder.verify(mBatteryStats).noteFullWifiLockReleasedFromSource(mChainedWorkSource);
         inOrder.verify(mBatteryStats).noteFullWifiLockAcquiredFromSource(eq(updated));
+        inOrder.verify(mBatteryStats).noteFullWifiLockReleasedFromSource(mChainedWorkSource);
 
         releaseWifiLockSuccessful(mBinder);
     }
@@ -280,8 +280,8 @@
 
         mWifiLockManager.updateWifiLockWorkSource(mBinder, newWorkSource);
         InOrder inOrder = inOrder(mBatteryStats);
-        inOrder.verify(mBatteryStats).noteFullWifiLockReleasedFromSource(mWorkSource);
         inOrder.verify(mBatteryStats).noteFullWifiLockAcquiredFromSource(eq(newWorkSource));
+        inOrder.verify(mBatteryStats).noteFullWifiLockReleasedFromSource(mWorkSource);
     }
 
     /**
@@ -299,8 +299,8 @@
 
         mWifiLockManager.updateWifiLockWorkSource(mBinder, null);
         InOrder inOrder = inOrder(mBatteryStats);
-        inOrder.verify(mBatteryStats).noteFullWifiLockReleasedFromSource(mWorkSource);
         inOrder.verify(mBatteryStats).noteFullWifiLockAcquiredFromSource(eq(newWorkSource));
+        inOrder.verify(mBatteryStats).noteFullWifiLockReleasedFromSource(mWorkSource);
     }
 
     /**
diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
index ef15914..bbf065a 100644
--- a/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
@@ -515,12 +515,15 @@
         int uid1 = 10;
         int uid2 = 20;
         int uid3 = 30;
+        int uid4 = 40;
         WorkSource worksourceRequest = new WorkSource(uid1);
         worksourceRequest.add(uid2);
         worksourceRequest.add(uid3);
+        worksourceRequest.createWorkChain().addNode(uid4, "foo");
         WorkSource worksourceCancel = new WorkSource(uid2);
         worksourceCancel.add(uid3);
         worksourceCancel.add(uid1);
+        worksourceCancel.createWorkChain().addNode(uid4, "foo");
 
         RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
         Pair<List<RttResult>, List<RangingResult>> results = RttTestUtils.getDummyRangingResults(
@@ -560,7 +563,7 @@
         int uid3 = 30;
         WorkSource worksourceRequest = new WorkSource(uid1);
         worksourceRequest.add(uid2);
-        worksourceRequest.add(uid3);
+        worksourceRequest.createWorkChain().addNode(uid3, null);
         WorkSource worksourceCancel = new WorkSource(uid1);
         worksourceCancel.add(uid2);
 
@@ -817,9 +820,28 @@
      */
     @Test
     public void testRangingThrottleBackgroundWorkSources() throws Exception {
-        WorkSource wsReq1 = new WorkSource(10);
-        WorkSource wsReq2 = new WorkSource(10);
-        wsReq2.add(20);
+        runTestRangingThrottleBackgroundWorkSources(false);
+    }
+
+    @Test
+    public void testRangingThrottleBackgroundChainedWorkSources() throws Exception {
+        runTestRangingThrottleBackgroundWorkSources(true);
+    }
+
+    private void runTestRangingThrottleBackgroundWorkSources(boolean isChained) throws Exception {
+        final WorkSource wsReq1 = new WorkSource();
+        final WorkSource wsReq2 = new WorkSource();
+        if (isChained) {
+            wsReq1.createWorkChain().addNode(10, "foo");
+
+            wsReq2.createWorkChain().addNode(10, "foo");
+            wsReq2.createWorkChain().addNode(20, "bar");
+        } else {
+            wsReq1.add(10);
+
+            wsReq2.add(10);
+            wsReq2.add(20);
+        }
 
         RangingRequest request1 = RttTestUtils.getDummyRangingRequest((byte) 1);
         RangingRequest request2 = RttTestUtils.getDummyRangingRequest((byte) 2);
@@ -885,7 +907,7 @@
      */
     @Test
     public void testRejectFloodingRequestsSingleUid() throws Exception {
-        runFloodRequestsTest(true);
+        runFloodRequestsTest(true, false);
     }
 
     /**
@@ -894,7 +916,12 @@
      */
     @Test
     public void testRejectFloodingRequestsIdenticalWorksources() throws Exception {
-        runFloodRequestsTest(false);
+        runFloodRequestsTest(false, false);
+    }
+
+    @Test
+    public void testRejectFloodingRequestsIdenticalChainedWorksources() throws Exception {
+        runFloodRequestsTest(false, true);
     }
 
     /**
@@ -941,15 +968,22 @@
      * - Flood service with requests: using same ID or same WorkSource
      * - Provide results (to clear queue) and execute another test: validate succeeds
      */
-    private void runFloodRequestsTest(boolean useUids) throws Exception {
+    private void runFloodRequestsTest(boolean useUids, boolean useChainedWorkSources)
+            throws Exception {
         RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 1);
         Pair<List<RttResult>, List<RangingResult>> result = RttTestUtils.getDummyRangingResults(
                 request);
 
         WorkSource ws = new WorkSource();
-        ws.add(10);
-        ws.add(20);
-        ws.add(30);
+        if (useChainedWorkSources) {
+            ws.createWorkChain().addNode(10, "foo");
+            ws.createWorkChain().addNode(20, "bar");
+            ws.createWorkChain().addNode(30, "baz");
+        } else {
+            ws.add(10);
+            ws.add(20);
+            ws.add(30);
+        }
 
         InOrder cbInorder = inOrder(mockCallback);
         InOrder nativeInorder = inOrder(mockNative);