1 /* 2 * Copyright (C) 2022 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.metrics; 18 19 import static android.provider.Telephony.Carriers.CONTENT_URI; 20 import static android.telephony.PhoneNumberUtils.areSamePhoneNumber; 21 22 import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_A; 23 import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_B; 24 import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_C; 25 import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_UNKNOWN; 26 import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__WFC_MODE__CELLULAR_PREFERRED; 27 import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__WFC_MODE__UNKNOWN; 28 import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__WFC_MODE__WIFI_ONLY; 29 import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__WFC_MODE__WIFI_PREFERRED; 30 31 import android.annotation.Nullable; 32 import android.database.Cursor; 33 import android.net.Uri; 34 import android.provider.Telephony; 35 import android.telephony.AnomalyReporter; 36 import android.telephony.SubscriptionManager; 37 import android.telephony.TelephonyManager; 38 import android.telephony.data.ApnSetting; 39 import android.telephony.ims.ImsManager; 40 import android.telephony.ims.ImsMmTelManager; 41 import android.text.TextUtils; 42 43 import com.android.internal.telephony.IccCard; 44 import com.android.internal.telephony.Phone; 45 import com.android.internal.telephony.PhoneFactory; 46 import com.android.internal.telephony.subscription.SubscriptionInfoInternal; 47 import com.android.internal.telephony.subscription.SubscriptionManagerService; 48 import com.android.internal.telephony.uicc.UiccController; 49 import com.android.internal.telephony.uicc.UiccSlot; 50 import com.android.telephony.Rlog; 51 52 import java.util.UUID; 53 54 /** Stores the per SIM status. */ 55 public class PerSimStatus { 56 private static final String TAG = "PerSimStatus"; 57 58 private static final long BITMASK_2G = 59 TelephonyManager.NETWORK_TYPE_BITMASK_GSM 60 | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS 61 | TelephonyManager.NETWORK_TYPE_BITMASK_EDGE 62 | TelephonyManager.NETWORK_TYPE_BITMASK_CDMA 63 | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT; 64 65 private static final UUID CROSS_SIM_CALLING_STATUS_ANOMALY_UUID = 66 UUID.fromString("377e1a33-d4ac-4039-9cc0-f0d8396757f3"); 67 68 public final int carrierId; 69 public final int phoneNumberSourceUicc; 70 public final int phoneNumberSourceCarrier; 71 public final int phoneNumberSourceIms; 72 public final boolean advancedCallingSettingEnabled; 73 public final boolean voWiFiSettingEnabled; 74 public final int voWiFiModeSetting; 75 public final int voWiFiRoamingModeSetting; 76 public final boolean vtSettingEnabled; 77 public final boolean dataRoamingEnabled; 78 public final long preferredNetworkType; 79 public final boolean disabled2g; 80 public final boolean pin1Enabled; 81 public final int minimumVoltageClass; 82 public final int userModifiedApnTypes; 83 public final long unmeteredNetworks; 84 public final boolean vonrEnabled; 85 86 public final boolean crossSimCallingEnabled; 87 88 /** Returns the current sim status of the given {@link Phone}. */ 89 @Nullable getCurrentState(Phone phone)90 public static PerSimStatus getCurrentState(Phone phone) { 91 int[] numberIds = getNumberIds(phone); 92 if (numberIds == null) return null; 93 int carrierId = phone.getCarrierId(); 94 ImsMmTelManager imsMmTelManager = getImsMmTelManager(phone); 95 IccCard iccCard = phone.getIccCard(); 96 PersistAtomsStorage persistAtomsStorage = 97 PhoneFactory.getMetricsCollector().getAtomsStorage(); 98 return new PerSimStatus( 99 carrierId, 100 numberIds[0], 101 numberIds[1], 102 numberIds[2], 103 imsMmTelManager == null ? false : imsMmTelManager.isAdvancedCallingSettingEnabled(), 104 imsMmTelManager == null ? false : imsMmTelManager.isVoWiFiSettingEnabled(), 105 imsMmTelManager == null 106 ? PER_SIM_STATUS__WFC_MODE__UNKNOWN 107 : wifiCallingModeToProtoEnum(imsMmTelManager.getVoWiFiModeSetting()), 108 imsMmTelManager == null 109 ? PER_SIM_STATUS__WFC_MODE__UNKNOWN 110 : wifiCallingModeToProtoEnum(imsMmTelManager.getVoWiFiRoamingModeSetting()), 111 imsMmTelManager == null ? false : imsMmTelManager.isVtSettingEnabled(), 112 phone.getDataRoamingEnabled(), 113 phone.getAllowedNetworkTypes(TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER), 114 is2gDisabled(phone), 115 iccCard == null ? false : iccCard.getIccLockEnabled(), 116 getMinimumVoltageClass(phone), 117 getUserModifiedApnTypes(phone), 118 persistAtomsStorage.getUnmeteredNetworks(phone.getPhoneId(), carrierId), 119 isVonrEnabled(phone), 120 isCrossSimCallingEnabled(imsMmTelManager)); 121 } 122 PerSimStatus( int carrierId, int phoneNumberSourceUicc, int phoneNumberSourceCarrier, int phoneNumberSourceIms, boolean advancedCallingSettingEnabled, boolean voWiFiSettingEnabled, int voWiFiModeSetting, int voWiFiRoamingModeSetting, boolean vtSettingEnabled, boolean dataRoamingEnabled, long preferredNetworkType, boolean disabled2g, boolean pin1Enabled, int minimumVoltageClass, int userModifiedApnTypes, long unmeteredNetworks, boolean vonrEnabled, boolean crossSimCallingEnabled)123 private PerSimStatus( 124 int carrierId, 125 int phoneNumberSourceUicc, 126 int phoneNumberSourceCarrier, 127 int phoneNumberSourceIms, 128 boolean advancedCallingSettingEnabled, 129 boolean voWiFiSettingEnabled, 130 int voWiFiModeSetting, 131 int voWiFiRoamingModeSetting, 132 boolean vtSettingEnabled, 133 boolean dataRoamingEnabled, 134 long preferredNetworkType, 135 boolean disabled2g, 136 boolean pin1Enabled, 137 int minimumVoltageClass, 138 int userModifiedApnTypes, 139 long unmeteredNetworks, 140 boolean vonrEnabled, 141 boolean crossSimCallingEnabled) { 142 this.carrierId = carrierId; 143 this.phoneNumberSourceUicc = phoneNumberSourceUicc; 144 this.phoneNumberSourceCarrier = phoneNumberSourceCarrier; 145 this.phoneNumberSourceIms = phoneNumberSourceIms; 146 this.advancedCallingSettingEnabled = advancedCallingSettingEnabled; 147 this.voWiFiSettingEnabled = voWiFiSettingEnabled; 148 this.voWiFiModeSetting = voWiFiModeSetting; 149 this.voWiFiRoamingModeSetting = voWiFiRoamingModeSetting; 150 this.vtSettingEnabled = vtSettingEnabled; 151 this.dataRoamingEnabled = dataRoamingEnabled; 152 this.preferredNetworkType = preferredNetworkType; 153 this.disabled2g = disabled2g; 154 this.pin1Enabled = pin1Enabled; 155 this.minimumVoltageClass = minimumVoltageClass; 156 this.userModifiedApnTypes = userModifiedApnTypes; 157 this.unmeteredNetworks = unmeteredNetworks; 158 this.vonrEnabled = vonrEnabled; 159 this.crossSimCallingEnabled = crossSimCallingEnabled; 160 } 161 isCrossSimCallingEnabled(ImsMmTelManager imsMmTelManager)162 private static boolean isCrossSimCallingEnabled(ImsMmTelManager imsMmTelManager) { 163 try { 164 return imsMmTelManager != null && imsMmTelManager.isCrossSimCallingEnabled(); 165 } catch (Exception e) { 166 AnomalyReporter.reportAnomaly(CROSS_SIM_CALLING_STATUS_ANOMALY_UUID, 167 "Failed to query ImsMmTelManager for cross-SIM calling status!"); 168 Rlog.e(TAG, e.getMessage()); 169 } 170 return false; 171 } 172 173 @Nullable getImsMmTelManager(Phone phone)174 private static ImsMmTelManager getImsMmTelManager(Phone phone) { 175 ImsManager imsManager = phone.getContext().getSystemService(ImsManager.class); 176 if (imsManager == null) { 177 return null; 178 } 179 try { 180 return imsManager.getImsMmTelManager(phone.getSubId()); 181 } catch (IllegalArgumentException e) { 182 return null; // Invalid subId 183 } 184 } 185 186 /** 187 * Returns an array of integer ids representing phone numbers. If number is empty then id will 188 * be 0. Two same numbers will have same id, and different numbers will have different ids. For 189 * example, [1, 0, 1] means that uicc and ims numbers are the same while carrier number is empty 190 * and [1, 2, 3] means all numbers are different. 191 * 192 * <ul> 193 * <li>Index 0: id associated with {@code PHONE_NUMBER_SOURCE_UICC}.</li> 194 * <li>Index 1: id associated with {@code PHONE_NUMBER_SOURCE_CARRIER}.</li> 195 * <li>Index 2: id associated with {@code PHONE_NUMBER_SOURCE_IMS}.</li> 196 * </ul> 197 */ 198 @Nullable getNumberIds(Phone phone)199 private static int[] getNumberIds(Phone phone) { 200 String countryIso = ""; 201 String[] numbersFromAllSources; 202 203 if (SubscriptionManagerService.getInstance() == null) return null; 204 SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() 205 .getSubscriptionInfoInternal(phone.getSubId()); 206 if (subInfo != null) { 207 countryIso = subInfo.getCountryIso(); 208 } 209 numbersFromAllSources = new String[]{ 210 SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), 211 SubscriptionManager.PHONE_NUMBER_SOURCE_UICC, null, null), 212 SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), 213 SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, null, null), 214 SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), 215 SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, null, null) 216 }; 217 218 int[] numberIds = new int[numbersFromAllSources.length]; // default value 0 219 for (int i = 0, idForNextUniqueNumber = 1; i < numberIds.length; i++) { 220 if (TextUtils.isEmpty(numbersFromAllSources[i])) { 221 // keep id 0 if number not available 222 continue; 223 } 224 // the number is available: 225 // try to find the same number from other sources and reuse the id 226 for (int j = 0; j < i; j++) { 227 if (!TextUtils.isEmpty(numbersFromAllSources[j]) 228 && areSamePhoneNumber( 229 numbersFromAllSources[i], numbersFromAllSources[j], countryIso)) { 230 numberIds[i] = numberIds[j]; 231 } 232 } 233 // didn't find same number (otherwise should not be id 0), assign a new id 234 if (numberIds[i] == 0) { 235 numberIds[i] = idForNextUniqueNumber++; 236 } 237 } 238 return numberIds; 239 } 240 241 /** 242 * Returns {@code true} if 2G cellular network is disabled (Allow 2G toggle in the settings). 243 */ is2gDisabled(Phone phone)244 private static boolean is2gDisabled(Phone phone) { 245 return (phone.getAllowedNetworkTypes( 246 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G) 247 & BITMASK_2G) 248 == 0; 249 } 250 251 /** Converts {@link ImsMmTelManager.WifiCallingMode} to the value of PerSimStatus WfcMode. */ wifiCallingModeToProtoEnum(@msMmTelManager.WiFiCallingMode int mode)252 private static int wifiCallingModeToProtoEnum(@ImsMmTelManager.WiFiCallingMode int mode) { 253 switch (mode) { 254 case ImsMmTelManager.WIFI_MODE_WIFI_ONLY: 255 return PER_SIM_STATUS__WFC_MODE__WIFI_ONLY; 256 case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED: 257 return PER_SIM_STATUS__WFC_MODE__CELLULAR_PREFERRED; 258 case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED: 259 return PER_SIM_STATUS__WFC_MODE__WIFI_PREFERRED; 260 default: 261 return PER_SIM_STATUS__WFC_MODE__UNKNOWN; 262 } 263 } 264 265 /** Returns the minimum voltage class supported by the UICC. */ getMinimumVoltageClass(Phone phone)266 private static int getMinimumVoltageClass(Phone phone) { 267 UiccSlot uiccSlot = UiccController.getInstance().getUiccSlotForPhone(phone.getPhoneId()); 268 if (uiccSlot == null) { 269 return PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_UNKNOWN; 270 } 271 switch (uiccSlot.getMinimumVoltageClass()) { 272 case UiccSlot.VOLTAGE_CLASS_A: 273 return PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_A; 274 case UiccSlot.VOLTAGE_CLASS_B: 275 return PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_B; 276 case UiccSlot.VOLTAGE_CLASS_C: 277 return PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_C; 278 default: 279 return PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_UNKNOWN; 280 } 281 } 282 283 /** Returns the bitmask representing types of APNs modified by user. */ getUserModifiedApnTypes(Phone phone)284 private static int getUserModifiedApnTypes(Phone phone) { 285 String[] projections = {Telephony.Carriers.TYPE}; 286 String selection = Telephony.Carriers.EDITED_STATUS + "=?"; 287 String[] selectionArgs = {Integer.toString(Telephony.Carriers.USER_EDITED)}; 288 try (Cursor cursor = 289 phone.getContext() 290 .getContentResolver() 291 .query( 292 Uri.withAppendedPath(CONTENT_URI, "subId/" + phone.getSubId()), 293 projections, 294 selection, 295 selectionArgs, 296 null)) { 297 int bitmask = 0; 298 while (cursor != null && cursor.moveToNext()) { 299 bitmask |= ApnSetting.getApnTypesBitmaskFromString(cursor.getString(0)); 300 } 301 return bitmask; 302 } 303 } 304 305 /** Returns true if VoNR is enabled */ isVonrEnabled(Phone phone)306 static boolean isVonrEnabled(Phone phone) { 307 TelephonyManager telephonyManager = 308 phone.getContext() 309 .getSystemService(TelephonyManager.class); 310 if (telephonyManager == null) { 311 return false; 312 } 313 telephonyManager = telephonyManager.createForSubscriptionId(phone.getSubId()); 314 return telephonyManager.isVoNrEnabled(); 315 } 316 } 317