Snap for 9769489 from 1c6e1ae19eb8b5a5182a2d7ee7d8f2d3d795f2c2 to tm-qpr3-release

Change-Id: Iaff6d18b9d53b8e8642bc65eb218126cb1e2229f
diff --git a/src/com/google/android/iwlan/IwlanDataService.java b/src/com/google/android/iwlan/IwlanDataService.java
index ba00b97..a87d6eb 100644
--- a/src/com/google/android/iwlan/IwlanDataService.java
+++ b/src/com/google/android/iwlan/IwlanDataService.java
@@ -921,6 +921,12 @@
         }
 
         @VisibleForTesting
+        @Nullable
+        public MetricsAtom getMetricsAtomByApn(String apnName) {
+            return mMetricsAtomForApn.get(apnName);
+        }
+
+        @VisibleForTesting
         public IwlanTunnelCallback getIwlanTunnelCallback() {
             return mIwlanTunnelCallback;
         }
@@ -1181,6 +1187,9 @@
                         // Record setup result for the Metrics
                         metricsAtom.setSetupRequestResult(DataServiceCallback.RESULT_SUCCESS);
                         metricsAtom.setIwlanError(iwlanError.getErrorType());
+
+                        metricsAtom.setIwlanErrorWrappedClassnameAndStack(iwlanError);
+
                         metricsAtom.setTunnelState(tunnelState.getState());
                         metricsAtom.setMessageId(
                                 IwlanStatsLog.IWLAN_SETUP_DATA_CALL_RESULT_REPORTED);
diff --git a/src/com/google/android/iwlan/proto/MetricsAtom.java b/src/com/google/android/iwlan/proto/MetricsAtom.java
index 33b0fcd..7ecf464 100644
--- a/src/com/google/android/iwlan/proto/MetricsAtom.java
+++ b/src/com/google/android/iwlan/proto/MetricsAtom.java
@@ -16,6 +16,10 @@
 
 package com.google.android.iwlan.proto;
 
+import android.net.ipsec.ike.exceptions.IkeIOException;
+import android.net.ipsec.ike.exceptions.IkeInternalException;
+
+import com.google.android.iwlan.IwlanError;
 import com.google.android.iwlan.IwlanStatsLog;
 
 public class MetricsAtom {
@@ -37,6 +41,8 @@
     private int mHandoverFailureMode;
     private int mRetryDurationMillis;
     private int mWifiSignalValue;
+    private String mIwlanErrorWrappedClassname;
+    private String mIwlanErrorWrappedStackFirstFrame;
 
     public void setMessageId(int messageId) {
         this.mMessageId = messageId;
@@ -110,6 +116,36 @@
         this.mWifiSignalValue = wifiSignalValue;
     }
 
+    public void setIwlanErrorWrappedClassnameAndStack(IwlanError iwlanError) {
+        Throwable iwlanErrorWrapped = iwlanError.getException();
+        if (iwlanErrorWrapped instanceof IkeInternalException
+                || iwlanErrorWrapped instanceof IkeIOException) {
+            iwlanErrorWrapped = iwlanErrorWrapped.getCause();
+        }
+
+        if (iwlanErrorWrapped == null) {
+            this.mIwlanErrorWrappedClassname = null;
+            this.mIwlanErrorWrappedStackFirstFrame = null;
+            return;
+        }
+
+        this.mIwlanErrorWrappedClassname = iwlanErrorWrapped.getClass().getCanonicalName();
+
+        StackTraceElement[] iwlanErrorWrappedStackTraceElements = iwlanErrorWrapped.getStackTrace();
+        this.mIwlanErrorWrappedStackFirstFrame =
+                iwlanErrorWrappedStackTraceElements.length != 0
+                        ? iwlanErrorWrappedStackTraceElements[0].toString()
+                        : null;
+    }
+
+    public String getIwlanErrorWrappedClassname() {
+        return mIwlanErrorWrappedClassname;
+    }
+
+    public String getIwlanErrorWrappedStackFirstFrame() {
+        return mIwlanErrorWrappedStackFirstFrame;
+    }
+
     public void sendMetricsData() {
         if (mMessageId == IwlanStatsLog.IWLAN_SETUP_DATA_CALL_RESULT_REPORTED) {
             IwlanStatsLog.write(
@@ -129,7 +165,9 @@
                     mIkeTunnelEstablishmentDurationMillis,
                     mTunnelState,
                     mHandoverFailureMode,
-                    mRetryDurationMillis);
+                    mRetryDurationMillis,
+                    mIwlanErrorWrappedClassname,
+                    mIwlanErrorWrappedStackFirstFrame);
             return;
         } else if (mMessageId == IwlanStatsLog.IWLAN_PDN_DISCONNECTED_REASON_REPORTED) {
             IwlanStatsLog.write(
diff --git a/test/com/google/android/iwlan/IwlanDataServiceTest.java b/test/com/google/android/iwlan/IwlanDataServiceTest.java
index f67b384..ee416d4 100644
--- a/test/com/google/android/iwlan/IwlanDataServiceTest.java
+++ b/test/com/google/android/iwlan/IwlanDataServiceTest.java
@@ -31,6 +31,7 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.ipsec.ike.exceptions.IkeInternalException;
 import android.os.test.TestLooper;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.DataFailCause;
@@ -56,6 +57,7 @@
 import com.google.android.iwlan.epdg.TunnelLinkProperties;
 import com.google.android.iwlan.epdg.TunnelLinkPropertiesTest;
 import com.google.android.iwlan.epdg.TunnelSetupRequest;
+import com.google.android.iwlan.proto.MetricsAtom;
 
 import org.junit.After;
 import org.junit.Before;
@@ -938,6 +940,114 @@
         mTestLooper.dispatchAll();
     }
 
+    @Test
+    public void testMetricsWhenTunnelClosedWithWrappedException() {
+        DataProfile dp = buildDataProfile();
+
+        mSpyIwlanDataServiceProvider.setTunnelState(
+                dp,
+                mMockDataServiceCallback,
+                TunnelState.TUNNEL_IN_BRINGUP,
+                null, /* linkProperties */
+                false /* isHandover */,
+                1 /* pduSessionId */);
+
+        mSpyIwlanDataServiceProvider.setMetricsAtom(
+                TEST_APN_NAME,
+                64, // type IMS
+                true,
+                13, // LTE
+                false,
+                true,
+                1 // Transport Wi-Fi
+                );
+
+        MetricsAtom metricsAtom = mSpyIwlanDataServiceProvider.getMetricsAtomByApn(TEST_APN_NAME);
+        assertNotNull(metricsAtom);
+
+        String exceptionMessage = "Some exception message";
+        Exception mockException = spy(new IllegalStateException(exceptionMessage));
+        String firstDeclaringClassName = "test.test.TestClass";
+        String firstMethodName = "someMethod";
+        String firstFileName = "TestClass.java";
+        int firstLineNumber = 12345;
+        StackTraceElement[] stackTraceElements = {
+            new StackTraceElement(
+                    firstDeclaringClassName, firstMethodName, firstFileName, firstLineNumber),
+            new StackTraceElement("test", "test", "test.java", 123)
+        };
+        doReturn(stackTraceElements).when(mockException).getStackTrace();
+
+        when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
+                .thenReturn(mMockErrorPolicyManager);
+        when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME)))
+                .thenReturn(DataFailCause.ERROR_UNSPECIFIED);
+
+        mSpyIwlanDataServiceProvider
+                .getIwlanTunnelCallback()
+                .onClosed(TEST_APN_NAME, new IwlanError(new IkeInternalException(mockException)));
+
+        mTestLooper.dispatchAll();
+
+        var expectedStackFirstFrame =
+                firstDeclaringClassName
+                        + "."
+                        + firstMethodName
+                        + "("
+                        + firstFileName
+                        + ":"
+                        + firstLineNumber
+                        + ")";
+
+        assertEquals(
+                mockException.getClass().getCanonicalName(),
+                metricsAtom.getIwlanErrorWrappedClassname());
+
+        assertEquals(expectedStackFirstFrame, metricsAtom.getIwlanErrorWrappedStackFirstFrame());
+    }
+
+    @Test
+    public void testMetricsWhenTunnelClosedWithoutWrappedException() {
+        DataProfile dp = buildDataProfile();
+
+        mSpyIwlanDataServiceProvider.setTunnelState(
+                dp,
+                mMockDataServiceCallback,
+                TunnelState.TUNNEL_IN_BRINGUP,
+                null, /* linkProperties */
+                false /* isHandover */,
+                1 /* pduSessionId */);
+
+        mSpyIwlanDataServiceProvider.setMetricsAtom(
+                TEST_APN_NAME,
+                64, // type IMS
+                true,
+                13, // LTE
+                false,
+                true,
+                1 // Transport Wi-Fi
+                );
+
+        MetricsAtom metricsAtom = mSpyIwlanDataServiceProvider.getMetricsAtomByApn(TEST_APN_NAME);
+        assertNotNull(metricsAtom);
+
+        when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
+                .thenReturn(mMockErrorPolicyManager);
+        when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME)))
+                .thenReturn(DataFailCause.ERROR_UNSPECIFIED);
+
+        mSpyIwlanDataServiceProvider
+                .getIwlanTunnelCallback()
+                .onClosed(
+                        TEST_APN_NAME,
+                        new IwlanError(IwlanError.EPDG_SELECTOR_SERVER_SELECTION_FAILED));
+
+        mTestLooper.dispatchAll();
+
+        assertEquals(null, metricsAtom.getIwlanErrorWrappedClassname());
+        assertEquals(null, metricsAtom.getIwlanErrorWrappedStackFirstFrame());
+    }
+
     private void mockTunnelSetupFail(DataProfile dp) {
         mSpyIwlanDataServiceProvider.setupDataCall(
                 AccessNetworkType.IWLAN, /* AccessNetworkType */