Merge "add java_api_finder plugin to tethering module"
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index 4306cf0..0491ad7 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -441,7 +441,8 @@
         }
 
         final Boolean setIfaceUp;
-        if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
+        if (mInterfaceType == TetheringManager.TETHERING_WIFI
+                || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
             // The WiFi stack has ownership of the interface up/down state.
             // It is unclear whether the Bluetooth or USB stacks will manage their own
             // state.
diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 26875b1..5bf41ce 100644
--- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -207,6 +207,7 @@
     private Network mTetherUpstream;
     private TetherStatesParcel mTetherStatesParcel;
     private boolean mDataSaverEnabled = false;
+    private String mWifiP2pTetherInterface = null;
 
     public Tethering(TetheringDependencies deps) {
         mLog.mark("Tethering.constructed");
@@ -852,6 +853,11 @@
             }
         }
 
+        private boolean isGroupOwner(WifiP2pGroup group) {
+            return group != null && group.isGroupOwner()
+                    && !TextUtils.isEmpty(group.getInterface());
+        }
+
         private void handleWifiP2pAction(Intent intent) {
             if (mConfig.isWifiP2pLegacyTetheringMode()) return;
 
@@ -864,24 +870,31 @@
                 Log.d(TAG, "WifiP2pAction: P2pInfo: " + p2pInfo + " Group: " + group);
             }
 
-            if (p2pInfo == null) return;
-            // When a p2p group is disconnected, p2pInfo would be cleared.
-            // group is still valid for detecting whether this device is group owner.
-            if (group == null || !group.isGroupOwner()
-                    || TextUtils.isEmpty(group.getInterface())) return;
-
             synchronized (Tethering.this.mPublicSync) {
-                // Enter below only if this device is Group Owner with a valid interface.
-                if (p2pInfo.groupFormed) {
-                    TetherState tetherState = mTetherStates.get(group.getInterface());
-                    if (tetherState == null
-                            || (tetherState.lastState != IpServer.STATE_TETHERED
-                                && tetherState.lastState != IpServer.STATE_LOCAL_ONLY)) {
-                        enableWifiIpServingLocked(group.getInterface(), IFACE_IP_MODE_LOCAL_ONLY);
-                    }
-                } else {
-                    disableWifiP2pIpServingLocked(group.getInterface());
+                // if no group is formed, bring it down if needed.
+                if (p2pInfo == null || !p2pInfo.groupFormed) {
+                    disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface);
+                    mWifiP2pTetherInterface = null;
+                    return;
                 }
+
+                // If there is a group but the device is not the owner, bail out.
+                if (!isGroupOwner(group)) return;
+
+                // If already serving from the correct interface, nothing to do.
+                if (group.getInterface().equals(mWifiP2pTetherInterface)) return;
+
+                // If already serving from another interface, turn it down first.
+                if (!TextUtils.isEmpty(mWifiP2pTetherInterface)) {
+                    mLog.w("P2P tethered interface " + mWifiP2pTetherInterface
+                            + "is different from current interface "
+                            + group.getInterface() + ", re-tether it");
+                    disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface);
+                }
+
+                // Finally bring up serving on the new interface
+                mWifiP2pTetherInterface = group.getInterface();
+                enableWifiIpServingLocked(mWifiP2pTetherInterface, IFACE_IP_MODE_LOCAL_ONLY);
             }
         }
 
@@ -979,7 +992,9 @@
         disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState);
     }
 
-    private void disableWifiP2pIpServingLocked(String ifname) {
+    private void disableWifiP2pIpServingLockedIfNeeded(String ifname) {
+        if (TextUtils.isEmpty(ifname)) return;
+
         disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
     }
 
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 1f50b6b..f29ad78 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -273,7 +273,7 @@
         dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
         InOrder inOrder = inOrder(mCallback, mNetd);
         inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
-                  IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
+                  IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP)));
         inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
         inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
         inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
@@ -547,4 +547,14 @@
         fail("Missing flag: " + match);
         return false;
     }
+
+    private boolean assertNotContainsFlag(String[] flags, String match) {
+        for (String flag : flags) {
+            if (flag.equals(match)) {
+                fail("Unexpected flag: " + match);
+                return false;
+            }
+        }
+        return true;
+    }
 }
diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index dc40800..affd691 100644
--- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -493,17 +493,21 @@
 
     private void sendWifiP2pConnectionChanged(
             boolean isGroupFormed, boolean isGroupOwner, String ifname) {
+        WifiP2pGroup group = null;
         WifiP2pInfo p2pInfo = new WifiP2pInfo();
         p2pInfo.groupFormed = isGroupFormed;
-        p2pInfo.isGroupOwner = isGroupOwner;
+        if (isGroupFormed) {
+            p2pInfo.isGroupOwner = isGroupOwner;
+            group = mock(WifiP2pGroup.class);
+            when(group.isGroupOwner()).thenReturn(isGroupOwner);
+            when(group.getInterface()).thenReturn(ifname);
+        }
 
-        WifiP2pGroup group = new WifiP2pGroup();
-        group.setIsGroupOwner(isGroupOwner);
-        group.setInterface(ifname);
+        final Intent intent = mock(Intent.class);
+        when(intent.getAction()).thenReturn(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO)).thenReturn(p2pInfo);
+        when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP)).thenReturn(group);
 
-        final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
-        intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo);
-        intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group);
         mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
                 P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
     }