HalDeviceManager: Rework the priority scheme

The new priority scheme is purely based on requesting app context (not
based on IfaceType). Details are explained in the design doc and in the
comments.

Bug: 162344695
Test: Device boots and connects to wifi networks, able to toggle softap
on.
Test: atest com.android.server.wifi

Change-Id: Iadac2ac78efe9d00509b177f97c2aab1eef5b3b1
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index 4c12d39..93a6756 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wifi;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.hardware.wifi.V1_0.IWifi;
@@ -39,7 +40,6 @@
 import android.os.RemoteException;
 import android.os.WorkSource;
 import android.util.Log;
-import android.util.LongSparseArray;
 import android.util.MutableBoolean;
 import android.util.MutableInt;
 import android.util.Pair;
@@ -51,6 +51,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -438,7 +440,7 @@
      * Returns whether the provided Iface combo can be supported by the device.
      * Note: This only returns an answer based on the iface combination exposed by the HAL.
      * The actual iface creation/deletion rules depend on the iface priorities set in
-     * {@link #allowedToDeleteIfaceTypeForRequestedType(int, int, WifiIfaceInfo[][], int)}
+     * {@link #allowedToDeleteIfaceTypeForRequestedType(int, WorkSource, int, WifiIfaceInfo[][])}
      *
      * @param ifaceCombo SparseArray keyed in by the iface type to number of ifaces needed.
      * @return true if the device supports the provided combo, false otherwise.
@@ -472,7 +474,12 @@
             if (mWifi == null) return false;
             WifiChipInfo[] chipInfos = getAllChipInfo();
             if (chipInfos == null) return false;
-            return isItPossibleToCreateIface(chipInfos, ifaceType);
+            if (!validateInterfaceCacheAndRetrieveRequestorWs(chipInfos)) {
+                Log.e(TAG, "isItPossibleToCreateIface: local cache is invalid!");
+                stopWifi(); // major error: shutting down
+                return false;
+            }
+            return isItPossibleToCreateIface(chipInfos, ifaceType, requestorWs);
         }
     }
 
@@ -513,14 +520,14 @@
         public int type;
         public Set<InterfaceDestroyedListenerProxy> destroyedListeners = new HashSet<>();
         public long creationTime;
-        public WorkSourceHelper mRequestorWsHelper;
+        public WorkSourceHelper requestorWsHelper;
 
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder();
             sb.append("{name=").append(name).append(", type=").append(type)
                     .append(", destroyedListeners.size()=").append(destroyedListeners.size())
-                    .append(", RequestorWs=").append(mRequestorWsHelper)
+                    .append(", RequestorWs=").append(requestorWsHelper)
                     .append(", creationTime=").append(creationTime).append("}");
             return sb.toString();
         }
@@ -529,10 +536,12 @@
     private class WifiIfaceInfo {
         public String name;
         public IWifiIface iface;
+        public WorkSourceHelper requestorWsHelper;
 
         @Override
         public String toString() {
-            return "{name=" + name + ", iface=" + iface + "}";
+            return "{name=" + name + ", iface=" + iface + ", requestorWs=" + requestorWsHelper
+                    + " }";
         }
     }
 
@@ -1105,8 +1114,10 @@
      *
      * A discrepancy is if any local state contains references to a chip or interface which are not
      * found on the information read from the chip.
+     *
+     * Also, fills in the |requestorWs| corresponding to each active iface in |WifiChipInfo|.
      */
-    private boolean validateInterfaceCache(WifiChipInfo[] chipInfos) {
+    private boolean validateInterfaceCacheAndRetrieveRequestorWs(WifiChipInfo[] chipInfos) {
         if (VDBG) Log.d(TAG, "validateInterfaceCache");
 
         synchronized (mLock) {
@@ -1134,6 +1145,7 @@
                 boolean matchFound = false;
                 for (WifiIfaceInfo ifaceInfo: ifaceInfoList) {
                     if (ifaceInfo.name.equals(entry.name)) {
+                        ifaceInfo.requestorWsHelper = entry.requestorWsHelper;
                         matchFound = true;
                         break;
                     }
@@ -1348,7 +1360,7 @@
                 return null;
             }
 
-            if (!validateInterfaceCache(chipInfos)) {
+            if (!validateInterfaceCacheAndRetrieveRequestorWs(chipInfos)) {
                 Log.e(TAG, "createIface: local cache is invalid!");
                 stopWifi(); // major error: shutting down
                 return null;
@@ -1380,7 +1392,7 @@
 
                         for (int[] expandedIfaceCombo: expandedIfaceCombos) {
                             IfaceCreationData currentProposal = canIfaceComboSupportRequest(
-                                    chipInfo, chipMode, expandedIfaceCombo, ifaceType);
+                                    chipInfo, chipMode, expandedIfaceCombo, ifaceType, requestorWs);
                             if (compareIfaceCreationData(currentProposal,
                                     bestIfaceCreationProposal)) {
                                 if (VDBG) Log.d(TAG, "new proposal accepted");
@@ -1400,7 +1412,7 @@
                     cacheEntry.chipId = bestIfaceCreationProposal.chipInfo.chipId;
                     cacheEntry.name = getName(iface);
                     cacheEntry.type = ifaceType;
-                    cacheEntry.mRequestorWsHelper = mWifiInjector.makeWsHelper(requestorWs);
+                    cacheEntry.requestorWsHelper = mWifiInjector.makeWsHelper(requestorWs);
                     if (destroyedListener != null) {
                         cacheEntry.destroyedListeners.add(
                                 new InterfaceDestroyedListenerProxy(
@@ -1421,7 +1433,8 @@
 
     // similar to createIfaceIfPossible - but simpler code: not looking for best option just
     // for any option (so terminates on first one).
-    private boolean isItPossibleToCreateIface(WifiChipInfo[] chipInfos, int ifaceType) {
+    private boolean isItPossibleToCreateIface(WifiChipInfo[] chipInfos, int ifaceType,
+            WorkSource requestorWs) {
         if (VDBG) {
             Log.d(TAG, "isItPossibleToCreateIface: chipInfos=" + Arrays.deepToString(chipInfos)
                     + ", ifaceType=" + ifaceType);
@@ -1439,7 +1452,7 @@
 
                     for (int[] expandedIfaceCombo: expandedIfaceCombos) {
                         if (canIfaceComboSupportRequest(chipInfo, chipMode, expandedIfaceCombo,
-                                ifaceType) != null) {
+                                ifaceType, requestorWs) != null) {
                             return true;
                         }
                     }
@@ -1510,11 +1523,12 @@
      * - Mode configuration: i.e. could the mode support the interface type in principle
      */
     private IfaceCreationData canIfaceComboSupportRequest(WifiChipInfo chipInfo,
-            IWifiChip.ChipMode chipMode, int[] chipIfaceCombo, int ifaceType) {
+            IWifiChip.ChipMode chipMode, int[] chipIfaceCombo, int ifaceType,
+            WorkSource requestorWs) {
         if (VDBG) {
             Log.d(TAG, "canIfaceComboSupportRequest: chipInfo=" + chipInfo + ", chipMode="
                     + chipMode + ", chipIfaceCombo=" + Arrays.toString(chipIfaceCombo)
-                    + ", ifaceType=" + ifaceType);
+                    + ", ifaceType=" + ifaceType + ", requestorWs=" + requestorWs);
         }
 
         // short-circuit: does the chipIfaceCombo even support the requested type?
@@ -1531,8 +1545,8 @@
         if (isChipModeChangeProposed) {
             for (int type: IFACE_TYPES_BY_PRIORITY) {
                 if (chipInfo.ifaces[type].length != 0) {
-                    if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType,
-                            chipInfo.ifaces, chipInfo.ifaces[type].length)) {
+                    if (!allowedToDeleteIfaceTypeForRequestedType(
+                            ifaceType, requestorWs, type, chipInfo.ifaces)) {
                         if (VDBG) {
                             Log.d(TAG, "Couldn't delete existing type " + type
                                     + " interfaces for requested type");
@@ -1562,8 +1576,8 @@
             }
 
             if (tooManyInterfaces > 0) { // may need to delete some
-                if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType, chipInfo.ifaces,
-                        tooManyInterfaces)) {
+                if (!allowedToDeleteIfaceTypeForRequestedType(
+                        ifaceType, requestorWs, type, chipInfo.ifaces)) {
                     if (VDBG) {
                         Log.d(TAG, "Would need to delete some higher priority interfaces");
                     }
@@ -1572,7 +1586,7 @@
 
                 // delete the most recently created interfaces
                 interfacesToBeRemovedFirst.addAll(selectInterfacesToDelete(tooManyInterfaces,
-                        chipInfo.ifaces[type]));
+                        ifaceType, requestorWs, type, chipInfo.ifaces[type]));
             }
         }
 
@@ -1635,75 +1649,155 @@
         return false;
     }
 
+    private static final int PRIORITY_PRIVILEGED = 0;
+    private static final int PRIORITY_SYSTEM = 1;
+    private static final int PRIORITY_FG_APP = 2;
+    private static final int PRIORITY_FG_SERVICE = 3;
+    private static final int PRIORITY_BG = 4;
+    @IntDef(prefix = { "PRIORITY_" }, value = {
+            PRIORITY_PRIVILEGED,
+            PRIORITY_SYSTEM,
+            PRIORITY_FG_APP,
+            PRIORITY_FG_SERVICE,
+            PRIORITY_BG
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RequestorWsPriority {}
+
+    /**
+     * Returns integer priority level for the provided |ws| based on rules mentioned in
+     * {@link #allowedToDeleteIfaceTypeForRequestedType(int, WorkSource, WifiIfaceInfo[][])}
+     */
+    private static @RequestorWsPriority int getRequestorWsPriority(WorkSourceHelper ws) {
+        if (ws.hasAnyPrivilegedAppRequest()) return PRIORITY_PRIVILEGED;
+        if (ws.hasAnySystemAppRequest()) return PRIORITY_SYSTEM;
+        if (ws.hasAnyForegroundAppRequest()) return PRIORITY_FG_APP;
+        if (ws.hasAnyForegroundServiceRequest()) return PRIORITY_FG_SERVICE;
+        return PRIORITY_BG;
+    }
+
+    /**
+     * Returns whether interface request from |newRequestorWsPriority| is allowed to delete an
+     * interface request from |existingRequestorWsPriority|.
+     *
+     * Rule:
+     *  - If |newRequestorWsPriority| < |existingRequestorWsPriority|, then YES.
+     *  - If they are at the same priority level, then
+     *      - If both are privileged and not for the same interface type, then YES.
+     *      - Else, NO.
+     */
+    private static boolean allowedToDelete(
+            int requestedIfaceType, @RequestorWsPriority int newRequestorWsPriority,
+            int existingIfaceType, @RequestorWsPriority int existingRequestorWsPriority) {
+        // If the new request is higher priority than existing priority, then the new requestor
+        // wins. This is because at all other priority levels (except privileged), existing caller
+        // wins if both the requests are at the same priority level.
+        if (newRequestorWsPriority < existingRequestorWsPriority) {
+            return true;
+        }
+        if (newRequestorWsPriority == existingRequestorWsPriority) {
+            // If both the requests are same priority for the same iface type, the existing
+            // requestor wins.
+            if (requestedIfaceType == existingIfaceType) {
+                return false;
+            }
+            // If both the requests are privileged, the new requestor wins.
+            if (newRequestorWsPriority == PRIORITY_PRIVILEGED) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Returns true if we're allowed to delete the existing interface type for the requested
      * interface type.
      *
-     * Rules - applies in order:
-     *
      * General rules:
-     * 1. No interface will be destroyed for a requested interface of the same type
-     * 2. No interface will be destroyed if one of the requested interfaces already exists
-     * 3. If there are >1 interface of an existing type, then it is ok to destroy that type
-     *    interface
-     *
-     * Type-specific rules (but note that the general rules are appied first):
-     * 4. Request for AP or STA will destroy any other interface
-     * 5. Request for P2P will destroy NAN-only (but will destroy a second STA per #3)
-     * 6. Request for NAN will destroy P2P-only (but will destroy a second STA per #3)
-     *
-     * Note: the 'numNecessaryInterfaces' is used to specify how many interfaces would be needed to
-     * be deleted. This is used to determine whether there are that many low priority interfaces
-     * of the requested type to delete.
+     * 1. Requests for interfaces have the following priority which are based on corresponding
+     * requesting  app's context. Priorities in decreasing order (i.e (i) has the highest priority,
+     * (v) has the lowest priority).
+     *  - (i) Requests from privileged apps (i.e settings, setup wizard, connectivity stack, etc)
+     *  - (ii) Requests from system apps.
+     *  - (iii) Requests from foreground apps.
+     *  - (iv) Requests from foreground services.
+     *  - (v) Requests from everything else (lumped together as "background").
+     * Note: If there are more than 1 app requesting for a particular interface, then we consider
+     * the priority of the highest priority app among them.
+     * For ex: If there is a system app and a foreground requesting for NAN iface, then we use the
+     * system app to determine the priority of the interface request.
+     * 2. If there are 2 conflicting interface requests from apps with the same priority, then
+     *    - (i) If both the apps are privileged and not for the same interface type, the new request
+     *          wins (last caller wins).
+     *    - (ii) Else, the existing request wins (first caller wins).
+     * Note: Privileged apps are the ones that the user is directly interacting with, hence we use
+     * last caller wins to decide among those, for all other apps we try to minimize disruption to
+     * existing requests.
+     * For ex: User turns on wifi, then hotspot on legacy devices which do not support STA + AP, we
+     * want the last request from the user (i.e hotspot) to be honored.
      */
-    private boolean allowedToDeleteIfaceTypeForRequestedType(int existingIfaceType,
-            int requestedIfaceType, WifiIfaceInfo[][] currentIfaces, int numNecessaryInterfaces) {
-        // rule 1
-        if (existingIfaceType == requestedIfaceType) {
+    private boolean allowedToDeleteIfaceTypeForRequestedType(
+            int requestedIfaceType, WorkSource requestorWs, int existingIfaceType,
+            WifiIfaceInfo[][] existingIfaces) {
+        WorkSourceHelper newRequestorWsHelper = mWifiInjector.makeWsHelper(requestorWs);
+        WifiIfaceInfo[] ifaceInfosForExistingIfaceType = existingIfaces[existingIfaceType];
+        // No ifaces of the existing type, error!
+        if (ifaceInfosForExistingIfaceType.length == 0) {
+            Log.wtf(TAG, "allowedToDeleteIfaceTypeForRequestedType: Num existings ifaces is 0!");
             return false;
         }
-
-        // rule 2
-        if (currentIfaces[requestedIfaceType].length != 0) {
-            return false;
+        for (WifiIfaceInfo ifaceInfo : ifaceInfosForExistingIfaceType) {
+            int newRequestorWsPriority = getRequestorWsPriority(newRequestorWsHelper);
+            int existingRequestorWsPriority = getRequestorWsPriority(ifaceInfo.requestorWsHelper);
+            if (allowedToDelete(
+                    requestedIfaceType, newRequestorWsPriority, existingIfaceType,
+                    existingRequestorWsPriority)) {
+                if (mDbg) {
+                    Log.d(TAG, "allowedToDeleteIfaceTypeForRequestedType: Allowed to delete "
+                            + "requestedIfaceType=" + requestedIfaceType
+                            + "existingIfaceType=" + existingIfaceType
+                            + ", newRequestorWsPriority=" + newRequestorWsHelper
+                            + ", existingRequestorWsPriority" + existingRequestorWsPriority);
+                }
+                return true;
+            }
         }
-
-        // rule 3
-        if (currentIfaces[existingIfaceType].length > 1) {
-            return true;
-        }
-
-        // rule 5
-        if (requestedIfaceType == IfaceType.P2P) {
-            return existingIfaceType == IfaceType.NAN;
-        }
-
-        // rule 6
-        if (requestedIfaceType == IfaceType.NAN) {
-            return existingIfaceType == IfaceType.P2P;
-        }
-
-        // rule 4, the requestIfaceType is either AP or STA
-        return true;
+        return false;
     }
 
     /**
      * Selects the interfaces to delete.
      *
-     * Rule: select low priority interfaces and then other interfaces in order of creation time.
+     * Rule:
+     *  - Select interfaces that are lower priority than the request priority.
+     *  - If they are at the same priority level, then
+     *      - If both are privileged and different iface type, then delete existing interfaces.
+     *      - Else, not allowed to delete.
+     *  - Delete ifaces based on the descending requestor priority
+     *    (i.e bg app requests are deleted first, privileged app requests are deleted last)
+     *  - If there are > 1 ifaces within the same priority group to delete, select them randomly.
      *
      * @param excessInterfaces Number of interfaces which need to be selected.
+     * @param requestedIfaceType Requested iface type.
+     * @param requestorWs Requestor worksource.
+     * @param existingIfaceType Existing iface type.
      * @param interfaces Array of interfaces.
      */
     private List<WifiIfaceInfo> selectInterfacesToDelete(int excessInterfaces,
+            int requestedIfaceType, WorkSource requestorWs, int existingIfaceType,
             WifiIfaceInfo[] interfaces) {
         if (VDBG) {
             Log.d(TAG, "selectInterfacesToDelete: excessInterfaces=" + excessInterfaces
+                    + ", requestedIfaceType=" + requestedIfaceType
+                    + ", requestorWs=" + requestorWs
+                    + ", existingIfaceType=" + existingIfaceType
                     + ", interfaces=" + Arrays.toString(interfaces));
         }
+        WorkSourceHelper newRequestorWsHelper = mWifiInjector.makeWsHelper(requestorWs);
 
         boolean lookupError = false;
-        LongSparseArray<WifiIfaceInfo> orderedList = new LongSparseArray<>();
+        // Map of priority levels to ifaces to delete.
+        Map<Integer, List<WifiIfaceInfo>> ifacesToDeleteMap = new HashMap<>();
         for (WifiIfaceInfo info : interfaces) {
             InterfaceCacheEntry cacheEntry;
             synchronized (mLock) {
@@ -1715,18 +1809,37 @@
                 lookupError = true;
                 break;
             }
-            orderedList.append(cacheEntry.creationTime, info);
+            int newRequestorWsPriority = getRequestorWsPriority(newRequestorWsHelper);
+            int existingRequestorWsPriority = getRequestorWsPriority(cacheEntry.requestorWsHelper);
+            if (allowedToDelete(requestedIfaceType, newRequestorWsPriority, existingIfaceType,
+                    existingRequestorWsPriority)) {
+                ifacesToDeleteMap.computeIfAbsent(
+                        existingRequestorWsPriority, v -> new ArrayList<>()).add(info);
+            }
         }
 
         if (lookupError) {
             Log.e(TAG, "selectInterfacesToDelete: falling back to arbitrary selection");
             return Arrays.asList(Arrays.copyOf(interfaces, excessInterfaces));
         } else {
-            List<WifiIfaceInfo> result = new ArrayList<>(excessInterfaces);
-            for (int i = 0; i < excessInterfaces; ++i) {
-                result.add(orderedList.valueAt(orderedList.size() - i - 1));
+            int numIfacesToDelete = 0;
+            List<WifiIfaceInfo> ifacesToDelete = new ArrayList<>(excessInterfaces);
+            // Iterate from lowest priority to highest priority ifaces.
+            for (int i = PRIORITY_BG; i >= PRIORITY_PRIVILEGED; i--) {
+                List<WifiIfaceInfo> ifacesToDeleteListWithinPriority =
+                        ifacesToDeleteMap.getOrDefault(i, new ArrayList<>());
+                int numIfacesToDeleteWithinPriority =
+                        Math.min(excessInterfaces - numIfacesToDelete,
+                                ifacesToDeleteListWithinPriority.size());
+                ifacesToDelete.addAll(
+                        ifacesToDeleteListWithinPriority.subList(
+                                0, numIfacesToDeleteWithinPriority));
+                numIfacesToDelete += numIfacesToDeleteWithinPriority;
+                if (numIfacesToDelete == excessInterfaces) {
+                    break;
+                }
             }
-            return result;
+            return ifacesToDelete;
         }
     }
 
diff --git a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index e29981d..682831e 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -89,7 +89,9 @@
  */
 @SmallTest
 public class HalDeviceManagerTest extends WifiBaseTest {
-    private static final WorkSource TEST_WORKSOURCE = new WorkSource();
+    private static final WorkSource TEST_WORKSOURCE_0 = new WorkSource(450, "com.test.0");
+    private static final WorkSource TEST_WORKSOURCE_1 = new WorkSource(451, "com.test.1");
+    private static final WorkSource TEST_WORKSOURCE_2 = new WorkSource(452, "com.test.2");
 
     private HalDeviceManager mDut;
     @Mock IServiceManager mServiceManagerMock;
@@ -98,7 +100,9 @@
     @Mock HalDeviceManager.ManagerStatusListener mManagerStatusListenerMock;
     @Mock private Clock mClock;
     @Mock private WifiInjector mWifiInjector;
-    @Mock private WorkSourceHelper mWorkSourceHelper;
+    @Mock private WorkSourceHelper mWorkSourceHelper0;
+    @Mock private WorkSourceHelper mWorkSourceHelper1;
+    @Mock private WorkSourceHelper mWorkSourceHelper2;
     private TestLooper mTestLooper;
     private Handler mHandler;
     private ArgumentCaptor<IHwBinder.DeathRecipient> mDeathRecipientCaptor =
@@ -139,7 +143,13 @@
         mStatusOk = getStatus(WifiStatusCode.SUCCESS);
         mStatusFail = getStatus(WifiStatusCode.ERROR_UNKNOWN);
 
-        when(mWifiInjector.makeWsHelper(any())).thenReturn(mWorkSourceHelper);
+        when(mWifiInjector.makeWsHelper(TEST_WORKSOURCE_0)).thenReturn(mWorkSourceHelper0);
+        when(mWifiInjector.makeWsHelper(TEST_WORKSOURCE_1)).thenReturn(mWorkSourceHelper1);
+        when(mWifiInjector.makeWsHelper(TEST_WORKSOURCE_2)).thenReturn(mWorkSourceHelper2);
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(true);
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(true);
+        when(mWorkSourceHelper2.hasAnyPrivilegedAppRequest()).thenReturn(true);
+
         when(mServiceManagerMock.linkToDeath(any(IHwBinder.DeathRecipient.class),
                 anyLong())).thenReturn(true);
         when(mServiceManagerMock.registerForNotifications(anyString(), anyString(),
@@ -331,7 +341,8 @@
                 "wlan0", // ifaceName
                 TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                staDestroyedListener // destroyedListener
+                staDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA can't be created", staIface, IsNull.notNullValue());
 
@@ -343,7 +354,8 @@
                 "wlan0", // ifaceName
                 TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                nanDestroyedListener // destroyedListener
+                nanDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("NAN can't be created", nanIface, IsNull.notNullValue());
 
@@ -351,7 +363,8 @@
         chipMock.interfaceNames.get(IfaceType.STA).remove("wlan0");
 
         // now try to request another NAN
-        IWifiIface nanIface2 = mDut.createNanIface(nanDestroyedListener, mHandler, TEST_WORKSOURCE);
+        IWifiIface nanIface2 =
+                mDut.createNanIface(nanDestroyedListener, mHandler, TEST_WORKSOURCE_0);
         collector.checkThat("NAN can't be created", nanIface2, IsNull.nullValue());
         mTestLooper.dispatchAll();
 
@@ -492,7 +505,8 @@
                 "wlan0",
                 TestChipV1.STA_CHIP_MODE_ID,
                 null, // tearDownList
-                null // destroyedListener
+                null, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         verify(chipMock.chip).createRttController(any(), any());
         io.verify(cb).onNewRttController(any());
@@ -537,7 +551,8 @@
                 "wlan0",
                 TestChipV1.STA_CHIP_MODE_ID,
                 null, // tearDownList
-                null // destroyedListener
+                null, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         mInOrder.verify(chipMock.chip, times(0)).createRttController(any(), any());
 
@@ -561,7 +576,8 @@
                 "wlan0",
                 TestChipV1.AP_CHIP_MODE_ID,
                 null, // tearDownList
-                null // destroyedListener
+                null, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         mTestLooper.dispatchAll();
         verify(chipMock.chip, times(2)).createRttController(any(), any()); // but returns a null!
@@ -576,7 +592,8 @@
                 "wlan0",
                 TestChipV1.STA_CHIP_MODE_ID,
                 null, // tearDownList
-                null // destroyedListener
+                null, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         mTestLooper.dispatchAll();
         verify(chipMock.chip, times(3)).createRttController(any(), any());
@@ -612,7 +629,8 @@
                 "wlan0",
                 TestChipV2.CHIP_MODE_ID,
                 null, // tearDownList
-                null // destroyedListener
+                null, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         mInOrder.verify(chipMock.chip, times(0)).createRttController(any(), any());
 
@@ -630,7 +648,8 @@
                 "wlan0",
                 TestChipV2.CHIP_MODE_ID,
                 null, // tearDownList
-                null // destroyedListener
+                null, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         mTestLooper.dispatchAll();
 
@@ -804,7 +823,8 @@
                 name, // ifaceName
                 TestChipV1.AP_CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                idl // destroyedListener
+                idl, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("allocated interface", iface, IsNull.notNullValue());
 
@@ -850,7 +870,7 @@
                 any(IWifiIface.getTypeCallback.class));
         doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, staIface)).when(
                 chipMock.chip).createStaIface(any(IWifiChip.createStaIfaceCallback.class));
-        assertEquals(staIface, mDut.createStaIface(staIdl, null, TEST_WORKSOURCE));
+        assertEquals(staIface, mDut.createStaIface(staIdl, null, TEST_WORKSOURCE_0));
 
         mInOrder.verify(chipMock.chip).configureChip(TestChipV1.STA_CHIP_MODE_ID);
 
@@ -862,7 +882,7 @@
                 any(IWifiIface.getTypeCallback.class));
         doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, apIface)).when(
                 chipMock.chip).createApIface(any(IWifiChip.createApIfaceCallback.class));
-        assertEquals(apIface, mDut.createApIface(apIdl, null, TEST_WORKSOURCE));
+        assertEquals(apIface, mDut.createApIface(apIdl, null, TEST_WORKSOURCE_0));
 
         mInOrder.verify(chipMock.chip).removeStaIface(getName(staIface));
         mInOrder.verify(staIdl).onDestroyed(getName(staIface));
@@ -903,7 +923,8 @@
                 name, // ifaceName
                 TestChipV1.AP_CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                idl // destroyedListener
+                idl, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("allocated interface", iface, IsNull.notNullValue());
 
@@ -919,166 +940,6 @@
     }
 
     /**
-     * Validate AP up/down creation of AP interface when a STA already created. Expect:
-     * - STA created
-     * - P2P created
-     * - When AP requested:
-     *   - STA & P2P torn down
-     *   - AP created
-     * - P2P creation refused
-     * - Request STA: will tear down AP
-     * - When AP destroyed:
-     *   - Get p2p available listener callback
-     *   - Can create P2P when requested
-     * - Create P2P
-     * - Request NAN: will get refused
-     * - Tear down P2P:
-     *    - should get nan available listener callback
-     *    - Can create NAN when requested
-     */
-    @Test
-    public void testCreateSameAndDiffPrioritiesTestChipV1() throws Exception {
-        TestChipV1 chipMock = new TestChipV1();
-        chipMock.initialize();
-        mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
-                mManagerStatusListenerMock);
-        executeAndValidateInitializationSequence();
-        executeAndValidateStartupSequence();
-
-        InterfaceDestroyedListener staDestroyedListener = mock(
-                InterfaceDestroyedListener.class);
-
-        InterfaceDestroyedListener staDestroyedListener2 = mock(
-                InterfaceDestroyedListener.class);
-
-        InterfaceDestroyedListener apDestroyedListener = mock(
-                InterfaceDestroyedListener.class);
-
-        InterfaceDestroyedListener p2pDestroyedListener = mock(
-                InterfaceDestroyedListener.class);
-
-        InterfaceDestroyedListener p2pDestroyedListener2 = mock(
-                InterfaceDestroyedListener.class);
-
-        InterfaceDestroyedListener nanDestroyedListener = mock(
-                InterfaceDestroyedListener.class);
-
-        // Request STA
-        IWifiIface staIface = validateInterfaceSequence(chipMock,
-                false, // chipModeValid
-                -1000, // chipModeId (only used if chipModeValid is true)
-                IfaceType.STA, // ifaceTypeToCreate
-                "wlan0", // ifaceName
-                TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
-                null, // tearDownList
-                staDestroyedListener // destroyedListener
-        );
-        collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
-
-        // request STA2: should fail
-        IWifiIface staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE);
-        collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
-
-        // register additional InterfaceDestroyedListeners - including a duplicate (verify that
-        // only called once!)
-        mDut.registerDestroyedListener(staIface, staDestroyedListener2, mHandler);
-        mDut.registerDestroyedListener(staIface, staDestroyedListener, mHandler);
-
-        // Request P2P
-        IWifiIface p2pIface = validateInterfaceSequence(chipMock,
-                true, // chipModeValid
-                TestChipV1.STA_CHIP_MODE_ID, // chipModeId
-                IfaceType.P2P, // ifaceTypeToCreate
-                "p2p0", // ifaceName
-                TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
-                null, // tearDownList
-                p2pDestroyedListener // destroyedListener
-        );
-        collector.checkThat("allocated P2P interface", p2pIface, IsNull.notNullValue());
-
-        // Request AP
-        IWifiIface apIface = validateInterfaceSequence(chipMock,
-                true, // chipModeValid
-                TestChipV1.STA_CHIP_MODE_ID, // chipModeId
-                IfaceType.AP, // ifaceTypeToCreate
-                "wlan0", // ifaceName
-                TestChipV1.AP_CHIP_MODE_ID, // finalChipMode
-                new IWifiIface[]{staIface, p2pIface}, // tearDownList
-                apDestroyedListener, // destroyedListener
-                // destroyedInterfacesDestroyedListeners...
-                new InterfaceDestroyedListenerWithIfaceName(
-                        getName(staIface), staDestroyedListener),
-                new InterfaceDestroyedListenerWithIfaceName(
-                        getName(staIface), staDestroyedListener2),
-                new InterfaceDestroyedListenerWithIfaceName(
-                        getName(p2pIface), p2pDestroyedListener)
-        );
-        collector.checkThat("allocated AP interface", apIface, IsNull.notNullValue());
-
-        // request AP2: should fail
-        IWifiIface apIface2 = mDut.createApIface(null, null, TEST_WORKSOURCE);
-        collector.checkThat("AP2 should not be created", apIface2, IsNull.nullValue());
-
-        // Request P2P: expect failure
-        p2pIface = mDut.createP2pIface(p2pDestroyedListener, mHandler, TEST_WORKSOURCE);
-        collector.checkThat("P2P can't be created", p2pIface, IsNull.nullValue());
-
-        // Request STA: expect success
-        staIface = validateInterfaceSequence(chipMock,
-                true, // chipModeValid
-                TestChipV1.AP_CHIP_MODE_ID, // chipModeId
-                IfaceType.STA, // ifaceTypeToCreate
-                "wlan0", // ifaceName
-                TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
-                null, // tearDownList
-                staDestroyedListener, // destroyedListener
-                // destroyedInterfacesDestroyedListeners...
-                new InterfaceDestroyedListenerWithIfaceName(
-                        getName(apIface), apDestroyedListener)
-        );
-        collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
-
-        mTestLooper.dispatchAll();
-        verify(apDestroyedListener).onDestroyed(getName(apIface));
-
-        // Request P2P: expect success now
-        p2pIface = validateInterfaceSequence(chipMock,
-                true, // chipModeValid
-                TestChipV1.STA_CHIP_MODE_ID, // chipModeId
-                IfaceType.P2P, // ifaceTypeToCreate
-                "p2p0", // ifaceName
-                TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
-                null, // tearDownList
-                p2pDestroyedListener2 // destroyedListener
-        );
-        collector.checkThat("allocated P2P interface", p2pIface, IsNull.notNullValue());
-
-        // create NAN: will destroy P2P
-        IWifiIface nanIface = validateInterfaceSequence(chipMock,
-                true, // chipModeValid
-                TestChipV1.STA_CHIP_MODE_ID, // chipModeId
-                IfaceType.NAN, // ifaceTypeToCreate
-                "wlan0", // ifaceName
-                TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
-                null, // tearDownList
-                nanDestroyedListener, // destroyedListener
-                new InterfaceDestroyedListenerWithIfaceName("p2p0", p2pDestroyedListener2)
-        );
-        collector.checkThat("allocated NAN interface", nanIface, IsNull.notNullValue());
-
-        // Tear down NAN
-        mDut.removeIface(nanIface);
-        mTestLooper.dispatchAll();
-
-        verify(chipMock.chip, times(1)).removeNanIface("wlan0");
-        verify(nanDestroyedListener).onDestroyed(getName(nanIface));
-
-        verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener,
-                staDestroyedListener2, apDestroyedListener, p2pDestroyedListener,
-                nanDestroyedListener, p2pDestroyedListener2);
-    }
-
-    /**
      * Validate P2P and NAN interactions. Expect:
      * - STA created
      * - NAN created
@@ -1096,11 +957,12 @@
     }
 
     /**
-     * Validates that trying to allocate a STA and then another STA fails. Only one STA at a time
-     * is permitted (by TestChipV1 chip).
+     * Validates that trying to allocate a STA from a lower priority app and then another STA from
+     * a privileged app exists, the request fails. Only one STA at a time is permitted (by
+     * TestChipV1 chip).
      */
     @Test
-    public void testDuplicateStaRequestsTestChipV1() throws Exception {
+    public void testDuplicateStaRequestsFromLowerPriorityAppTestChipV1() throws Exception {
         TestChipV1 chipMock = new TestChipV1();
         chipMock.initialize();
         mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
@@ -1114,7 +976,7 @@
         InterfaceDestroyedListener staDestroyedListener2 = mock(
                 InterfaceDestroyedListener.class);
 
-        // get STA interface
+        // get STA interface (from a privileged app)
         IWifiIface staIface1 = validateInterfaceSequence(chipMock,
                 false, // chipModeValid
                 -1000, // chipModeId (only used if chipModeValid is true)
@@ -1122,13 +984,16 @@
                 "wlan0", // ifaceName
                 TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                staDestroyedListener1 // destroyedListener
+                staDestroyedListener1, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA created", staIface1, IsNull.notNullValue());
 
-        // get STA interface again
+        // get STA interface again (from a system app)
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface staIface2 = mDut.createStaIface(
-                staDestroyedListener2, mHandler, TEST_WORKSOURCE);
+                staDestroyedListener2, mHandler, TEST_WORKSOURCE_1);
         collector.checkThat("STA created", staIface2, IsNull.nullValue());
 
         verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener1,
@@ -1255,7 +1120,9 @@
         executeAndValidateInitializationSequence();
         executeAndValidateStartupSequence();
 
-        // get STA interface
+        // get STA interface from system app.
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper0.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface staIface = validateInterfaceSequence(chipMock,
                 false, // chipModeValid
                 -1000, // chipModeId (only used if chipModeValid is true)
@@ -1263,29 +1130,34 @@
                 "wlan0", // ifaceName
                 TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                mock(InterfaceDestroyedListener.class) // destroyedListener
+                mock(InterfaceDestroyedListener.class), // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA created", staIface, IsNull.notNullValue());
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE));
 
-        // get AP interface
-        IWifiIface apIface = validateInterfaceSequence(chipMock,
-                false, // chipModeValid
-                -1000, // chipModeId (only used if chipModeValid is true)
-                IfaceType.AP, // ifaceTypeToCreate
-                "wlan0", // ifaceName
-                TestChipV1.AP_CHIP_MODE_ID, // finalChipMode
-                null, // tearDownList
-                mock(InterfaceDestroyedListener.class) // destroyedListener
-        );
-        collector.checkThat("AP created", apIface, IsNull.notNullValue());
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE));
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE));
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE));
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE));
+        // FG app not allowed to create AP interface.
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(true);
+        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE_1));
+
+        // New system app not allowed to create AP interface.
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(true);
+        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE_1));
+
+        // Privileged app allowed to create AP interface.
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(true);
+        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE_1));
+
+        // FG app allowed to create NAN interface (since there is no need to delete any interfaces).
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(true);
+        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE_1));
+
+        // BG app allowed to create P2P interface (since there is no need to delete any interfaces).
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(false);
+        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE_1));
     }
 
     //////////////////////////////////////////////////////////////////////////////////////
@@ -1294,18 +1166,19 @@
 
     /**
      * Validate a flow sequence for test chip 2:
-     * - create STA
-     * - create P2P
-     * - request NAN: failure
-     * - create AP
-     * - create STA: will get refused
-     * - create AP: will get refused
+     * - create STA (system app)
+     * - create P2P (system app)
+     * - create NAN (privileged app): should tear down P2P first
+     * - create AP (privileged app)
+     * - create STA (system app): will get refused
+     * - create AP (system app): will get refuse
      * - tear down AP
-     * - create STA
-     * - create STA: will get refused
-     * - create AP: should get created and the last created STA should get destroyed
+     * - create STA (system app)
+     * - create STA (system app): will get refused
+     * - create AP (privileged app): should get created and the last created STA should get
+     *   destroyed
      * - tear down P2P
-     * - create NAN
+     * - create NAN (system app)
      */
     @Test
     public void testInterfaceCreationFlowTestChipV2() throws Exception {
@@ -1330,8 +1203,10 @@
         InterfaceDestroyedListener nanDestroyedListener = mock(
                 InterfaceDestroyedListener.class);
 
-        // create STA
+        // create STA (system app)
         when(mClock.getUptimeSinceBootMillis()).thenReturn(15L);
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper0.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface staIface = validateInterfaceSequence(chipMock,
                 false, // chipModeValid
                 -1000, // chipModeId (only used if chipModeValid is true)
@@ -1339,11 +1214,14 @@
                 "wlan0", // ifaceName
                 TestChipV2.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                staDestroyedListener // destroyedListener
+                staDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA interface wasn't created", staIface, IsNull.notNullValue());
 
-        // create P2P
+        // create P2P (system app)
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface p2pIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV2.CHIP_MODE_ID, // chipModeId
@@ -1351,11 +1229,12 @@
                 "p2p0", // ifaceName
                 TestChipV2.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                p2pDestroyedListener // destroyedListener
+                p2pDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_1 // requestorWs
         );
         collector.checkThat("P2P interface wasn't created", p2pIface, IsNull.notNullValue());
 
-        // create NAN
+        // create NAN (system app)
         IWifiIface nanIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV2.CHIP_MODE_ID, // chipModeId
@@ -1364,12 +1243,13 @@
                 TestChipV2.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
                 nanDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_2, // requestorWs
                 new InterfaceDestroyedListenerWithIfaceName(
                         getName(p2pIface), p2pDestroyedListener)
         );
         collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
 
-        // create AP
+        // create AP (privileged app)
         IWifiIface apIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV2.CHIP_MODE_ID, // chipModeId
@@ -1377,16 +1257,17 @@
                 "wlan1", // ifaceName
                 TestChipV2.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                apDestroyedListener // destroyedListener
+                apDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_2 // requestorWs
         );
         collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
 
-        // request STA2: should fail
-        IWifiIface staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE);
+        // request STA2 (system app): should fail
+        IWifiIface staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
 
-        // request AP2: should fail
-        IWifiIface apIface2 = mDut.createApIface(null, null, TEST_WORKSOURCE);
+        // request AP2 (system app): should fail
+        IWifiIface apIface2 = mDut.createApIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("AP2 should not be created", apIface2, IsNull.nullValue());
 
         // tear down AP
@@ -1396,7 +1277,7 @@
         verify(chipMock.chip).removeApIface("wlan1");
         verify(apDestroyedListener).onDestroyed(getName(apIface));
 
-        // create STA2: using a later clock
+        // create STA2 (system app): using a later clock
         when(mClock.getUptimeSinceBootMillis()).thenReturn(20L);
         staIface2 = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
@@ -1405,15 +1286,16 @@
                 "wlan1", // ifaceName
                 TestChipV2.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                staDestroyedListener2 // destroyedListener
+                staDestroyedListener2, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA 2 interface wasn't created", staIface2, IsNull.notNullValue());
 
-        // request STA3: should fail
-        IWifiIface staIface3 = mDut.createStaIface(null, null, TEST_WORKSOURCE);
+        // request STA3 (system app): should fail
+        IWifiIface staIface3 = mDut.createStaIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("STA3 should not be created", staIface3, IsNull.nullValue());
 
-        // create AP - this will destroy the last STA created, i.e. STA2
+        // create AP (privileged app) - this will destroy the last STA created, i.e. STA2
         apIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV2.CHIP_MODE_ID, // chipModeId
@@ -1422,9 +1304,10 @@
                 TestChipV2.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
                 apDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_2, // requestorWs
                 // destroyedInterfacesDestroyedListeners...
                 new InterfaceDestroyedListenerWithIfaceName(
-                        getName(staIface2), staDestroyedListener2)
+                        getName(staIface), staDestroyedListener)
         );
         collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
 
@@ -1443,7 +1326,8 @@
                 "wlan0", // ifaceName
                 TestChipV2.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                nanDestroyedListener // destroyedListener
+                nanDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
 
@@ -1615,7 +1499,9 @@
         executeAndValidateInitializationSequence();
         executeAndValidateStartupSequence();
 
-        // get STA interface
+        // get STA interface from system app.
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper0.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface staIface = validateInterfaceSequence(chipMock,
                 false, // chipModeValid
                 -1000, // chipModeId (only used if chipModeValid is true)
@@ -1623,29 +1509,49 @@
                 "wlan0", // ifaceName
                 TestChipV2.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                mock(InterfaceDestroyedListener.class) // destroyedListener
+                mock(InterfaceDestroyedListener.class), // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA created", staIface, IsNull.notNullValue());
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE));
 
-        // get AP interface
+        // get AP interface from system app.
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper0.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface apIface = validateInterfaceSequence(chipMock,
-                false, // chipModeValid
-                -1000, // chipModeId (only used if chipModeValid is true)
+                true, // chipModeValid
+                TestChipV2.CHIP_MODE_ID, // chipModeId
                 IfaceType.AP, // ifaceTypeToCreate
                 "wlan0", // ifaceName
                 TestChipV2.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                mock(InterfaceDestroyedListener.class) // destroyedListener
+                mock(InterfaceDestroyedListener.class), // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("AP created", apIface, IsNull.notNullValue());
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE));
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE));
+
+        // FG app not allowed to create STA interface.
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(true);
+        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE_1));
+
+        // New system app not allowed to create STA interface.
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(true);
+        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE_1));
+
+        // Privileged app allowed to create STA interface.
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(true);
+        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE_1));
+
+        // FG app allowed to create NAN interface (since there is no need to delete any interfaces).
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(true);
+        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE_1));
+
+        // BG app allowed to create P2P interface (since there is no need to delete any interfaces).
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(false);
+        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE_1));
     }
 
     //////////////////////////////////////////////////////////////////////////////////////
@@ -1654,18 +1560,18 @@
 
     /**
      * Validate a flow sequence for test chip 3:
-     * - create STA
-     * - create P2P
-     * - request NAN: failure
-     * - create AP: should tear down P2P first
-     * - create STA: will get refused
-     * - create AP: will get refused
-     * - request P2P: failure
+     * - create STA (system app)
+     * - create P2P (system app)
+     * - create NAN (privileged app): should tear down P2P first
+     * - create AP (privileged app): should tear down NAN first
+     * - create STA (system app): will get refused
+     * - create AP (system app): will get refused
+     * - request P2P (system app): failure
      * - tear down AP
-     * - create STA
-     * - create STA: will get refused
-     * - create NAN: should tear down last created STA
-     * - create STA: will get refused
+     * - create STA (system app)
+     * - create STA (system app): will get refused
+     * - create NAN (privileged app): should tear down last created STA
+     * - create STA (foreground app): will get refused
      */
     @Test
     public void testInterfaceCreationFlowTestChipV3() throws Exception {
@@ -1690,8 +1596,10 @@
         InterfaceDestroyedListener nanDestroyedListener = mock(
                 InterfaceDestroyedListener.class);
 
-        // create STA
+        // create STA (system app)
         when(mClock.getUptimeSinceBootMillis()).thenReturn(15L);
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper0.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface staIface = validateInterfaceSequence(chipMock,
                 false, // chipModeValid
                 -1000, // chipModeId (only used if chipModeValid is true)
@@ -1699,11 +1607,14 @@
                 "wlan0", // ifaceName
                 TestChipV3.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                staDestroyedListener // destroyedListener
+                staDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA interface wasn't created", staIface, IsNull.notNullValue());
 
-        // create P2P
+        // create P2P (system app)
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface p2pIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV3.CHIP_MODE_ID, // chipModeId
@@ -1711,11 +1622,12 @@
                 "p2p0", // ifaceName
                 TestChipV3.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                p2pDestroyedListener // destroyedListener
+                p2pDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_1 // requestorWs
         );
         collector.checkThat("P2P interface wasn't created", p2pIface, IsNull.notNullValue());
 
-        // create NAN
+        // create NAN (privileged app): will destroy P2P
         IWifiIface nanIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV3.CHIP_MODE_ID, // chipModeId
@@ -1724,11 +1636,12 @@
                 TestChipV3.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
                 nanDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_2, // requestorWs
                 new InterfaceDestroyedListenerWithIfaceName("p2p0", p2pDestroyedListener)
         );
         collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
 
-        // create AP: will destroy P2P
+        // create AP (privileged app): will destroy NAN
         IWifiIface apIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV3.CHIP_MODE_ID, // chipModeId
@@ -1737,21 +1650,22 @@
                 TestChipV3.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
                 apDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_2, // requestorWs
                 new InterfaceDestroyedListenerWithIfaceName("wlan0", nanDestroyedListener)
         );
         collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
         verify(chipMock.chip).removeP2pIface("p2p0");
 
-        // request STA2: should fail
-        IWifiIface staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE);
+        // request STA2 (system app): s/hould fail
+        IWifiIface staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
 
-        // request AP2: should fail
-        IWifiIface apIface2 = mDut.createApIface(null, null, TEST_WORKSOURCE);
+        // request AP2 (system app): should fail
+        IWifiIface apIface2 = mDut.createApIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("AP2 should not be created", apIface2, IsNull.nullValue());
 
-        // request P2P: should fail
-        p2pIface = mDut.createP2pIface(null, null, TEST_WORKSOURCE);
+        // request P2P (system app): should fail
+        p2pIface = mDut.createP2pIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("P2P should not be created", p2pIface, IsNull.nullValue());
 
         // tear down AP
@@ -1761,7 +1675,7 @@
         verify(chipMock.chip).removeApIface("wlan1");
         verify(apDestroyedListener).onDestroyed(getName(apIface));
 
-        // create STA2: using a later clock
+        // create STA2 (system app): using a later clock
         when(mClock.getUptimeSinceBootMillis()).thenReturn(20L);
         staIface2 = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
@@ -1770,15 +1684,16 @@
                 "wlan1", // ifaceName
                 TestChipV3.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                staDestroyedListener2 // destroyedListener
+                staDestroyedListener2, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA 2 interface wasn't created", staIface2, IsNull.notNullValue());
 
-        // request STA3: should fail
-        IWifiIface staIface3 = mDut.createStaIface(null, null, TEST_WORKSOURCE);
+        // request STA3 (system app): should fail
+        IWifiIface staIface3 = mDut.createStaIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("STA3 should not be created", staIface3, IsNull.nullValue());
 
-        // create NAN: should destroy the last created STA (STA2)
+        // create NAN (privileged app): should destroy the last created STA (STA2)
         nanIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV3.CHIP_MODE_ID, // chipModeId
@@ -1787,16 +1702,19 @@
                 TestChipV3.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
                 nanDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_2, // requestorWs
                 new InterfaceDestroyedListenerWithIfaceName(
-                        getName(staIface2), staDestroyedListener2)
+                        getName(staIface), staDestroyedListener)
         );
         collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
 
-        verify(chipMock.chip).removeStaIface("wlan1");
-        verify(staDestroyedListener2).onDestroyed(getName(staIface2));
+        verify(chipMock.chip).removeStaIface("wlan0");
+        verify(staDestroyedListener).onDestroyed(getName(staIface));
 
-        // request STA2: should fail
-        staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE);
+        // request STA2 (foreground app): should fail
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(true);
+        staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE_1);
         collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
 
         verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener,
@@ -1882,7 +1800,9 @@
         executeAndValidateInitializationSequence();
         executeAndValidateStartupSequence();
 
-        // get STA interface
+        // get STA interface from system app.
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper0.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface staIface = validateInterfaceSequence(chipMock,
                 false, // chipModeValid
                 -1000, // chipModeId (only used if chipModeValid is true)
@@ -1890,29 +1810,49 @@
                 "wlan0", // ifaceName
                 TestChipV3.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                mock(InterfaceDestroyedListener.class) // destroyedListener
+                mock(InterfaceDestroyedListener.class), // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA created", staIface, IsNull.notNullValue());
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE));
 
-        // get AP interface
+        // get AP interface from system app.
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper0.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface apIface = validateInterfaceSequence(chipMock,
-                false, // chipModeValid
-                -1000, // chipModeId (only used if chipModeValid is true)
+                true, // chipModeValid
+                TestChipV3.CHIP_MODE_ID, // chipModeId (only used if chipModeValid is true)
                 IfaceType.AP, // ifaceTypeToCreate
                 "wlan0", // ifaceName
                 TestChipV3.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                mock(InterfaceDestroyedListener.class) // destroyedListener
+                mock(InterfaceDestroyedListener.class), // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("AP created", apIface, IsNull.notNullValue());
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE));
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE));
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE));
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE));
+
+        // FG app not allowed to create STA interface.
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(true);
+        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE_1));
+
+        // New system app not allowed to create STA interface.
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(true);
+        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE_1));
+
+        // Privileged app allowed to create STA interface.
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(true);
+        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE_1));
+
+        // FG app not allowed to create NAN interface.
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(true);
+        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE_1));
+
+        // Privileged app allowed to create P2P interface.
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(true);
+        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE_1));
     }
 
     //////////////////////////////////////////////////////////////////////////////////////
@@ -1921,17 +1861,17 @@
 
     /**
      * Validate a flow sequence for test chip 4:
-     * - create STA
-     * - create P2P
-     * - request NAN: failure
-     * - create AP: should tear down P2P first
-     * - create STA: will get refused
-     * - create AP: will get refused
-     * - request P2P: failure
+     * - create STA (system app)
+     * - create P2P (system app)
+     * - create NAN (privileged app): should tear down P2P first
+     * - create AP (privileged app): should tear down NAN first
+     * - create STA (system app): will get refused
+     * - create AP (system app): will get refused
+     * - request P2P (system app): failure
      * - tear down AP
-     * - create STA: will get refused
-     * - create NAN
-     * - create STA: will get refused
+     * - create STA (system app): will get refused
+     * - create NAN (privileged app)
+     * - create STA (foreground app): will get refused
      */
     @Test
     public void testInterfaceCreationFlowTestChipV4() throws Exception {
@@ -1956,8 +1896,10 @@
         InterfaceDestroyedListener nanDestroyedListener = mock(
                 InterfaceDestroyedListener.class);
 
-        // create STA
+        // create STA (system app)
         when(mClock.getUptimeSinceBootMillis()).thenReturn(15L);
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper0.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface staIface = validateInterfaceSequence(chipMock,
                 false, // chipModeValid
                 -1000, // chipModeId (only used if chipModeValid is true)
@@ -1965,11 +1907,14 @@
                 "wlan0", // ifaceName
                 TestChipV4.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                staDestroyedListener // destroyedListener
+                staDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA interface wasn't created", staIface, IsNull.notNullValue());
 
-        // create P2P
+        // create P2P (system app)
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface p2pIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV4.CHIP_MODE_ID, // chipModeId
@@ -1977,11 +1922,12 @@
                 "p2p0", // ifaceName
                 TestChipV4.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                p2pDestroyedListener // destroyedListener
+                p2pDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("P2P interface wasn't created", p2pIface, IsNull.notNullValue());
 
-        // create NAN: will destroy P2P
+        // create NAN (privileged app): will destroy P2P
         IWifiIface nanIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV4.CHIP_MODE_ID, // chipModeId
@@ -1990,11 +1936,12 @@
                 TestChipV4.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
                 nanDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_2, // requestorWs
                 new InterfaceDestroyedListenerWithIfaceName("p2p0", p2pDestroyedListener)
         );
         collector.checkThat("allocated NAN interface", nanIface, IsNull.notNullValue());
 
-        // create AP: will destroy NAN
+        // create AP (privileged app): will destroy NAN
         IWifiIface apIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV4.CHIP_MODE_ID, // chipModeId
@@ -2003,21 +1950,22 @@
                 TestChipV4.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
                 apDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_2, // requestorWs
                 new InterfaceDestroyedListenerWithIfaceName("wlan0", nanDestroyedListener)
         );
         collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
         verify(chipMock.chip).removeP2pIface("p2p0");
 
-        // request STA2: should fail
-        IWifiIface staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE);
+        // request STA2 (system app): should fail
+        IWifiIface staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
 
-        // request AP2: should fail
-        IWifiIface apIface2 = mDut.createApIface(null, null, TEST_WORKSOURCE);
+        // request AP2 (system app): should fail
+        IWifiIface apIface2 = mDut.createApIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("AP2 should not be created", apIface2, IsNull.nullValue());
 
-        // request P2P: should fail
-        p2pIface = mDut.createP2pIface(null, null, TEST_WORKSOURCE);
+        // request P2P (system app): should fail
+        p2pIface = mDut.createP2pIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("P2P should not be created", p2pIface, IsNull.nullValue());
 
         // tear down AP
@@ -2027,11 +1975,11 @@
         verify(chipMock.chip).removeApIface("wlan1");
         verify(apDestroyedListener).onDestroyed(getName(apIface));
 
-        // request STA2: should fail
-        staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE);
+        // request STA2 (system app): should fail
+        staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE_0);
         collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
 
-        // create NAN
+        // create NAN (privileged app)
         nanIface = validateInterfaceSequence(chipMock,
                 true, // chipModeValid
                 TestChipV4.CHIP_MODE_ID, // chipModeId
@@ -2039,12 +1987,15 @@
                 "wlan0", // ifaceName
                 TestChipV4.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                nanDestroyedListener // destroyedListener
+                nanDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_2 // requestorWs
         );
         collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
 
-        // request STA2: should fail
-        staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE);
+        // request STA2 (foreground app): should fail
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(true);
+        staIface2 = mDut.createStaIface(null, null, TEST_WORKSOURCE_1);
         collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
 
         // tear down STA
@@ -2137,7 +2088,9 @@
         executeAndValidateInitializationSequence();
         executeAndValidateStartupSequence();
 
-        // get STA interface
+        // get STA interface from system app.
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper0.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface staIface = validateInterfaceSequence(chipMock,
                 false, // chipModeValid
                 -1000, // chipModeId (only used if chipModeValid is true)
@@ -2145,29 +2098,49 @@
                 "wlan0", // ifaceName
                 TestChipV4.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                mock(InterfaceDestroyedListener.class) // destroyedListener
+                mock(InterfaceDestroyedListener.class), // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA created", staIface, IsNull.notNullValue());
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE));
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE));
 
-        // get AP interface
+        // get AP interface from system app.
+        when(mWorkSourceHelper0.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper0.hasAnySystemAppRequest()).thenReturn(true);
         IWifiIface apIface = validateInterfaceSequence(chipMock,
-                false, // chipModeValid
-                -1000, // chipModeId (only used if chipModeValid is true)
+                true, // chipModeValid
+                TestChipV4.CHIP_MODE_ID, // chipModeId (only used if chipModeValid is true)
                 IfaceType.AP, // ifaceTypeToCreate
                 "wlan0", // ifaceName
                 TestChipV4.CHIP_MODE_ID, // finalChipMode
                 null, // tearDownList
-                mock(InterfaceDestroyedListener.class) // destroyedListener
+                mock(InterfaceDestroyedListener.class), // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("AP created", apIface, IsNull.notNullValue());
-        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE));
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.AP, TEST_WORKSOURCE));
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE));
-        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE));
+
+        // FG app not allowed to create STA interface.
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(true);
+        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE_1));
+
+        // New system app not allowed to create STA interface.
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(true);
+        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE_1));
+
+        // Privileged app allowed to create STA interface.
+        when(mWorkSourceHelper1.hasAnySystemAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(true);
+        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.STA, TEST_WORKSOURCE_1));
+
+        // FG app not allowed to create NAN interface.
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(false);
+        when(mWorkSourceHelper1.hasAnyForegroundAppRequest()).thenReturn(true);
+        assertFalse(mDut.isItPossibleToCreateIface(IfaceType.NAN, TEST_WORKSOURCE_1));
+
+        // Privileged app allowed to create P2P interface.
+        when(mWorkSourceHelper1.hasAnyPrivilegedAppRequest()).thenReturn(true);
+        assertTrue(mDut.isItPossibleToCreateIface(IfaceType.P2P, TEST_WORKSOURCE_1));
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////
@@ -2251,7 +2224,8 @@
                 ifaceName,
                 finalChipMode,
                 null, // tearDownList
-                idl // destroyedListener
+                idl, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("allocated interface", iface, IsNull.notNullValue());
 
@@ -2320,7 +2294,8 @@
                 "wlan0", // ifaceName
                 onlyChipMode, // finalChipMode
                 null, // tearDownList
-                staDestroyedListener // destroyedListener
+                staDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("STA can't be created", staIface, IsNull.notNullValue());
 
@@ -2332,7 +2307,8 @@
                 "wlan0", // ifaceName
                 onlyChipMode, // finalChipMode
                 null, // tearDownList
-                nanDestroyedListener // destroyedListener
+                nanDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
 
         // Request P2P
@@ -2344,6 +2320,7 @@
                 onlyChipMode, // finalChipMode
                 new IWifiIface[]{nanIface}, // tearDownList
                 p2pDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0, // requestorWs
                 // destroyedInterfacesDestroyedListeners...
                 new InterfaceDestroyedListenerWithIfaceName(
                         getName(nanIface), nanDestroyedListener)
@@ -2360,7 +2337,8 @@
                 "wlan0", // ifaceName
                 onlyChipMode, // finalChipMode
                 new IWifiIface[]{p2pIface}, // tearDownList
-                nanDestroyedListener // destroyedListener
+                nanDestroyedListener, // destroyedListener
+                TEST_WORKSOURCE_0 // requestorWs
         );
         collector.checkThat("NAN can't be created", nanIface, IsNull.notNullValue());
 
@@ -2376,6 +2354,7 @@
             int ifaceTypeToCreate, String ifaceName, int finalChipMode,
             IWifiIface[] tearDownList,
             InterfaceDestroyedListener destroyedListener,
+            WorkSource requestorWs,
             InterfaceDestroyedListenerWithIfaceName...destroyedInterfacesDestroyedListeners)
             throws Exception {
         // configure chip mode response
@@ -2396,7 +2375,7 @@
                 doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when(
                         chipMock.chip).createStaIface(any(IWifiChip.createStaIfaceCallback.class));
 
-                mDut.createStaIface(destroyedListener, mHandler, TEST_WORKSOURCE);
+                mDut.createStaIface(destroyedListener, mHandler, requestorWs);
                 break;
             case IfaceType.AP:
                 iface = mock(IWifiApIface.class);
@@ -2407,7 +2386,7 @@
                 doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when(
                         chipMock.chip).createApIface(any(IWifiChip.createApIfaceCallback.class));
 
-                mDut.createApIface(destroyedListener, mHandler, TEST_WORKSOURCE);
+                mDut.createApIface(destroyedListener, mHandler, requestorWs);
                 break;
             case IfaceType.P2P:
                 iface = mock(IWifiP2pIface.class);
@@ -2418,7 +2397,7 @@
                 doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when(
                         chipMock.chip).createP2pIface(any(IWifiChip.createP2pIfaceCallback.class));
 
-                mDut.createP2pIface(destroyedListener, mHandler, TEST_WORKSOURCE);
+                mDut.createP2pIface(destroyedListener, mHandler, requestorWs);
                 break;
             case IfaceType.NAN:
                 iface = mock(IWifiNanIface.class);
@@ -2429,7 +2408,7 @@
                 doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when(
                         chipMock.chip).createNanIface(any(IWifiChip.createNanIfaceCallback.class));
 
-                mDut.createNanIface(destroyedListener, mHandler, TEST_WORKSOURCE);
+                mDut.createNanIface(destroyedListener, mHandler, requestorWs);
                 break;
         }