Use direct callback for tethering p2p localonly interface state change

Bug: 263198976
Test: atest com.android.server.wifi.p2p.WifiP2pServiceImplTest
Test: manual test with p2p test app and nearby
Change-Id: I37defe3d8a3ca266548292e494a59328ead40525
Merged-In: I37defe3d8a3ca266548292e494a59328ead40525
diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
index 6434672..22fa00d 100644
--- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
+++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
@@ -41,7 +41,9 @@
 import android.net.MacAddress;
 import android.net.NetworkInfo;
 import android.net.NetworkStack;
+import android.net.TetheringInterface;
 import android.net.TetheringManager;
+import android.net.TetheringManager.TetheringEventCallback;
 import android.net.ip.IIpClient;
 import android.net.ip.IpClientCallbacks;
 import android.net.ip.IpClientUtil;
@@ -216,6 +218,7 @@
     private WifiGlobals mWifiGlobals;
     private UserManager mUserManager;
     private InterfaceConflictManager mInterfaceConflictManager;
+    private TetheringManager mTetheringManager = null;
     private WifiP2pNative mWifiNative;
 
     private static final Boolean JOIN_GROUP = true;
@@ -307,8 +310,8 @@
     private static final int IPC_DHCP_RESULTS               =   BASE + 32;
     private static final int IPC_PROVISIONING_SUCCESS       =   BASE + 33;
     private static final int IPC_PROVISIONING_FAILURE       =   BASE + 34;
-
-    private static final int TETHER_INTERFACE_STATE_CHANGED =   BASE + 35;
+    @VisibleForTesting
+    static final int TETHER_INTERFACE_STATE_CHANGED         =   BASE + 35;
 
     private static final int UPDATE_P2P_DISALLOWED_CHANNELS =   BASE + 36;
 
@@ -649,6 +652,10 @@
     public void handleBootCompleted() {
         updateVerboseLoggingEnabled();
         mIsBootComplete = true;
+        mTetheringManager = mContext.getSystemService(TetheringManager.class);
+        if (mTetheringManager == null) {
+            Log.wtf(TAG, "Tethering manager is null when WifiP2pServiceImp handles boot completed");
+        }
     }
 
     private void updateVerboseLoggingEnabled() {
@@ -1024,6 +1031,21 @@
         private WifiP2pMonitor mWifiMonitor = mWifiInjector.getWifiP2pMonitor();
         private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
         private String mInterfaceName;
+        private TetheringEventCallback mTetheringEventCallback =
+                new TetheringManager.TetheringEventCallback() {
+                    @Override
+                    public void onLocalOnlyInterfacesChanged(Set<TetheringInterface> interfaces) {
+                        ArrayList<String> ifaceList = interfaces.stream().map(
+                                p -> p.getInterface()).collect(
+                                Collectors.toCollection(ArrayList::new));
+                        if (interfaces.stream().anyMatch(
+                                p -> p.getType() == TetheringManager.TETHERING_WIFI_P2P)) {
+                            logd(getName() + " Tethering localOnlyInterfacesChanged"
+                                    + " callback for ifaceList: " + ifaceList);
+                            sendMessage(TETHER_INTERFACE_STATE_CHANGED, ifaceList);
+                        }
+                    }
+                };
 
         private List<CoexUnsafeChannel> mCoexUnsafeChannels = new ArrayList<>();
         private int mUserListenChannel = 0;
@@ -1132,16 +1154,6 @@
                         }
                     }
                 }, new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
-                // Register for tethering state
-                mContext.registerReceiver(new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context context, Intent intent) {
-                        final ArrayList<String> interfaces = intent.getStringArrayListExtra(
-                                TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY);
-
-                        sendMessage(TETHER_INTERFACE_STATE_CHANGED, interfaces);
-                    }
-                }, new IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED));
                 mSettingsConfigStore.registerChangeListener(
                         WIFI_VERBOSE_LOGGING_ENABLED,
                         (key, newValue) -> enableVerboseLogging(newValue),
@@ -2415,6 +2427,10 @@
 
                 sendP2pConnectionChangedBroadcast();
                 initializeP2pSettings();
+                if (mTetheringManager != null) {
+                    mTetheringManager.registerTetheringEventCallback(getHandler()::post,
+                            mTetheringEventCallback);
+                }
             }
 
             @Override
@@ -2817,6 +2833,9 @@
                 mUserListenChannel = 0;
                 mUserOperatingChannel = 0;
                 mCoexUnsafeChannels.clear();
+                if (mTetheringManager != null) {
+                    mTetheringManager.unregisterTetheringEventCallback(mTetheringEventCallback);
+                }
             }
         }
 
diff --git a/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java
index d5f3ea3..a5ff227 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java
@@ -77,6 +77,7 @@
 import android.net.InetAddresses;
 import android.net.MacAddress;
 import android.net.NetworkInfo;
+import android.net.TetheringInterface;
 import android.net.TetheringManager;
 import android.net.wifi.CoexUnsafeChannel;
 import android.net.wifi.ScanResult;
@@ -110,6 +111,7 @@
 import android.os.test.TestLooper;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -162,6 +164,7 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * Unit test harness for WifiP2pServiceImpl.
@@ -200,7 +203,6 @@
 
     private BroadcastReceiver mLocationModeReceiver;
     private BroadcastReceiver mWifiStateChangedReceiver;
-    private BroadcastReceiver mTetherStateReceiver;
     private BroadcastReceiver mUserRestrictionReceiver;
     private Handler mClientHandler;
     private Messenger mP2pStateMachineMessenger;
@@ -219,6 +221,9 @@
     private ArgumentCaptor<Message> mMessageCaptor = ArgumentCaptor.forClass(Message.class);
     private MockitoSession mStaticMockSession = null;
     private Bundle mAttribution = new Bundle();
+    private ArgumentCaptor<TetheringManager.TetheringEventCallback> mTetheringEventCallbackCaptor =
+            ArgumentCaptor.forClass(TetheringManager.TetheringEventCallback.class);
+    private TetheringManager.TetheringEventCallback mTetheringEventCallback;
 
     @Mock Bundle mBundle;
     @Mock Context mContext;
@@ -258,6 +263,7 @@
     @Mock AsyncChannel mAsyncChannel;
     CoexManager.CoexListener mCoexListener;
     @Mock DeviceConfigFacade mDeviceConfigFacade;
+    @Mock TetheringManager mTetheringManager;
 
     private void generatorTestData() {
         mTestWifiP2pGroup = new WifiP2pGroup();
@@ -345,20 +351,11 @@
     /**
      * Simulate tethering flow is completed
      */
-    private void simulateTetherReady() {
-        ArrayList<String> availableList = new ArrayList<>();
-        ArrayList<String> localOnlyList = new ArrayList<>();
-        localOnlyList.add(IFACE_NAME_P2P);
-        ArrayList<String> tetherList = new ArrayList<>();
-        ArrayList<String> erroredList = new ArrayList<>();
-
-        Intent intent = new Intent(TetheringManager.ACTION_TETHER_STATE_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.putStringArrayListExtra(TetheringManager.EXTRA_AVAILABLE_TETHER, availableList);
-        intent.putStringArrayListExtra(TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
-        intent.putStringArrayListExtra(TetheringManager.EXTRA_ACTIVE_TETHER, tetherList);
-        intent.putStringArrayListExtra(TetheringManager.EXTRA_ERRORED_TETHER, erroredList);
-        mTetherStateReceiver.onReceive(mContext, intent);
+    private void simulateTetherReady() throws Exception {
+        mTetheringEventCallback.onLocalOnlyInterfacesChanged(Collections.unmodifiableSet(
+                (new ArraySet(new TetheringInterface[]{
+                        new TetheringInterface(TetheringManager.TETHERING_WIFI_P2P,
+                                IFACE_NAME_P2P)}))));
         mLooper.dispatchAll();
     }
 
@@ -995,6 +992,9 @@
         simulateLocationModeChange(true);
         checkIsP2pInitWhenClientConnected(true, clientBinder,
                 new WorkSource(clientBinder.getCallingUid(), TEST_PACKAGE_NAME));
+        verify(mTetheringManager).registerTetheringEventCallback(any(Executor.class),
+                mTetheringEventCallbackCaptor.capture());
+        mTetheringEventCallback = mTetheringEventCallbackCaptor.getValue();
         verify(mContext).sendBroadcastWithMultiplePermissions(
                 argThat(new WifiP2pServiceImplTest
                        .P2pConnectionChangedIntentMatcherForNetworkState(IDLE)), any());
@@ -1307,25 +1307,24 @@
         when(mCoexManager.getCoexUnsafeChannels()).thenReturn(Collections.emptyList());
         when(mWifiInjector.getDeviceConfigFacade()).thenReturn(mDeviceConfigFacade);
         when(mDeviceConfigFacade.isP2pFailureBugreportEnabled()).thenReturn(false);
+        when(mContext.getSystemService(TetheringManager.class)).thenReturn(mTetheringManager);
 
         mWifiP2pServiceImpl = new WifiP2pServiceImpl(mContext, mWifiInjector);
         if (supported) {
             // register these event:
-            // * WifiManager.WIFI_STATE_CHANGED_ACTION
-            // * LocationManager.MODE_CHANGED_ACTION
-            // * TetheringManager.ACTION_TETHER_STATE_CHANGED
-            // * UserManager.ACTION_USER_RESTRICTIONS_CHANGED
+            // * WifiManager.WIFI_STATE_CHANGED_ACTION        -- always
+            // * LocationManager.MODE_CHANGED_ACTION          -- always
+            // * UserManager.ACTION_USER_RESTRICTIONS_CHANGED -- >= T
             if (SdkLevel.isAtLeastT()) {
-                verify(mContext, times(4)).registerReceiver(mBcastRxCaptor.capture(),
-                        any(IntentFilter.class));
-                mUserRestrictionReceiver = mBcastRxCaptor.getAllValues().get(3);
-            } else {
                 verify(mContext, times(3)).registerReceiver(mBcastRxCaptor.capture(),
                         any(IntentFilter.class));
+                mUserRestrictionReceiver = mBcastRxCaptor.getAllValues().get(2);
+            } else {
+                verify(mContext, times(2)).registerReceiver(mBcastRxCaptor.capture(),
+                        any(IntentFilter.class));
             }
             mWifiStateChangedReceiver = mBcastRxCaptor.getAllValues().get(0);
             mLocationModeReceiver = mBcastRxCaptor.getAllValues().get(1);
-            mTetherStateReceiver = mBcastRxCaptor.getAllValues().get(2);
         }
 
         verify(mWifiPermissionsUtil, never()).isLocationModeEnabled();
@@ -2367,7 +2366,6 @@
         reset(mClientHandler);
 
         sendGroupStartedMsg(mTestWifiP2pGroup);
-        simulateTetherReady();
         sendRequestGroupInfoMsg(mClientMessenger);
         verify(mClientHandler).sendMessage(mMessageCaptor.capture());
         assertEquals(WifiP2pManager.RESPONSE_GROUP_INFO, mMessageCaptor.getValue().what);
@@ -7049,4 +7047,29 @@
         assertEquals(WifiP2pManager.RESPONSE_CONNECTION_INFO, mMessageCaptor.getValue().what);
         assertFalse(((WifiP2pInfo) mMessageCaptor.getValue().obj).groupFormed);
     }
+
+    @Test
+    public void testGroupStartedTetheringDirectCallback() throws Exception {
+        setTargetSdkGreaterThanT();
+        forceP2pEnabled(mClient1);
+        verify(mTetheringManager).registerTetheringEventCallback(any(), any());
+
+        //create/start/remove group
+        when(mWifiNative.p2pGroupAdd(any(), eq(false))).thenReturn(true);
+        sendCreateGroupMsgWithConfigValidAsGroup(mClientMessenger);
+        assertTrue(mClientHandler.hasMessages(WifiP2pManager.CREATE_GROUP_SUCCEEDED));
+        WifiP2pGroup group = new WifiP2pGroup();
+        group.setNetworkName("DIRECT-test");
+        group.setOwner(new WifiP2pDevice("thisDeviceMac"));
+        group.setIsGroupOwner(true);
+        group.setInterface(IFACE_NAME_P2P);
+        sendGroupStartedMsg(group);
+        simulateTetherReady();
+        verify(mWifiP2pMetrics).startGroupEvent(group);
+        sendGroupRemovedMsg();
+
+        //force to back disabled state
+        mockEnterDisabledState();
+        verify(mTetheringManager).unregisterTetheringEventCallback(any());
+    }
 }