Snap for 8642511 from adc4d719111d5703b57e9896ef2f003dd2e46343 to tm-release

Change-Id: I632c48a4bc989731d3a2475005030a9c9c475222
diff --git a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java
index 7df872f..ea78893 100644
--- a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java
+++ b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java
@@ -22,6 +22,7 @@
 import static android.system.OsConstants.AF_INET6;
 
 import android.content.Context;
+import android.net.ConnectivityManager;
 import android.net.InetAddresses;
 import android.net.IpPrefix;
 import android.net.IpSecManager;
@@ -113,6 +114,7 @@
     private static final int EVENT_IPSEC_TRANSFORM_DELETED = 8;
     private static final int EVENT_UPDATE_NETWORK = 9;
     private static final int EVENT_IKE_SESSION_OPENED = 10;
+    private static final int EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED = 11;
     private static final int IKE_HARD_LIFETIME_SEC_MINIMUM = 300;
     private static final int IKE_HARD_LIFETIME_SEC_MAXIMUM = 86400;
     private static final int IKE_SOFT_LIFETIME_SEC_MINIMUM = 120;
@@ -481,14 +483,17 @@
         @Override
         public void onIkeSessionConnectionInfoChanged(
                 IkeSessionConnectionInfo ikeSessionConnectionInfo) {
-            Log.d(TAG, "Ike session connection info changed for apn: " + mApnName);
-            TunnelConfig tunnelConfig = mApnNameToTunnelConfig.get(mApnName);
-            IpSecManager.IpSecTunnelInterface tunnelInterface = tunnelConfig.getIface();
-            try {
-                tunnelInterface.setUnderlyingNetwork(ikeSessionConnectionInfo.getNetwork());
-            } catch (IOException e) {
-                Log.e(TAG, "IOException while updating underlying network for apn: " + mApnName);
-            }
+            Network network = ikeSessionConnectionInfo.getNetwork();
+            Log.d(
+                    TAG,
+                    "Ike session connection info changed for apn: "
+                            + mApnName
+                            + " Network: "
+                            + network);
+            mHandler.sendMessage(
+                    mHandler.obtainMessage(
+                            EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED,
+                            new IkeSessionConnectionInfoData(mApnName, ikeSessionConnectionInfo)));
         }
     }
 
@@ -1577,6 +1582,34 @@
                         }
                     }
                     break;
+
+                case EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED:
+                    IkeSessionConnectionInfoData ikeSessionConnectionInfoData =
+                            (IkeSessionConnectionInfoData) msg.obj;
+                    network = ikeSessionConnectionInfoData.mIkeSessionConnectionInfo.getNetwork();
+                    apnName = ikeSessionConnectionInfoData.mApnName;
+
+                    ConnectivityManager connectivityManager =
+                            mContext.getSystemService(ConnectivityManager.class);
+                    if (connectivityManager.getLinkProperties(network) == null) {
+                        Log.e(TAG, "Network " + network + " has null LinkProperties!");
+                        return;
+                    }
+
+                    tunnelConfig = mApnNameToTunnelConfig.get(apnName);
+                    tunnelInterface = tunnelConfig.getIface();
+                    try {
+                        tunnelInterface.setUnderlyingNetwork(network);
+                    } catch (IOException | IllegalArgumentException e) {
+                        Log.e(
+                                TAG,
+                                "Failed to update underlying network for apn: "
+                                        + apnName
+                                        + " exception: "
+                                        + e);
+                    }
+                    break;
+
                 default:
                     throw new IllegalStateException("Unexpected value: " + msg.what);
             }
@@ -1804,6 +1837,17 @@
         }
     }
 
+    private static final class IkeSessionConnectionInfoData {
+        final String mApnName;
+        final IkeSessionConnectionInfo mIkeSessionConnectionInfo;
+
+        private IkeSessionConnectionInfoData(
+                String apnName, IkeSessionConnectionInfo ikeSessionConnectionInfo) {
+            mApnName = apnName;
+            mIkeSessionConnectionInfo = ikeSessionConnectionInfo;
+        }
+    }
+
     // Data received from IkeSessionStateMachine if either IKE session or Child session have been
     // closed, normally or exceptionally.
     private static final class SessionClosedData {
diff --git a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java
index 2386ccd..f2cba73 100644
--- a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java
+++ b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java
@@ -28,10 +28,12 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.net.ConnectivityManager;
 import android.net.InetAddresses;
 import android.net.IpSecManager;
 import android.net.IpSecTransform;
 import android.net.LinkAddress;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.ipsec.ike.ChildSessionCallback;
 import android.net.ipsec.ike.ChildSessionConfiguration;
@@ -40,6 +42,7 @@
 import android.net.ipsec.ike.IkeSession;
 import android.net.ipsec.ike.IkeSessionCallback;
 import android.net.ipsec.ike.IkeSessionConfiguration;
+import android.net.ipsec.ike.IkeSessionConnectionInfo;
 import android.net.ipsec.ike.IkeSessionParams;
 import android.net.ipsec.ike.SaProposal;
 import android.net.ipsec.ike.TunnelModeChildSessionParams;
@@ -132,6 +135,7 @@
     @Mock private EpdgSelector mMockEpdgSelector;
     @Mock private Network mMockNetwork;
     @Mock CarrierConfigManager mMockCarrierConfigManager;
+    @Mock ConnectivityManager mMockConnectivityManager;
     @Mock SubscriptionManager mMockSubscriptionManager;
     @Mock SubscriptionInfo mMockSubscriptionInfo;
     @Mock TelephonyManager mMockTelephonyManager;
@@ -141,8 +145,10 @@
     @Mock IkeSessionConfiguration mMockIkeSessionConfiguration;
     @Mock ChildSessionConfiguration mMockChildSessionConfiguration;
     @Mock IpSecManager.IpSecTunnelInterface mMockIpSecTunnelInterface;
+    @Mock IkeSessionConnectionInfo mMockIkeSessionConnectionInfo;
     @Mock IpSecTransform mMockedIpSecTransformIn;
     @Mock IpSecTransform mMockedIpSecTransformOut;
+    @Mock LinkProperties mMockLinkProperties;
 
     ArgumentCaptor<ChildSessionCallback> mChildSessionCallbackCaptor;
 
@@ -184,6 +190,8 @@
 
         when(mMockIpSecTunnelInterface.getInterfaceName()).thenReturn("wlan0");
 
+        when(mMockIkeSessionConnectionInfo.getNetwork()).thenReturn(mMockNetwork);
+
         mChildSessionCallbackCaptor = ArgumentCaptor.forClass(ChildSessionCallback.class);
 
         doReturn(EXPECTED_LOCAL_ADDRESSES)
@@ -1008,6 +1016,8 @@
                 });
         when(mMockContext.getSystemService(eq(CarrierConfigManager.class)))
                 .thenReturn(mMockCarrierConfigManager);
+        when(mMockContext.getSystemService(eq(ConnectivityManager.class)))
+                .thenReturn(mMockConnectivityManager);
         when(mMockContext.getSystemService(eq(SubscriptionManager.class)))
                 .thenReturn(mMockSubscriptionManager);
         when(mMockContext.getSystemService(eq(TelephonyManager.class)))
@@ -1286,6 +1296,43 @@
     }
 
     @Test
+    public void testIkeSessionConnectionInfoChangedSetsUnderlyingNetwork() throws Exception {
+        String testApnName = "ims";
+        when(mMockConnectivityManager.getLinkProperties(any())).thenReturn(mMockLinkProperties);
+
+        ChildSessionCallback childSessionCallback =
+                verifyBringUpTunnelWithDnsQuery(testApnName, mMockIkeSession);
+        childSessionCallback.onIpSecTransformCreated(
+                mMockedIpSecTransformIn, IpSecManager.DIRECTION_IN);
+
+        mEpdgTunnelManager
+                .getTmIkeSessionCallback(testApnName)
+                .onIkeSessionConnectionInfoChanged(mMockIkeSessionConnectionInfo);
+        mTestLooper.dispatchAll();
+
+        verify(mMockIpSecTunnelInterface, times(1)).setUnderlyingNetwork(mMockNetwork);
+    }
+
+    @Test
+    public void testIkeSessionConnectionInfoChangedWithNullLinkPropertiesDoesNothing()
+            throws Exception {
+        String testApnName = "ims";
+        when(mMockConnectivityManager.getLinkProperties(any())).thenReturn(null);
+
+        ChildSessionCallback childSessionCallback =
+                verifyBringUpTunnelWithDnsQuery(testApnName, mMockIkeSession);
+        childSessionCallback.onIpSecTransformCreated(
+                mMockedIpSecTransformIn, IpSecManager.DIRECTION_IN);
+
+        mEpdgTunnelManager
+                .getTmIkeSessionCallback(testApnName)
+                .onIkeSessionConnectionInfoChanged(mMockIkeSessionConnectionInfo);
+        mTestLooper.dispatchAll();
+
+        verify(mMockIpSecTunnelInterface, times(0)).setUnderlyingNetwork(any());
+    }
+
+    @Test
     public void testSetIkeTrafficSelectorsIPv4() throws Exception {
         testSetIkeTrafficSelectors(ApnSetting.PROTOCOL_IP, false);
     }