Add carrier ID to telecom metrics proto

Add the carrier ID so it can be used in server-side aggregation

Bug: 119153703
Test: unit, manual
Change-Id: I10212411741850169ecb7712f60b2275620b3943
(cherry picked from commit e3fc38d188f6061427e8d2341370366838ba21ff)
diff --git a/proto/telecom.proto b/proto/telecom.proto
index 2f4fae8..73eba87 100644
--- a/proto/telecom.proto
+++ b/proto/telecom.proto
@@ -16,6 +16,9 @@
 
   // Hardware revision (EVT, DVT, PVT etc.)
   optional string hardware_revision = 3;
+
+  // Carrier ID that the device is associated to
+  optional int32 carrier_id = 4;
 }
 
 message LogSessionTiming {
diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java
index 1d3a90e..2997454 100644
--- a/src/com/android/server/telecom/Analytics.java
+++ b/src/com/android/server/telecom/Analytics.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom;
 
+import android.content.Context;
 import android.os.SystemProperties;
 
 import android.telecom.Connection;
@@ -23,6 +24,8 @@
 import android.telecom.Logging.EventManager;
 import android.telecom.ParcelableCallAnalytics;
 import android.telecom.TelecomAnalytics;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.util.Base64;
 import android.telecom.Log;
 
@@ -37,10 +40,12 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.PriorityQueue;
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.stream.Collectors;
@@ -628,7 +633,7 @@
         return new TelecomAnalytics(sessionTimings, calls);
     }
 
-    public static void dumpToEncodedProto(PrintWriter pw, String[] args) {
+    public static void dumpToEncodedProto(Context context, PrintWriter pw, String[] args) {
         TelecomLogClass.TelecomLog result = new TelecomLogClass.TelecomLog();
 
         synchronized (sLock) {
@@ -642,6 +647,7 @@
                             .setTimeMillis(timing.getTime()))
                     .toArray(TelecomLogClass.LogSessionTiming[]::new);
             result.setHardwareRevision(SystemProperties.get("ro.boot.revision", ""));
+            result.setCarrierId(getCarrierId(context));
             if (args.length > 1 && CLEAR_ANALYTICS_ARG.equals(args[1])) {
                 sCallIdToInfo.clear();
                 sSessionTimings.clear();
@@ -652,6 +658,29 @@
         pw.write(encodedProto);
     }
 
+    private static int getCarrierId(Context context) {
+        SubscriptionManager subscriptionManager =
+                context.getSystemService(SubscriptionManager.class);
+        List<SubscriptionInfo> subInfos = subscriptionManager.getActiveSubscriptionInfoList();
+        if (subInfos == null) {
+            return -1;
+        }
+        return subInfos.stream()
+                .max(Comparator.comparing(Analytics::scoreSubscriptionInfo))
+                .map(SubscriptionInfo::getCarrierId).orElse(-1);
+    }
+
+    // Copied over from Telephony's server-side logic for consistency
+    private static int scoreSubscriptionInfo(SubscriptionInfo subInfo) {
+        final int scoreCarrierId = 0b100;
+        final int scoreNotOpportunistic = 0b010;
+        final int scoreSlot0 = 0b001;
+
+        return ((subInfo.getCarrierId() >= 0) ? scoreCarrierId : 0)
+                + (subInfo.isOpportunistic() ? 0 : scoreNotOpportunistic)
+                + ((subInfo.getSimSlotIndex() == 0) ? scoreSlot0 : 0);
+    }
+
     public static void dump(IndentingPrintWriter writer) {
         synchronized (sLock) {
             int prefixLength = CallsManager.TELECOM_CALL_ID_PREFIX.length();
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 8bf42a8..e8030c8 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -1376,10 +1376,13 @@
                 return;
             }
 
+
             if (args.length > 0 && Analytics.ANALYTICS_DUMPSYS_ARG.equals(args[0])) {
-                Analytics.dumpToEncodedProto(writer, args);
+                Binder.withCleanCallingIdentity(() ->
+                        Analytics.dumpToEncodedProto(mContext, writer, args));
                 return;
             }
+
             boolean isTimeLineView = (args.length > 0 && TIME_LINE_ARG.equalsIgnoreCase(args[0]));
 
             final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
index 1fad3f7..ec5f7ba 100644
--- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -25,6 +25,7 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.os.Build;
@@ -39,6 +40,8 @@
 import android.telecom.TelecomManager;
 import android.telecom.VideoCallImpl;
 import android.telecom.VideoProfile;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Base64;
@@ -60,6 +63,7 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -70,10 +74,16 @@
 
 @RunWith(JUnit4.class)
 public class AnalyticsTests extends TelecomSystemTest {
+    private SubscriptionManager mSubscriptionManager;
+
     @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
+        // this is a mock
+        mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList())
+                .thenReturn(Collections.emptyList());
     }
 
     @Override
@@ -253,7 +263,7 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
@@ -300,6 +310,7 @@
     @Test
     public void testAnalyticsDumpToProto() throws Exception {
         Analytics.reset();
+        setupCarrierIds();
         IdPair testCall = startAndMakeActiveIncomingCall(
                 "650-555-1212",
                 mPhoneAccountA0.getAccountHandle(),
@@ -311,10 +322,11 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
+        assertEquals(1, analyticsProto.getCarrierId());
         assertEquals(1, analyticsProto.callLogs.length);
         TelecomLogClass.CallLog callLog = analyticsProto.callLogs[0];
 
@@ -413,7 +425,7 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
@@ -432,7 +444,7 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
@@ -445,4 +457,17 @@
     private void assertIsRoundedToOneSigFig(long x) {
         assertEquals(x, Analytics.roundToOneSigFig(x));
     }
+
+    private void setupCarrierIds() {
+        SubscriptionInfo subInfo1 = mock(SubscriptionInfo.class);
+        SubscriptionInfo subInfo2 = mock(SubscriptionInfo.class);
+        when(subInfo1.getCarrierId()).thenReturn(1);
+        when(subInfo2.getCarrierId()).thenReturn(2);
+        when(subInfo1.isOpportunistic()).thenReturn(false);
+        when(subInfo2.isOpportunistic()).thenReturn(true);
+        when(subInfo1.getSimSlotIndex()).thenReturn(0);
+        when(subInfo2.getSimSlotIndex()).thenReturn(1);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList())
+                .thenReturn(Arrays.asList(subInfo2, subInfo1));
+    }
 }
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 19278a5..e6e8ba1 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -212,6 +212,8 @@
                 return Context.TELEPHONY_SERVICE;
             } else if (svcClass == CarrierConfigManager.class) {
                 return Context.CARRIER_CONFIG_SERVICE;
+            } else if (svcClass == SubscriptionManager.class) {
+                return Context.TELEPHONY_SUBSCRIPTION_SERVICE;
             }
             throw new UnsupportedOperationException();
         }