[Aware] Fix the offloading transition for device does not support FW priority

Bug: 266092994
Test: atest com.android.server.wifi, SingleDeviceTest
Change-Id: Ie8b17696a7f49e95cd357810ecd1f30c2e9e0592
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
index f772cc1..e8e5f87 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
@@ -287,6 +287,8 @@
             "bootstrapping_request_id";
     private static final String MESSAGE_BUNDLE_KEY_BOOTSTRAPPING_ACCEPT = "bootstrapping_accept";
     private static final String MESSAGE_BUNDLE_KEY_AWARE_OFFLOAD = "aware_offload";
+    private static final String MESSAGE_BUNDLE_KEY_RE_ENABLE_AWARE_FROM_OFFLOAD =
+            "aware_re_enable_from_offload";
 
 
     private WifiAwareNativeApi mWifiAwareNativeApi;
@@ -1018,10 +1020,14 @@
             @Nullable String callingFeatureId, IWifiAwareEventCallback callback,
             ConfigRequest configRequest, boolean notifyOnIdentityChanged, Bundle extra,
             boolean forAwareOffload) {
+        boolean reEnableAware = false;
+        // If FW could not handle the Aware request priority, disable the Aware first
         if (!mContext.getResources()
                 .getBoolean(R.bool.config_wifiAwareOffloadingFirmwareHandlePriority)
                 && isAwareOffloading() && !forAwareOffload) {
-            deferDisableAware();
+            // Do not release Aware, as new request will get Interface again
+            deferDisableAware(false);
+            reEnableAware = true;
         }
         Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND);
         msg.arg1 = COMMAND_TYPE_CONNECT;
@@ -1036,7 +1042,9 @@
                 notifyOnIdentityChanged);
         msg.getData().putBundle(MESSAGE_BUNDLE_KEY_ATTRIBUTION_SOURCE, extra);
         msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_AWARE_OFFLOAD, forAwareOffload);
+        msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_RE_ENABLE_AWARE_FROM_OFFLOAD, reEnableAware);
         mSm.sendMessage(msg);
+        // Clean the client after the connect to avoid Aware disable
         if (!forAwareOffload) {
             for (int i = 0; i < mClients.size(); i++) {
                 WifiAwareClientState clientState = mClients.valueAt(i);
@@ -1060,11 +1068,13 @@
 
     /**
      * Place a request to defer Disable Aware on the state machine queue.
+     * @param releaseAware
      */
-    private void deferDisableAware() {
+    private void deferDisableAware(boolean releaseAware) {
         mAwareIsDisabling = true;
         Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND);
         msg.arg1 = COMMAND_TYPE_DISABLE;
+        msg.obj = releaseAware;
         mSm.sendMessage(msg);
     }
 
@@ -2461,6 +2471,8 @@
                             MESSAGE_BUNDLE_KEY_NOTIFY_IDENTITY_CHANGE);
                     boolean awareOffload = msg.getData().getBoolean(
                             MESSAGE_BUNDLE_KEY_AWARE_OFFLOAD);
+                    boolean reEnableAware = msg.getData()
+                            .getBoolean(MESSAGE_BUNDLE_KEY_RE_ENABLE_AWARE_FROM_OFFLOAD);
                     WorkSource workSource;
                     if (awareOffload) {
                         workSource = new WorkSource(Process.WIFI_UID);
@@ -2492,7 +2504,7 @@
                                 callingPackage, callingFeatureId, callback, configRequest,
                                 notifyIdentityChange,
                                 msg.getData().getBundle(MESSAGE_BUNDLE_KEY_ATTRIBUTION_SOURCE),
-                                awareOffload);
+                                awareOffload, reEnableAware);
                     } else { // InterfaceConflictManager.ICM_SKIP_COMMAND_WAIT_FOR_USER
                         waitForResponse = false;
                     }
@@ -3295,11 +3307,14 @@
     private boolean connectLocal(short transactionId, int clientId, int uid, int pid,
             String callingPackage, @Nullable String callingFeatureId,
             IWifiAwareEventCallback callback, ConfigRequest configRequest,
-            boolean notifyIdentityChange, Bundle extra, boolean awareOffload) {
+            boolean notifyIdentityChange, Bundle extra, boolean awareOffload,
+            boolean reEnableAware) {
         mLocalLog.log("connectLocal(): transactionId=" + transactionId + ", clientId=" + clientId
                 + ", uid=" + uid + ", pid=" + pid + ", callingPackage=" + callingPackage
                 + ", callback=" + callback + ", configRequest=" + configRequest
-                + ", notifyIdentityChange=" + notifyIdentityChange);
+                + ", notifyIdentityChange=" + notifyIdentityChange
+                + ", awareOffload" + awareOffload
+                + ", reEnableAware" + reEnableAware);
 
         if (!mUsageEnabled) {
             Log.w(TAG, "connect(): called with mUsageEnabled=false");
@@ -3337,7 +3352,8 @@
         }
 
         if (mCurrentAwareConfiguration != null && mCurrentAwareConfiguration.equals(merged)
-                && (mCurrentIdentityNotification || !notifyIdentityChange)) {
+                && (mCurrentIdentityNotification || !notifyIdentityChange)
+                && !reEnableAware) {
             if (awareOffload && !isAwareOffloading()) {
                 try {
                     mLocalLog.log("Connect failure for clientId:" + clientId);
@@ -3387,9 +3403,10 @@
             }
             mWifiAwareNativeManager.tryToGetAware(workSource);
         }
-
+        boolean initialConfiguration = mCurrentAwareConfiguration == null
+                || reEnableAware;
         boolean success = mWifiAwareNativeApi.enableAndConfigure(transactionId, merged,
-                notificationRequired, mCurrentAwareConfiguration == null,
+                notificationRequired, initialConfiguration,
                 mPowerManager.isInteractive(), mPowerManager.isDeviceIdleMode(),
                 rangingRequired, enableInstantMode, instantModeChannel, mClusterIdInt);
         if (!success) {
@@ -3432,7 +3449,7 @@
             mCurrentRangingEnabled = false;
             mCurrentIdentityNotification = false;
             mInstantCommModeClientRequest = INSTANT_MODE_DISABLED;
-            deferDisableAware();
+            deferDisableAware(true);
             return false;
         }
 
@@ -3777,7 +3794,7 @@
         mCurrentRangingEnabled = false;
         mCurrentIdentityNotification = false;
         mInstantCommModeClientRequest = INSTANT_MODE_DISABLED;
-        deferDisableAware();
+        deferDisableAware(true);
         sendAwareStateChangedBroadcast(markAsAvailable);
         if (!markAsAvailable) {
             mAwareMetrics.recordDisableUsage();
@@ -3948,7 +3965,12 @@
             Log.e(TAG, "onDisableResponseLocal: FAILED!? command=" + command + ", reason="
                     + reason);
         }
-        mWifiAwareNativeManager.releaseAware();
+
+        boolean releaseAware = (boolean) command.obj;
+        if (releaseAware) {
+            // Need to release Aware
+            mWifiAwareNativeManager.releaseAware();
+        }
         mAwareMetrics.recordDisableAware();
     }
 
diff --git a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
index b857fa8..30cf8b8 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
@@ -43,6 +43,7 @@
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -209,7 +210,6 @@
         mResources = new MockResources();
         mResources.setInteger(R.integer.config_wifiAwareInstantCommunicationModeDurationMillis,
                 30000);
-        mResources.setBoolean(R.bool.config_wifiAwareOffloadingFirmwareHandlePriority, true);
         when(mMockContext.getResources()).thenReturn(mResources);
 
         when(mInterfaceConflictManager.manageInterfaceConflictForStateMachine(any(), any(), any(),
@@ -5235,7 +5235,8 @@
      * that IdentityChanged not delivered if configuration disables delivery.
      */
     @Test
-    public void testAwareWithOffloading() throws Exception {
+    public void testAwareWithOffloadingWithFwHandlePriority() throws Exception {
+        mResources.setBoolean(R.bool.config_wifiAwareOffloadingFirmwareHandlePriority, true);
         final int clientId1 = 1005;
         final int clientId2 = 1007;
         final int clusterLow = 5;
@@ -5274,10 +5275,84 @@
 
         // (2) connect Aware session for App
         mDut.connect(clientId2, uid, pid, callingPackage, callingFeature, mockCallback2,
-                configRequest, true, mExtras, false);
+                configRequest, false, mExtras, false);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback2).onConnectSuccess(clientId2);
+        // Session for offloading should be terminated.
+        inOrder.verify(mockCallback1).onAttachTerminate();
+
+        // (3) connect Aware session for offloading again - should reject
+        mDut.connect(clientId1, uid, pid, callingPackage, callingFeature, mockCallback1,
+                configRequest, false, mExtras, true);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback1).onConnectFail(anyInt());
+
+        // (6) Aware down - session should be terminated.
+        mDut.onAwareDownNotification(reason);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback2).onAttachTerminate();
+
+        validateInternalClientInfoCleanedUp(clientId1);
+        validateInternalClientInfoCleanedUp(clientId2);
+
+        verifyNoMoreInteractions(mockCallback1, mockCallback2, mMockNative);
+    }
+
+    /**
+     * Validates that all events are delivered with correct arguments. Validates
+     * that IdentityChanged not delivered if configuration disables delivery.
+     */
+    @Test
+    public void testAwareWithOffloadingWithoutFwHandlePriority() throws Exception {
+        mResources.setBoolean(R.bool.config_wifiAwareOffloadingFirmwareHandlePriority, false);
+        final int clientId1 = 1005;
+        final int clientId2 = 1007;
+        final int clusterLow = 5;
+        final int clusterHigh = 100;
+        final int masterPref = 111;
+        final int uid = 1000;
+        final int pid = 2000;
+        final String callingPackage = "com.google.somePackage";
+        final String callingFeature = "com.google.someFeature";
+        final int reason = NanStatusCode.INTERNAL_FAILURE;
+
+        ConfigRequest configRequest = new ConfigRequest.Builder().setClusterLow(clusterLow)
+                .setClusterHigh(clusterHigh).setMasterPreference(masterPref)
+                .build();
+
+        IWifiAwareEventCallback mockCallback1 = mock(IWifiAwareEventCallback.class);
+        IWifiAwareEventCallback mockCallback2 = mock(IWifiAwareEventCallback.class);
+        ArgumentCaptor<Short> transactionIdCapture = ArgumentCaptor.forClass(Short.class);
+        InOrder inOrder = inOrder(mockCallback1, mockCallback2, mMockNative);
+
+        mDut.enableUsage();
+        mMockLooper.dispatchAll();
+        inOrder.verify(mMockNative).getCapabilities(transactionIdCapture.capture());
+        reset(mMockNativeManager);
+
+        // (1) connect Aware session for offloading
+        mDut.connect(clientId1, uid, pid, callingPackage, callingFeature, mockCallback1,
+                configRequest, false, mExtras, true);
         mMockLooper.dispatchAll();
         inOrder.verify(mMockNative).enableAndConfigure(transactionIdCapture.capture(),
-                eq(configRequest), eq(true), eq(false), eq(true), eq(false), eq(false), eq(false),
+                eq(configRequest), eq(false), eq(true), eq(true), eq(false), eq(false), eq(false),
+                anyInt(), anyInt());
+        short transactionId = transactionIdCapture.getValue();
+        mDut.onConfigSuccessResponse(transactionId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback1).onConnectSuccess(clientId1);
+
+        // (2) connect Aware session for App
+        mDut.connect(clientId2, uid, pid, callingPackage, callingFeature, mockCallback2,
+                configRequest, true, mExtras, false);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mMockNative).disable(transactionIdCapture.capture());
+        mDut.onDisableResponse(transactionIdCapture.getValue(), NanStatusCode.SUCCESS);
+        mMockLooper.dispatchAll();
+        verify(mMockNativeManager, never()).releaseAware();
+        mMockLooper.dispatchAll();
+        inOrder.verify(mMockNative).enableAndConfigure(transactionIdCapture.capture(),
+                eq(configRequest), eq(true), eq(true), eq(true), eq(false), eq(false), eq(false),
                 anyInt(), anyInt());
         transactionId = transactionIdCapture.getValue();
         mDut.onConfigSuccessResponse(transactionId);