Add dump of KeepaliveStatsTracker

To debug unexpected metrics values, print the built metrics into
the connectivity dump.

Sample of the added log dump:
KeepaliveStatsTracker enabled: true
   # android.net.connectivity.com.android.metrics.Dailykeepalive
InfoReported@3293424e
   automatic_keepalive_requests: 2
   distinct_user_count: 1
   duration_per_num_of_keepalive {
     duration_for_num_of_keepalive {
       keepalive_active_durations_msec: 36
       keepalive_registered_durations_msec: 36
       num_of_keepalive: 0
     }
     duration_for_num_of_keepalive {
       keepalive_active_durations_msec: 9
       keepalive_registered_durations_msec: 6
       num_of_keepalive: 1
     }
     duration_for_num_of_keepalive {
       keepalive_active_durations_msec: 7
       keepalive_registered_durations_msec: 10
       num_of_keepalive: 2
     }
   }
   keepalive_lifetime_per_carrier {
     keepalive_lifetime_for_carrier {
       active_lifetime_msec: 23
       carrier_id: -1
       intervals_msec: 10000
       lifetime_msec: 26
       transport_types: 1
     }
   }
   keepalive_requests: 2
   uid: 10097

Bug: 297292877
Test: adb shell dumpsys connectivity
Test: New test testDumpDoesNotCrash()
Change-Id: Ifc076a8dce734e9c175f1b1f28e1c448b9a792e5
diff --git a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
index 11345d3..cda8d06 100644
--- a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
@@ -692,8 +692,10 @@
 
     /**
      * Dump AutomaticOnOffKeepaliveTracker state.
+     * This should be only be called in ConnectivityService handler thread.
      */
     public void dump(IndentingPrintWriter pw) {
+        ensureRunningOnHandlerThread();
         mKeepaliveTracker.dump(pw);
         // Reading DeviceConfig will check if the calling uid and calling package name are the same.
         // Clear calling identity to align the calling uid and package so that it won't fail if cts
@@ -712,6 +714,9 @@
         pw.increaseIndent();
         mEventLog.reverseDump(pw);
         pw.decreaseIndent();
+
+        pw.println();
+        mKeepaliveStatsTracker.dump(pw);
     }
 
     /**
diff --git a/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java b/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java
index 0c2ed18..35c4909 100644
--- a/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java
+++ b/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java
@@ -34,6 +34,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -727,6 +728,15 @@
         mDependencies.writeStats(dailyKeepaliveInfoReported);
     }
 
+    /** Dump KeepaliveStatsTracker state. */
+    public void dump(IndentingPrintWriter pw) {
+        ensureRunningOnHandlerThread();
+        pw.println("KeepaliveStatsTracker enabled: " + isEnabled());
+        pw.increaseIndent();
+        pw.println(buildKeepaliveMetrics().toString());
+        pw.decreaseIndent();
+    }
+
     private void ensureRunningOnHandlerThread() {
         if (mConnectivityServiceHandler.getLooper().getThread() != Thread.currentThread()) {
             throw new IllegalStateException(
diff --git a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
index 986c389..8e19c01 100644
--- a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
@@ -77,6 +77,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker.AutomaticOnOffKeepalive;
 import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
 import com.android.testutils.DevSdkIgnoreRule;
@@ -94,6 +95,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.io.FileDescriptor;
+import java.io.StringWriter;
 import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.net.Socket;
@@ -974,4 +976,19 @@
         // The keepalive should be removed in AutomaticOnOffKeepaliveTracker.
         assertNull(getAutoKiForBinder(testInfo.binder));
     }
+
+    @Test
+    public void testDumpDoesNotCrash() throws Exception {
+        final TestKeepaliveInfo testInfo1 = doStartNattKeepalive();
+        final TestKeepaliveInfo testInfo2 = doStartNattKeepalive();
+        checkAndProcessKeepaliveStart(TEST_SLOT, testInfo1.kpd);
+        checkAndProcessKeepaliveStart(TEST_SLOT + 1, testInfo2.kpd);
+        final AutomaticOnOffKeepalive autoKi1  = getAutoKiForBinder(testInfo1.binder);
+        doPauseKeepalive(autoKi1);
+
+        final StringWriter stringWriter = new StringWriter();
+        final IndentingPrintWriter pw = new IndentingPrintWriter(stringWriter, "   ");
+        visibleOnHandlerThread(mTestHandler, () -> mAOOKeepaliveTracker.dump(pw));
+        assertFalse(stringWriter.toString().isEmpty());
+    }
 }