1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.satellite.metrics; 18 19 import android.annotation.NonNull; 20 import android.os.SystemClock; 21 import android.telephony.SubscriptionManager; 22 import android.telephony.TelephonyManager; 23 import android.util.Log; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 import com.android.internal.telephony.Phone; 27 import com.android.internal.telephony.PhoneFactory; 28 import com.android.internal.telephony.metrics.SatelliteStats; 29 import com.android.internal.telephony.satellite.SatelliteConstants; 30 import com.android.internal.telephony.satellite.SatelliteServiceUtils; 31 import com.android.internal.telephony.subscription.SubscriptionManagerService; 32 33 import java.util.ArrayList; 34 import java.util.Collections; 35 import java.util.HashMap; 36 import java.util.List; 37 import java.util.Map; 38 39 public class CarrierRoamingSatelliteControllerStats { 40 private static final String TAG = CarrierRoamingSatelliteControllerStats.class.getSimpleName(); 41 private static CarrierRoamingSatelliteControllerStats sInstance = null; 42 private static final int ADD_COUNT = 1; 43 private SatelliteStats mSatelliteStats; 44 /** Map key subId, value: list of session start time in milliseconds */ 45 private Map<Integer, List<Long>> mSessionStartTimeMap = new HashMap<>(); 46 /** Map key subId, list of session end time in milliseconds */ 47 private Map<Integer, List<Long>> mSessionEndTimeMap = new HashMap<>(); 48 49 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) CarrierRoamingSatelliteControllerStats()50 public CarrierRoamingSatelliteControllerStats() { 51 mSatelliteStats = SatelliteStats.getInstance(); 52 resetSessionGapLists(); 53 } 54 55 /** 56 * Returns the Singleton instance of CarrierRoamingSatelliteControllerStats class. 57 * If an instance of the Singleton class has not been created, 58 * it creates a new instance and returns it. Otherwise, it returns 59 * the existing instance. 60 * @return the Singleton instance of CarrierRoamingSatelliteControllerStats 61 */ getOrCreateInstance()62 public static CarrierRoamingSatelliteControllerStats getOrCreateInstance() { 63 if (sInstance == null) { 64 logd("Create new CarrierRoamingSatelliteControllerStats."); 65 sInstance = new CarrierRoamingSatelliteControllerStats(); 66 } 67 return sInstance; 68 } 69 70 /** Report config data source */ reportConfigDataSource(int subId, @SatelliteConstants.ConfigDataSource int configDataSource)71 public void reportConfigDataSource(int subId, 72 @SatelliteConstants.ConfigDataSource int configDataSource) { 73 mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics( 74 new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder() 75 .setConfigDataSource(configDataSource) 76 .setCarrierId(getCarrierIdFromSubscription(subId)) 77 .setIsMultiSim(isMultiSim()) 78 .setIsNbIotNtn(SatelliteServiceUtils.isNbIotNtn(subId)) 79 .build()); 80 } 81 82 /** Report count of entitlement status query request */ reportCountOfEntitlementStatusQueryRequest(int subId)83 public void reportCountOfEntitlementStatusQueryRequest(int subId) { 84 mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics( 85 new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder() 86 .setCountOfEntitlementStatusQueryRequest(ADD_COUNT) 87 .setCarrierId(getCarrierIdFromSubscription(subId)) 88 .setIsMultiSim(isMultiSim()) 89 .setIsNbIotNtn(SatelliteServiceUtils.isNbIotNtn(subId)) 90 .build()); 91 } 92 93 /** Report count of satellite config update request */ reportCountOfSatelliteConfigUpdateRequest()94 public void reportCountOfSatelliteConfigUpdateRequest() { 95 mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics( 96 new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder() 97 .setCountOfSatelliteConfigUpdateRequest(ADD_COUNT) 98 .setIsMultiSim(isMultiSim()) 99 .build()); 100 } 101 102 /** Report count of satellite notification displayed */ reportCountOfSatelliteNotificationDisplayed(int subId)103 public void reportCountOfSatelliteNotificationDisplayed(int subId) { 104 mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics( 105 new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder() 106 .setCountOfSatelliteNotificationDisplayed(ADD_COUNT) 107 .setCarrierId(getCarrierIdFromSubscription(subId)) 108 .setIsMultiSim(isMultiSim()) 109 .setIsNbIotNtn(SatelliteServiceUtils.isNbIotNtn(subId)) 110 .build()); 111 } 112 113 /** Capture the NB-IoT NTN carrier ID */ reportCarrierId(int carrierId)114 public void reportCarrierId(int carrierId) { 115 mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics( 116 new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder() 117 .setCarrierId(carrierId) 118 .setIsMultiSim(isMultiSim()) 119 .build()); 120 } 121 122 /** Capture whether the device is satellite entitled or not */ reportIsDeviceEntitled(int subId, boolean isDeviceEntitled)123 public void reportIsDeviceEntitled(int subId, boolean isDeviceEntitled) { 124 mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics( 125 new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder() 126 .setIsDeviceEntitled(isDeviceEntitled) 127 .setCarrierId(getCarrierIdFromSubscription(subId)) 128 .setIsMultiSim(isMultiSim()) 129 .setIsNbIotNtn(SatelliteServiceUtils.isNbIotNtn(subId)) 130 .build()); 131 } 132 133 /** Log carrier roaming satellite session start */ onSessionStart(int subId)134 public void onSessionStart(int subId) { 135 List<Long> sessionStartTimeListForSubscription = mSessionStartTimeMap.getOrDefault(subId, 136 new ArrayList<>()); 137 sessionStartTimeListForSubscription.add(getElapsedRealtime()); 138 mSessionStartTimeMap.put(subId, sessionStartTimeListForSubscription); 139 140 mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics( 141 new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder() 142 .setCarrierId(getCarrierIdFromSubscription(subId)) 143 .increaseCountOfSatelliteSessions() 144 .build()); 145 } 146 147 /** Log carrier roaming satellite session end */ onSessionEnd(int subId)148 public void onSessionEnd(int subId) { 149 List<Long> sessionEndTimeListForSubscription = mSessionEndTimeMap.getOrDefault(subId, 150 new ArrayList<>()); 151 sessionEndTimeListForSubscription.add(getElapsedRealtime()); 152 mSessionEndTimeMap.put(subId, sessionEndTimeListForSubscription); 153 154 int numberOfSatelliteSessions = getNumberOfSatelliteSessions(subId); 155 List<Integer> sessionGapList = getSatelliteSessionGapList(subId, numberOfSatelliteSessions); 156 int satelliteSessionGapMinSec = 0; 157 int satelliteSessionGapMaxSec = 0; 158 if (!sessionGapList.isEmpty()) { 159 satelliteSessionGapMinSec = Collections.min(sessionGapList); 160 satelliteSessionGapMaxSec = Collections.max(sessionGapList); 161 } 162 163 mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics( 164 new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder() 165 .setSatelliteSessionGapMinSec(satelliteSessionGapMinSec) 166 .setSatelliteSessionGapAvgSec(getAvg(sessionGapList)) 167 .setSatelliteSessionGapMaxSec(satelliteSessionGapMaxSec) 168 .setCarrierId(getCarrierIdFromSubscription(subId)) 169 .setIsMultiSim(isMultiSim()) 170 .setIsNbIotNtn(SatelliteServiceUtils.isNbIotNtn(subId)) 171 .build()); 172 } 173 174 /** Atom is pulled once per day. Reset session gap lists after the atom is pulled. */ resetSessionGapLists()175 public void resetSessionGapLists() { 176 mSessionStartTimeMap = new HashMap<>(); 177 mSessionEndTimeMap = new HashMap<>(); 178 } 179 getNumberOfSatelliteSessions(int subId)180 private int getNumberOfSatelliteSessions(int subId) { 181 return Math.min(mSessionStartTimeMap.getOrDefault(subId, new ArrayList<>()).size(), 182 mSessionEndTimeMap.getOrDefault(subId, new ArrayList<>()).size()); 183 } 184 getSatelliteSessionGapList(int subId, int numberOfSatelliteSessions)185 private List<Integer> getSatelliteSessionGapList(int subId, int numberOfSatelliteSessions) { 186 if (numberOfSatelliteSessions == 0) { 187 return new ArrayList<>(); 188 } 189 190 List<Long> sessionStartTimeList = mSessionStartTimeMap.getOrDefault(subId, 191 new ArrayList<>()); 192 List<Long> sessionEndTimeList = mSessionEndTimeMap.getOrDefault(subId, new ArrayList<>()); 193 List<Integer> sessionGapList = new ArrayList<>(); 194 for (int i = 1; i < numberOfSatelliteSessions; i++) { 195 long prevSessionEndTime = sessionEndTimeList.get(i - 1); 196 long currentSessionStartTime = sessionStartTimeList.get(i); 197 if (currentSessionStartTime > prevSessionEndTime && prevSessionEndTime > 0) { 198 sessionGapList.add((int) ( 199 (currentSessionStartTime - prevSessionEndTime) / 1000)); 200 } 201 } 202 return sessionGapList; 203 } 204 getAvg(@onNull List<Integer> list)205 private int getAvg(@NonNull List<Integer> list) { 206 if (list.isEmpty()) { 207 return 0; 208 } 209 210 int total = 0; 211 for (int num : list) { 212 total += num; 213 } 214 215 return total / list.size(); 216 } 217 218 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) getElapsedRealtime()219 protected long getElapsedRealtime() { 220 return SystemClock.elapsedRealtime(); 221 } 222 223 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) isMultiSim()224 public boolean isMultiSim() { 225 return SubscriptionManagerService.getInstance().getActiveSubIdList(true).length > 1; 226 } 227 228 /** Returns the carrier ID of the given subscription id. */ 229 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) getCarrierIdFromSubscription(int subId)230 protected int getCarrierIdFromSubscription(int subId) { 231 int phoneId = SubscriptionManager.getPhoneId(subId); 232 Phone phone = PhoneFactory.getPhone(phoneId); 233 return phone != null ? phone.getCarrierId() : TelephonyManager.UNKNOWN_CARRIER_ID; 234 } 235 logd(@onNull String log)236 private static void logd(@NonNull String log) { 237 Log.d(TAG, log); 238 } 239 } 240