1 /* 2 * Copyright (C) 2020 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.text.format.DateUtils.HOUR_IN_MILLIS; 20 import static android.text.format.DateUtils.MINUTE_IN_MILLIS; 21 import static android.text.format.DateUtils.SECOND_IN_MILLIS; 22 23 import static com.android.internal.telephony.TelephonyStatsLog.CARRIER_ID_TABLE_VERSION; 24 import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_DATA_SERVICE_SWITCH; 25 import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE; 26 import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION; 27 import static com.android.internal.telephony.TelephonyStatsLog.DEVICE_TELEPHONY_PROPERTIES; 28 import static com.android.internal.telephony.TelephonyStatsLog.GBA_EVENT; 29 import static com.android.internal.telephony.TelephonyStatsLog.IMS_DEDICATED_BEARER_EVENT; 30 import static com.android.internal.telephony.TelephonyStatsLog.IMS_DEDICATED_BEARER_LISTENER_EVENT; 31 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_FEATURE_TAG_STATS; 32 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS; 33 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_STATS; 34 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_TERMINATION; 35 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS; 36 import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS; 37 import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS; 38 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT; 39 import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS; 40 import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS; 41 import static com.android.internal.telephony.TelephonyStatsLog.SIM_SLOT_STATE; 42 import static com.android.internal.telephony.TelephonyStatsLog.SIP_DELEGATE_STATS; 43 import static com.android.internal.telephony.TelephonyStatsLog.SIP_MESSAGE_RESPONSE; 44 import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_FEATURE_TAG_STATS; 45 import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION; 46 import static com.android.internal.telephony.TelephonyStatsLog.SUPPORTED_RADIO_ACCESS_FAMILY; 47 import static com.android.internal.telephony.TelephonyStatsLog.TELEPHONY_NETWORK_REQUESTS_V2; 48 import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS; 49 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_RAT_USAGE; 50 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION; 51 52 import android.app.StatsManager; 53 import android.content.Context; 54 import android.util.StatsEvent; 55 56 import com.android.internal.annotations.VisibleForTesting; 57 import com.android.internal.telephony.Phone; 58 import com.android.internal.telephony.PhoneFactory; 59 import com.android.internal.telephony.TelephonyStatsLog; 60 import com.android.internal.telephony.imsphone.ImsPhone; 61 import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch; 62 import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState; 63 import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession; 64 import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent; 65 import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent; 66 import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerListenerEvent; 67 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationFeatureTagStats; 68 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationServiceDescStats; 69 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationStats; 70 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination; 71 import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms; 72 import com.android.internal.telephony.nano.PersistAtomsProto.NetworkRequestsV2; 73 import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; 74 import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent; 75 import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats; 76 import com.android.internal.telephony.nano.PersistAtomsProto.RcsClientProvisioningStats; 77 import com.android.internal.telephony.nano.PersistAtomsProto.SipDelegateStats; 78 import com.android.internal.telephony.nano.PersistAtomsProto.SipMessageResponse; 79 import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportFeatureTagStats; 80 import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportSession; 81 import com.android.internal.telephony.nano.PersistAtomsProto.UceEventStats; 82 import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallRatUsage; 83 import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession; 84 import com.android.internal.util.ConcurrentUtils; 85 import com.android.telephony.Rlog; 86 87 import java.util.Arrays; 88 import java.util.Comparator; 89 import java.util.List; 90 import java.util.Random; 91 import java.util.Set; 92 import java.util.concurrent.ConcurrentHashMap; 93 94 /** 95 * Implements statsd pullers for Telephony. 96 * 97 * <p>This class registers pullers to statsd, which will be called once a day to obtain telephony 98 * statistics that cannot be sent to statsd in real time. 99 */ 100 public class MetricsCollector implements StatsManager.StatsPullAtomCallback { 101 private static final String TAG = MetricsCollector.class.getSimpleName(); 102 103 /** Disables various restrictions to ease debugging during development. */ 104 private static final boolean DBG = false; // STOPSHIP if true 105 106 /** 107 * Sets atom pull cool down to 23 hours to help enforcing privacy requirement. 108 * 109 * <p>Applies to certain atoms. The interval of 23 hours leaves some margin for pull operations 110 * that occur once a day. 111 */ 112 private static final long MIN_COOLDOWN_MILLIS = 113 DBG ? 10L * SECOND_IN_MILLIS : 23L * HOUR_IN_MILLIS; 114 115 /** 116 * Buckets with less than these many calls will be dropped. 117 * 118 * <p>Applies to metrics with duration fields. Currently used by voice call RAT usages. 119 */ 120 private static final long MIN_CALLS_PER_BUCKET = DBG ? 0L : 5L; 121 122 /** Bucket size in milliseconds to round call durations into. */ 123 private static final long DURATION_BUCKET_MILLIS = 124 DBG ? 2L * SECOND_IN_MILLIS : 5L * MINUTE_IN_MILLIS; 125 126 private final PersistAtomsStorage mStorage; 127 private final StatsManager mStatsManager; 128 private final AirplaneModeStats mAirplaneModeStats; 129 private final Set<DataCallSessionStats> mOngoingDataCallStats = ConcurrentHashMap.newKeySet(); 130 private static final Random sRandom = new Random(); 131 MetricsCollector(Context context)132 public MetricsCollector(Context context) { 133 this(context, new PersistAtomsStorage(context)); 134 } 135 136 /** Allows dependency injection. Used during unit tests. */ 137 @VisibleForTesting MetricsCollector(Context context, PersistAtomsStorage storage)138 public MetricsCollector(Context context, 139 PersistAtomsStorage storage) { 140 mStorage = storage; 141 mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER); 142 if (mStatsManager != null) { 143 registerAtom(CELLULAR_DATA_SERVICE_SWITCH); 144 registerAtom(CELLULAR_SERVICE_STATE); 145 registerAtom(SIM_SLOT_STATE); 146 registerAtom(SUPPORTED_RADIO_ACCESS_FAMILY); 147 registerAtom(VOICE_CALL_RAT_USAGE); 148 registerAtom(VOICE_CALL_SESSION); 149 registerAtom(INCOMING_SMS); 150 registerAtom(OUTGOING_SMS); 151 registerAtom(CARRIER_ID_TABLE_VERSION); 152 registerAtom(DATA_CALL_SESSION); 153 registerAtom(IMS_REGISTRATION_STATS); 154 registerAtom(IMS_REGISTRATION_TERMINATION); 155 registerAtom(TELEPHONY_NETWORK_REQUESTS_V2); 156 registerAtom(IMS_REGISTRATION_FEATURE_TAG_STATS); 157 registerAtom(RCS_CLIENT_PROVISIONING_STATS); 158 registerAtom(RCS_ACS_PROVISIONING_STATS); 159 registerAtom(SIP_DELEGATE_STATS); 160 registerAtom(SIP_TRANSPORT_FEATURE_TAG_STATS); 161 registerAtom(SIP_MESSAGE_RESPONSE); 162 registerAtom(SIP_TRANSPORT_SESSION); 163 registerAtom(DEVICE_TELEPHONY_PROPERTIES); 164 registerAtom(IMS_DEDICATED_BEARER_LISTENER_EVENT); 165 registerAtom(IMS_DEDICATED_BEARER_EVENT); 166 registerAtom(IMS_REGISTRATION_SERVICE_DESC_STATS); 167 registerAtom(UCE_EVENT_STATS); 168 registerAtom(PRESENCE_NOTIFY_EVENT); 169 registerAtom(GBA_EVENT); 170 registerAtom(PER_SIM_STATUS); 171 Rlog.d(TAG, "registered"); 172 } else { 173 Rlog.e(TAG, "could not get StatsManager, atoms not registered"); 174 } 175 176 mAirplaneModeStats = new AirplaneModeStats(context); 177 } 178 179 /** 180 * {@inheritDoc} 181 * 182 * @return {@link StatsManager#PULL_SUCCESS} with list of atoms (potentially empty) if pull 183 * succeeded, {@link StatsManager#PULL_SKIP} if pull was too frequent or atom ID is 184 * unexpected. 185 */ 186 @Override onPullAtom(int atomTag, List<StatsEvent> data)187 public int onPullAtom(int atomTag, List<StatsEvent> data) { 188 switch (atomTag) { 189 case CELLULAR_DATA_SERVICE_SWITCH: 190 return pullCellularDataServiceSwitch(data); 191 case CELLULAR_SERVICE_STATE: 192 return pullCellularServiceState(data); 193 case SIM_SLOT_STATE: 194 return pullSimSlotState(data); 195 case SUPPORTED_RADIO_ACCESS_FAMILY: 196 return pullSupportedRadioAccessFamily(data); 197 case VOICE_CALL_RAT_USAGE: 198 return pullVoiceCallRatUsages(data); 199 case VOICE_CALL_SESSION: 200 return pullVoiceCallSessions(data); 201 case INCOMING_SMS: 202 return pullIncomingSms(data); 203 case OUTGOING_SMS: 204 return pullOutgoingSms(data); 205 case CARRIER_ID_TABLE_VERSION: 206 return pullCarrierIdTableVersion(data); 207 case DATA_CALL_SESSION: 208 return pullDataCallSession(data); 209 case IMS_REGISTRATION_STATS: 210 return pullImsRegistrationStats(data); 211 case IMS_REGISTRATION_TERMINATION: 212 return pullImsRegistrationTermination(data); 213 case TELEPHONY_NETWORK_REQUESTS_V2: 214 return pullTelephonyNetworkRequestsV2(data); 215 case DEVICE_TELEPHONY_PROPERTIES: 216 return pullDeviceTelephonyProperties(data); 217 case IMS_REGISTRATION_FEATURE_TAG_STATS: 218 return pullImsRegistrationFeatureTagStats(data); 219 case RCS_CLIENT_PROVISIONING_STATS: 220 return pullRcsClientProvisioningStats(data); 221 case RCS_ACS_PROVISIONING_STATS: 222 return pullRcsAcsProvisioningStats(data); 223 case SIP_DELEGATE_STATS: 224 return pullSipDelegateStats(data); 225 case SIP_TRANSPORT_FEATURE_TAG_STATS: 226 return pullSipTransportFeatureTagStats(data); 227 case SIP_MESSAGE_RESPONSE: 228 return pullSipMessageResponse(data); 229 case SIP_TRANSPORT_SESSION: 230 return pullSipTransportSession(data); 231 case IMS_DEDICATED_BEARER_LISTENER_EVENT: 232 return pullImsDedicatedBearerListenerEvent(data); 233 case IMS_DEDICATED_BEARER_EVENT: 234 return pullImsDedicatedBearerEvent(data); 235 case IMS_REGISTRATION_SERVICE_DESC_STATS: 236 return pullImsRegistrationServiceDescStats(data); 237 case UCE_EVENT_STATS: 238 return pullUceEventStats(data); 239 case PRESENCE_NOTIFY_EVENT: 240 return pullPresenceNotifyEvent(data); 241 case GBA_EVENT: 242 return pullGbaEvent(data); 243 case PER_SIM_STATUS: 244 return pullPerSimStatus(data); 245 default: 246 Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag)); 247 return StatsManager.PULL_SKIP; 248 } 249 } 250 251 /** Returns the {@link PersistAtomsStorage} backing the puller. */ getAtomsStorage()252 public PersistAtomsStorage getAtomsStorage() { 253 return mStorage; 254 } 255 256 /** 257 * Registers a {@link DataCallSessionStats} which will be pinged for on-going data calls when 258 * data call atoms are pulled. 259 */ registerOngoingDataCallStat(DataCallSessionStats call)260 public void registerOngoingDataCallStat(DataCallSessionStats call) { 261 mOngoingDataCallStats.add(call); 262 } 263 264 /** Unregisters a {@link DataCallSessionStats} when it no longer handles an active data call. */ unregisterOngoingDataCallStat(DataCallSessionStats call)265 public void unregisterOngoingDataCallStat(DataCallSessionStats call) { 266 mOngoingDataCallStats.remove(call); 267 } 268 pullSimSlotState(List<StatsEvent> data)269 private static int pullSimSlotState(List<StatsEvent> data) { 270 SimSlotState state; 271 try { 272 state = SimSlotState.getCurrentState(); 273 } catch (RuntimeException e) { 274 // UiccController has not been made yet 275 return StatsManager.PULL_SKIP; 276 } 277 278 data.add( 279 TelephonyStatsLog.buildStatsEvent( 280 SIM_SLOT_STATE, 281 state.numActiveSlots, 282 state.numActiveSims, 283 state.numActiveEsims)); 284 return StatsManager.PULL_SUCCESS; 285 } 286 pullSupportedRadioAccessFamily(List<StatsEvent> data)287 private static int pullSupportedRadioAccessFamily(List<StatsEvent> data) { 288 Phone[] phones = getPhonesIfAny(); 289 if (phones.length == 0) { 290 return StatsManager.PULL_SKIP; 291 } 292 293 // The bitmask is defined in android.telephony.TelephonyManager.NetworkTypeBitMask 294 long rafSupported = 0L; 295 for (Phone phone : PhoneFactory.getPhones()) { 296 rafSupported |= phone.getRadioAccessFamily(); 297 } 298 299 data.add(TelephonyStatsLog.buildStatsEvent(SUPPORTED_RADIO_ACCESS_FAMILY, rafSupported)); 300 return StatsManager.PULL_SUCCESS; 301 } 302 pullCarrierIdTableVersion(List<StatsEvent> data)303 private static int pullCarrierIdTableVersion(List<StatsEvent> data) { 304 Phone[] phones = getPhonesIfAny(); 305 if (phones.length == 0) { 306 return StatsManager.PULL_SKIP; 307 } else { 308 // All phones should have the same version of the carrier ID table, so only query the 309 // first one. 310 int version = phones[0].getCarrierIdListVersion(); 311 data.add(TelephonyStatsLog.buildStatsEvent(CARRIER_ID_TABLE_VERSION, version)); 312 return StatsManager.PULL_SUCCESS; 313 } 314 } 315 pullVoiceCallRatUsages(List<StatsEvent> data)316 private int pullVoiceCallRatUsages(List<StatsEvent> data) { 317 VoiceCallRatUsage[] usages = mStorage.getVoiceCallRatUsages(MIN_COOLDOWN_MILLIS); 318 if (usages != null) { 319 // sort by carrier/RAT and remove buckets with insufficient number of calls 320 Arrays.stream(usages) 321 .sorted( 322 Comparator.comparingLong( 323 usage -> ((long) usage.carrierId << 32) | usage.rat)) 324 .filter(usage -> usage.callCount >= MIN_CALLS_PER_BUCKET) 325 .forEach(usage -> data.add(buildStatsEvent(usage))); 326 Rlog.d( 327 TAG, 328 String.format( 329 "%d out of %d VOICE_CALL_RAT_USAGE pulled", 330 data.size(), usages.length)); 331 return StatsManager.PULL_SUCCESS; 332 } else { 333 Rlog.w(TAG, "VOICE_CALL_RAT_USAGE pull too frequent, skipping"); 334 return StatsManager.PULL_SKIP; 335 } 336 } 337 pullVoiceCallSessions(List<StatsEvent> data)338 private int pullVoiceCallSessions(List<StatsEvent> data) { 339 VoiceCallSession[] calls = mStorage.getVoiceCallSessions(MIN_COOLDOWN_MILLIS); 340 if (calls != null) { 341 // call session list is already shuffled when calls were inserted 342 Arrays.stream(calls).forEach(call -> data.add(buildStatsEvent(call))); 343 return StatsManager.PULL_SUCCESS; 344 } else { 345 Rlog.w(TAG, "VOICE_CALL_SESSION pull too frequent, skipping"); 346 return StatsManager.PULL_SKIP; 347 } 348 } 349 pullIncomingSms(List<StatsEvent> data)350 private int pullIncomingSms(List<StatsEvent> data) { 351 IncomingSms[] smsList = mStorage.getIncomingSms(MIN_COOLDOWN_MILLIS); 352 if (smsList != null) { 353 // SMS list is already shuffled when SMS were inserted 354 Arrays.stream(smsList).forEach(sms -> data.add(buildStatsEvent(sms))); 355 return StatsManager.PULL_SUCCESS; 356 } else { 357 Rlog.w(TAG, "INCOMING_SMS pull too frequent, skipping"); 358 return StatsManager.PULL_SKIP; 359 } 360 } 361 pullOutgoingSms(List<StatsEvent> data)362 private int pullOutgoingSms(List<StatsEvent> data) { 363 OutgoingSms[] smsList = mStorage.getOutgoingSms(MIN_COOLDOWN_MILLIS); 364 if (smsList != null) { 365 // SMS list is already shuffled when SMS were inserted 366 Arrays.stream(smsList).forEach(sms -> data.add(buildStatsEvent(sms))); 367 return StatsManager.PULL_SUCCESS; 368 } else { 369 Rlog.w(TAG, "OUTGOING_SMS pull too frequent, skipping"); 370 return StatsManager.PULL_SKIP; 371 } 372 } 373 pullDataCallSession(List<StatsEvent> data)374 private int pullDataCallSession(List<StatsEvent> data) { 375 // Include ongoing data call segments 376 for (DataCallSessionStats stats : mOngoingDataCallStats) { 377 stats.conclude(); 378 } 379 380 DataCallSession[] dataCallSessions = mStorage.getDataCallSessions(MIN_COOLDOWN_MILLIS); 381 if (dataCallSessions != null) { 382 Arrays.stream(dataCallSessions) 383 .forEach(dataCall -> data.add(buildStatsEvent(dataCall))); 384 return StatsManager.PULL_SUCCESS; 385 } else { 386 Rlog.w(TAG, "DATA_CALL_SESSION pull too frequent, skipping"); 387 return StatsManager.PULL_SKIP; 388 } 389 } 390 pullCellularDataServiceSwitch(List<StatsEvent> data)391 private int pullCellularDataServiceSwitch(List<StatsEvent> data) { 392 CellularDataServiceSwitch[] persistAtoms = 393 mStorage.getCellularDataServiceSwitches(MIN_COOLDOWN_MILLIS); 394 if (persistAtoms != null) { 395 // list is already shuffled when instances were inserted 396 Arrays.stream(persistAtoms) 397 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 398 return StatsManager.PULL_SUCCESS; 399 } else { 400 Rlog.w(TAG, "CELLULAR_DATA_SERVICE_SWITCH pull too frequent, skipping"); 401 return StatsManager.PULL_SKIP; 402 } 403 } 404 pullCellularServiceState(List<StatsEvent> data)405 private int pullCellularServiceState(List<StatsEvent> data) { 406 // Include the latest durations 407 for (Phone phone : getPhonesIfAny()) { 408 phone.getServiceStateTracker().getServiceStateStats().conclude(); 409 } 410 411 CellularServiceState[] persistAtoms = 412 mStorage.getCellularServiceStates(MIN_COOLDOWN_MILLIS); 413 if (persistAtoms != null) { 414 // list is already shuffled when instances were inserted 415 Arrays.stream(persistAtoms) 416 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 417 return StatsManager.PULL_SUCCESS; 418 } else { 419 Rlog.w(TAG, "CELLULAR_SERVICE_STATE pull too frequent, skipping"); 420 return StatsManager.PULL_SKIP; 421 } 422 } 423 pullImsRegistrationStats(List<StatsEvent> data)424 private int pullImsRegistrationStats(List<StatsEvent> data) { 425 // Include the latest durations 426 for (Phone phone : getPhonesIfAny()) { 427 ImsPhone imsPhone = (ImsPhone) phone.getImsPhone(); 428 if (imsPhone != null) { 429 imsPhone.getImsStats().conclude(); 430 } 431 } 432 433 ImsRegistrationStats[] persistAtoms = mStorage.getImsRegistrationStats(MIN_COOLDOWN_MILLIS); 434 if (persistAtoms != null) { 435 // list is already shuffled when instances were inserted 436 Arrays.stream(persistAtoms) 437 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 438 return StatsManager.PULL_SUCCESS; 439 } else { 440 Rlog.w(TAG, "IMS_REGISTRATION_STATS pull too frequent, skipping"); 441 return StatsManager.PULL_SKIP; 442 } 443 } 444 pullImsRegistrationTermination(List<StatsEvent> data)445 private int pullImsRegistrationTermination(List<StatsEvent> data) { 446 ImsRegistrationTermination[] persistAtoms = 447 mStorage.getImsRegistrationTerminations(MIN_COOLDOWN_MILLIS); 448 if (persistAtoms != null) { 449 // list is already shuffled when instances were inserted 450 Arrays.stream(persistAtoms) 451 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 452 return StatsManager.PULL_SUCCESS; 453 } else { 454 Rlog.w(TAG, "IMS_REGISTRATION_TERMINATION pull too frequent, skipping"); 455 return StatsManager.PULL_SKIP; 456 } 457 } 458 pullTelephonyNetworkRequestsV2(List<StatsEvent> data)459 private int pullTelephonyNetworkRequestsV2(List<StatsEvent> data) { 460 NetworkRequestsV2[] persistAtoms = mStorage.getNetworkRequestsV2(MIN_COOLDOWN_MILLIS); 461 if (persistAtoms != null) { 462 Arrays.stream(persistAtoms) 463 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 464 return StatsManager.PULL_SUCCESS; 465 } else { 466 Rlog.w(TAG, "TELEPHONY_NETWORK_REQUESTS_V2 pull too frequent, skipping"); 467 return StatsManager.PULL_SKIP; 468 } 469 } 470 pullDeviceTelephonyProperties(List<StatsEvent> data)471 private static int pullDeviceTelephonyProperties(List<StatsEvent> data) { 472 Phone[] phones = getPhonesIfAny(); 473 if (phones.length == 0) { 474 return StatsManager.PULL_SKIP; 475 } 476 477 data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, 478 phones[0].isUsingNewDataStack())); 479 return StatsManager.PULL_SUCCESS; 480 } 481 pullImsRegistrationFeatureTagStats(List<StatsEvent> data)482 private int pullImsRegistrationFeatureTagStats(List<StatsEvent> data) { 483 RcsStats.getInstance().onFlushIncompleteImsRegistrationFeatureTagStats(); 484 485 ImsRegistrationFeatureTagStats[] persistAtoms = 486 mStorage.getImsRegistrationFeatureTagStats(MIN_COOLDOWN_MILLIS); 487 if (persistAtoms != null) { 488 Arrays.stream(persistAtoms) 489 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 490 return StatsManager.PULL_SUCCESS; 491 } else { 492 Rlog.w(TAG, "IMS_REGISTRATION_FEATURE_TAG_STATS pull too frequent, skipping"); 493 return StatsManager.PULL_SKIP; 494 } 495 } 496 pullRcsClientProvisioningStats(List<StatsEvent> data)497 private int pullRcsClientProvisioningStats(List<StatsEvent> data) { 498 RcsClientProvisioningStats[] persistAtoms = 499 mStorage.getRcsClientProvisioningStats(MIN_COOLDOWN_MILLIS); 500 if (persistAtoms != null) { 501 Arrays.stream(persistAtoms) 502 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 503 return StatsManager.PULL_SUCCESS; 504 } else { 505 Rlog.w(TAG, "RCS_CLIENT_PROVISIONING_STATS pull too frequent, skipping"); 506 return StatsManager.PULL_SKIP; 507 } 508 } 509 pullRcsAcsProvisioningStats(List<StatsEvent> data)510 private int pullRcsAcsProvisioningStats(List<StatsEvent> data) { 511 RcsStats.getInstance().onFlushIncompleteRcsAcsProvisioningStats(); 512 513 RcsAcsProvisioningStats[] persistAtoms = 514 mStorage.getRcsAcsProvisioningStats(MIN_COOLDOWN_MILLIS); 515 if (persistAtoms != null) { 516 Arrays.stream(persistAtoms) 517 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 518 return StatsManager.PULL_SUCCESS; 519 } else { 520 Rlog.w(TAG, "RCS_ACS_PROVISIONING_STATS pull too frequent, skipping"); 521 return StatsManager.PULL_SKIP; 522 } 523 } 524 pullSipDelegateStats(List<StatsEvent> data)525 private int pullSipDelegateStats(List<StatsEvent> data) { 526 SipDelegateStats[] persisAtoms = 527 mStorage.getSipDelegateStats(MIN_COOLDOWN_MILLIS); 528 if (persisAtoms != null) { 529 Arrays.stream(persisAtoms) 530 .forEach(persisAtom -> data.add(buildStatsEvent(persisAtom))); 531 return StatsManager.PULL_SUCCESS; 532 } else { 533 Rlog.w(TAG, "SIP_DELEGATE_STATS pull too frequent, skipping"); 534 return StatsManager.PULL_SKIP; 535 } 536 } 537 pullSipTransportFeatureTagStats(List<StatsEvent> data)538 private int pullSipTransportFeatureTagStats(List<StatsEvent> data) { 539 RcsStats.getInstance().concludeSipTransportFeatureTagsStat(); 540 541 SipTransportFeatureTagStats[] persisAtoms = 542 mStorage.getSipTransportFeatureTagStats(MIN_COOLDOWN_MILLIS); 543 if (persisAtoms != null) { 544 Arrays.stream(persisAtoms) 545 .forEach(persisAtom -> data.add(buildStatsEvent(persisAtom))); 546 return StatsManager.PULL_SUCCESS; 547 } else { 548 Rlog.w(TAG, "SIP_DELEGATE_STATS pull too frequent, skipping"); 549 return StatsManager.PULL_SKIP; 550 } 551 } 552 pullSipMessageResponse(List<StatsEvent> data)553 private int pullSipMessageResponse(List<StatsEvent> data) { 554 SipMessageResponse[] persistAtoms = 555 mStorage.getSipMessageResponse(MIN_COOLDOWN_MILLIS); 556 if (persistAtoms != null) { 557 Arrays.stream(persistAtoms) 558 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 559 return StatsManager.PULL_SUCCESS; 560 } else { 561 Rlog.w(TAG, "RCS_SIP_MESSAGE_RESPONSE pull too frequent, skipping"); 562 return StatsManager.PULL_SKIP; 563 } 564 } 565 pullSipTransportSession(List<StatsEvent> data)566 private int pullSipTransportSession(List<StatsEvent> data) { 567 SipTransportSession[] persistAtoms = 568 mStorage.getSipTransportSession(MIN_COOLDOWN_MILLIS); 569 if (persistAtoms != null) { 570 Arrays.stream(persistAtoms) 571 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 572 return StatsManager.PULL_SUCCESS; 573 } else { 574 Rlog.w(TAG, "RCS_SIP_TRANSPORT_SESSION pull too frequent, skipping"); 575 return StatsManager.PULL_SKIP; 576 } 577 } 578 pullImsDedicatedBearerListenerEvent(List<StatsEvent> data)579 private int pullImsDedicatedBearerListenerEvent(List<StatsEvent> data) { 580 ImsDedicatedBearerListenerEvent[] persistAtoms = 581 mStorage.getImsDedicatedBearerListenerEvent(MIN_COOLDOWN_MILLIS); 582 if (persistAtoms != null) { 583 Arrays.stream(persistAtoms) 584 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 585 return StatsManager.PULL_SUCCESS; 586 } else { 587 Rlog.w(TAG, "IMS_DEDICATED_BEARER_LISTENER_EVENT pull too frequent, skipping"); 588 return StatsManager.PULL_SKIP; 589 } 590 } 591 pullImsDedicatedBearerEvent(List<StatsEvent> data)592 private int pullImsDedicatedBearerEvent(List<StatsEvent> data) { 593 ImsDedicatedBearerEvent[] persistAtoms = 594 mStorage.getImsDedicatedBearerEvent(MIN_COOLDOWN_MILLIS); 595 if (persistAtoms != null) { 596 Arrays.stream(persistAtoms) 597 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 598 return StatsManager.PULL_SUCCESS; 599 } else { 600 Rlog.w(TAG, "IMS_DEDICATED_BEARER_EVENT pull too frequent, skipping"); 601 return StatsManager.PULL_SKIP; 602 } 603 } 604 pullImsRegistrationServiceDescStats(List<StatsEvent> data)605 private int pullImsRegistrationServiceDescStats(List<StatsEvent> data) { 606 RcsStats.getInstance().onFlushIncompleteImsRegistrationServiceDescStats(); 607 ImsRegistrationServiceDescStats[] persistAtoms = 608 mStorage.getImsRegistrationServiceDescStats(MIN_COOLDOWN_MILLIS); 609 if (persistAtoms != null) { 610 Arrays.stream(persistAtoms) 611 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 612 return StatsManager.PULL_SUCCESS; 613 } else { 614 Rlog.w(TAG, "IMS_REGISTRATION_SERVICE_DESC_STATS pull too frequent, skipping"); 615 return StatsManager.PULL_SKIP; 616 } 617 } 618 pullUceEventStats(List<StatsEvent> data)619 private int pullUceEventStats(List<StatsEvent> data) { 620 UceEventStats[] persistAtoms = mStorage.getUceEventStats(MIN_COOLDOWN_MILLIS); 621 if (persistAtoms != null) { 622 Arrays.stream(persistAtoms) 623 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 624 return StatsManager.PULL_SUCCESS; 625 } else { 626 Rlog.w(TAG, "UCE_EVENT_STATS pull too frequent, skipping"); 627 return StatsManager.PULL_SKIP; 628 } 629 } 630 pullPresenceNotifyEvent(List<StatsEvent> data)631 private int pullPresenceNotifyEvent(List<StatsEvent> data) { 632 PresenceNotifyEvent[] persistAtoms = mStorage.getPresenceNotifyEvent(MIN_COOLDOWN_MILLIS); 633 if (persistAtoms != null) { 634 Arrays.stream(persistAtoms) 635 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 636 return StatsManager.PULL_SUCCESS; 637 } else { 638 Rlog.w(TAG, "PRESENCE_NOTIFY_EVENT pull too frequent, skipping"); 639 return StatsManager.PULL_SKIP; 640 } 641 } 642 pullGbaEvent(List<StatsEvent> data)643 private int pullGbaEvent(List<StatsEvent> data) { 644 GbaEvent[] persistAtoms = mStorage.getGbaEvent(MIN_COOLDOWN_MILLIS); 645 if (persistAtoms != null) { 646 Arrays.stream(persistAtoms) 647 .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); 648 return StatsManager.PULL_SUCCESS; 649 } else { 650 Rlog.w(TAG, "GBA_EVENT pull too frequent, skipping"); 651 return StatsManager.PULL_SKIP; 652 } 653 } 654 pullPerSimStatus(List<StatsEvent> data)655 private int pullPerSimStatus(List<StatsEvent> data) { 656 int result = StatsManager.PULL_SKIP; 657 for (Phone phone : getPhonesIfAny()) { 658 PerSimStatus perSimStatus = PerSimStatus.getCurrentState(phone); 659 if (perSimStatus == null) { 660 continue; 661 } 662 StatsEvent statsEvent = TelephonyStatsLog.buildStatsEvent( 663 PER_SIM_STATUS, 664 phone.getPhoneId(), // simSlotIndex 665 perSimStatus.carrierId, // carrierId 666 perSimStatus.phoneNumberSourceUicc, // phoneNumberSourceUicc 667 perSimStatus.phoneNumberSourceCarrier, // phoneNumberSourceCarrier 668 perSimStatus.phoneNumberSourceIms, // phoneNumberSourceIms 669 perSimStatus.advancedCallingSettingEnabled, // volteEnabled 670 perSimStatus.voWiFiSettingEnabled, // wfcEnabled 671 perSimStatus.voWiFiModeSetting, // wfcMode 672 perSimStatus.voWiFiRoamingModeSetting, // wfcRoamingMode 673 perSimStatus.vtSettingEnabled, // videoCallingEnabled 674 perSimStatus.dataRoamingEnabled, // dataRoamingEnabled 675 perSimStatus.preferredNetworkType, // allowedNetworksByUser 676 perSimStatus.disabled2g, // is2gDisabled 677 perSimStatus.pin1Enabled, // isPin1Enabled 678 perSimStatus.minimumVoltageClass, // simVoltageClass 679 perSimStatus.userModifiedApnTypes, // userModifiedApnTypeBitmask 680 perSimStatus.unmeteredNetworks); // unmeteredNetworks 681 data.add(statsEvent); 682 result = StatsManager.PULL_SUCCESS; 683 } 684 return result; 685 } 686 687 /** Registers a pulled atom ID {@code atomId}. */ registerAtom(int atomId)688 private void registerAtom(int atomId) { 689 mStatsManager.setPullAtomCallback(atomId, /* metadata= */ null, 690 ConcurrentUtils.DIRECT_EXECUTOR, this); 691 } 692 buildStatsEvent(CellularDataServiceSwitch serviceSwitch)693 private static StatsEvent buildStatsEvent(CellularDataServiceSwitch serviceSwitch) { 694 return TelephonyStatsLog.buildStatsEvent( 695 CELLULAR_DATA_SERVICE_SWITCH, 696 serviceSwitch.ratFrom, 697 serviceSwitch.ratTo, 698 serviceSwitch.simSlotIndex, 699 serviceSwitch.isMultiSim, 700 serviceSwitch.carrierId, 701 serviceSwitch.switchCount); 702 } 703 buildStatsEvent(CellularServiceState state)704 private static StatsEvent buildStatsEvent(CellularServiceState state) { 705 return TelephonyStatsLog.buildStatsEvent( 706 CELLULAR_SERVICE_STATE, 707 state.voiceRat, 708 state.dataRat, 709 state.voiceRoamingType, 710 state.dataRoamingType, 711 state.isEndc, 712 state.simSlotIndex, 713 state.isMultiSim, 714 state.carrierId, 715 (int) (round(state.totalTimeMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS), 716 state.isEmergencyOnly); 717 } 718 buildStatsEvent(VoiceCallRatUsage usage)719 private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) { 720 return TelephonyStatsLog.buildStatsEvent( 721 VOICE_CALL_RAT_USAGE, 722 usage.carrierId, 723 usage.rat, 724 round(usage.totalDurationMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS, 725 usage.callCount); 726 } 727 buildStatsEvent(VoiceCallSession session)728 private static StatsEvent buildStatsEvent(VoiceCallSession session) { 729 return TelephonyStatsLog.buildStatsEvent( 730 VOICE_CALL_SESSION, 731 session.bearerAtStart, 732 session.bearerAtEnd, 733 session.direction, 734 session.setupDuration, 735 session.setupFailed, 736 session.disconnectReasonCode, 737 session.disconnectExtraCode, 738 session.disconnectExtraMessage, 739 session.ratAtStart, 740 session.ratAtEnd, 741 session.ratSwitchCount, 742 session.codecBitmask, 743 session.concurrentCallCountAtStart, 744 session.concurrentCallCountAtEnd, 745 session.simSlotIndex, 746 session.isMultiSim, 747 session.isEsim, 748 session.carrierId, 749 session.srvccCompleted, 750 session.srvccFailureCount, 751 session.srvccCancellationCount, 752 session.rttEnabled, 753 session.isEmergency, 754 session.isRoaming, 755 // workaround: dimension required for keeping multiple pulled atoms 756 sRandom.nextInt(), 757 // New fields introduced in Android S 758 session.signalStrengthAtEnd, 759 session.bandAtEnd, 760 session.setupDurationMillis, 761 session.mainCodecQuality, 762 session.videoEnabled, 763 session.ratAtConnected, 764 session.isMultiparty, 765 session.callDuration, 766 session.lastKnownRat); 767 } 768 buildStatsEvent(IncomingSms sms)769 private static StatsEvent buildStatsEvent(IncomingSms sms) { 770 return TelephonyStatsLog.buildStatsEvent( 771 INCOMING_SMS, 772 sms.smsFormat, 773 sms.smsTech, 774 sms.rat, 775 sms.smsType, 776 sms.totalParts, 777 sms.receivedParts, 778 sms.blocked, 779 sms.error, 780 sms.isRoaming, 781 sms.simSlotIndex, 782 sms.isMultiSim, 783 sms.isEsim, 784 sms.carrierId, 785 sms.messageId, 786 sms.count); 787 } 788 buildStatsEvent(OutgoingSms sms)789 private static StatsEvent buildStatsEvent(OutgoingSms sms) { 790 return TelephonyStatsLog.buildStatsEvent( 791 OUTGOING_SMS, 792 sms.smsFormat, 793 sms.smsTech, 794 sms.rat, 795 sms.sendResult, 796 sms.errorCode, 797 sms.isRoaming, 798 sms.isFromDefaultApp, 799 sms.simSlotIndex, 800 sms.isMultiSim, 801 sms.isEsim, 802 sms.carrierId, 803 sms.messageId, 804 sms.retryId, 805 sms.intervalMillis, 806 sms.count); 807 } 808 buildStatsEvent(DataCallSession dataCallSession)809 private static StatsEvent buildStatsEvent(DataCallSession dataCallSession) { 810 return TelephonyStatsLog.buildStatsEvent( 811 DATA_CALL_SESSION, 812 dataCallSession.dimension, 813 dataCallSession.isMultiSim, 814 dataCallSession.isEsim, 815 0, // profile is deprecated, so we default to 0 816 dataCallSession.apnTypeBitmask, 817 dataCallSession.carrierId, 818 dataCallSession.isRoaming, 819 dataCallSession.ratAtEnd, 820 dataCallSession.oosAtEnd, 821 dataCallSession.ratSwitchCount, 822 dataCallSession.isOpportunistic, 823 dataCallSession.ipType, 824 dataCallSession.setupFailed, 825 dataCallSession.failureCause, 826 dataCallSession.suggestedRetryMillis, 827 dataCallSession.deactivateReason, 828 round(dataCallSession.durationMinutes, DURATION_BUCKET_MILLIS / MINUTE_IN_MILLIS), 829 dataCallSession.ongoing, 830 dataCallSession.bandAtEnd, 831 dataCallSession.handoverFailureCauses, 832 dataCallSession.handoverFailureRat); 833 } 834 buildStatsEvent(ImsRegistrationStats stats)835 private static StatsEvent buildStatsEvent(ImsRegistrationStats stats) { 836 return TelephonyStatsLog.buildStatsEvent( 837 IMS_REGISTRATION_STATS, 838 stats.carrierId, 839 stats.simSlotIndex, 840 stats.rat, 841 (int) (round(stats.registeredMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS), 842 (int) (round(stats.voiceCapableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS), 843 (int) 844 (round(stats.voiceAvailableMillis, DURATION_BUCKET_MILLIS) 845 / SECOND_IN_MILLIS), 846 (int) (round(stats.smsCapableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS), 847 (int) (round(stats.smsAvailableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS), 848 (int) (round(stats.videoCapableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS), 849 (int) 850 (round(stats.videoAvailableMillis, DURATION_BUCKET_MILLIS) 851 / SECOND_IN_MILLIS), 852 (int) (round(stats.utCapableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS), 853 (int) (round(stats.utAvailableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS)); 854 } 855 buildStatsEvent(ImsRegistrationTermination termination)856 private static StatsEvent buildStatsEvent(ImsRegistrationTermination termination) { 857 return TelephonyStatsLog.buildStatsEvent( 858 IMS_REGISTRATION_TERMINATION, 859 termination.carrierId, 860 termination.isMultiSim, 861 termination.ratAtEnd, 862 termination.setupFailed, 863 termination.reasonCode, 864 termination.extraCode, 865 termination.extraMessage, 866 termination.count); 867 } 868 buildStatsEvent(NetworkRequestsV2 networkRequests)869 private static StatsEvent buildStatsEvent(NetworkRequestsV2 networkRequests) { 870 return TelephonyStatsLog.buildStatsEvent( 871 TELEPHONY_NETWORK_REQUESTS_V2, 872 networkRequests.carrierId, 873 networkRequests.capability, 874 networkRequests.requestCount); 875 } 876 buildStatsEvent(ImsRegistrationFeatureTagStats stats)877 private static StatsEvent buildStatsEvent(ImsRegistrationFeatureTagStats stats) { 878 return TelephonyStatsLog.buildStatsEvent( 879 IMS_REGISTRATION_FEATURE_TAG_STATS, 880 stats.carrierId, 881 stats.slotId, 882 stats.featureTagName, 883 stats.registrationTech, 884 (int) (round(stats.registeredMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS)); 885 } 886 buildStatsEvent(RcsClientProvisioningStats stats)887 private static StatsEvent buildStatsEvent(RcsClientProvisioningStats stats) { 888 return TelephonyStatsLog.buildStatsEvent( 889 RCS_CLIENT_PROVISIONING_STATS, 890 stats.carrierId, 891 stats.slotId, 892 stats.event, 893 stats.count); 894 } 895 buildStatsEvent(RcsAcsProvisioningStats stats)896 private static StatsEvent buildStatsEvent(RcsAcsProvisioningStats stats) { 897 return TelephonyStatsLog.buildStatsEvent( 898 RCS_ACS_PROVISIONING_STATS, 899 stats.carrierId, 900 stats.slotId, 901 stats.responseCode, 902 stats.responseType, 903 stats.isSingleRegistrationEnabled, 904 stats.count, 905 (int) (round(stats.stateTimerMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS)); 906 } 907 buildStatsEvent(SipDelegateStats stats)908 private static StatsEvent buildStatsEvent(SipDelegateStats stats) { 909 return TelephonyStatsLog.buildStatsEvent( 910 SIP_DELEGATE_STATS, 911 stats.dimension, 912 stats.carrierId, 913 stats.slotId, 914 (int) (round(stats.uptimeMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS), 915 stats.destroyReason); 916 } 917 buildStatsEvent(SipTransportFeatureTagStats stats)918 private static StatsEvent buildStatsEvent(SipTransportFeatureTagStats stats) { 919 return TelephonyStatsLog.buildStatsEvent( 920 SIP_TRANSPORT_FEATURE_TAG_STATS, 921 stats.carrierId, 922 stats.slotId, 923 stats.featureTagName, 924 stats.sipTransportDeniedReason, 925 stats.sipTransportDeregisteredReason, 926 (int) (round(stats.associatedMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS)); 927 } 928 buildStatsEvent(SipMessageResponse stats)929 private static StatsEvent buildStatsEvent(SipMessageResponse stats) { 930 return TelephonyStatsLog.buildStatsEvent( 931 SIP_MESSAGE_RESPONSE, 932 stats.carrierId, 933 stats.slotId, 934 stats.sipMessageMethod, 935 stats.sipMessageResponse, 936 stats.sipMessageDirection, 937 stats.messageError, 938 stats.count); 939 } 940 buildStatsEvent(SipTransportSession stats)941 private static StatsEvent buildStatsEvent(SipTransportSession stats) { 942 return TelephonyStatsLog.buildStatsEvent( 943 SIP_TRANSPORT_SESSION, 944 stats.carrierId, 945 stats.slotId, 946 stats.sessionMethod, 947 stats.sipMessageDirection, 948 stats.sipResponse, 949 stats.sessionCount, 950 stats.endedGracefullyCount); 951 } 952 buildStatsEvent(ImsDedicatedBearerListenerEvent stats)953 private static StatsEvent buildStatsEvent(ImsDedicatedBearerListenerEvent stats) { 954 return TelephonyStatsLog.buildStatsEvent( 955 IMS_DEDICATED_BEARER_LISTENER_EVENT, 956 stats.carrierId, 957 stats.slotId, 958 stats.ratAtEnd, 959 stats.qci, 960 stats.dedicatedBearerEstablished, 961 stats.eventCount); 962 } 963 buildStatsEvent(ImsDedicatedBearerEvent stats)964 private static StatsEvent buildStatsEvent(ImsDedicatedBearerEvent stats) { 965 return TelephonyStatsLog.buildStatsEvent( 966 IMS_DEDICATED_BEARER_EVENT, 967 stats.carrierId, 968 stats.slotId, 969 stats.ratAtEnd, 970 stats.qci, 971 stats.bearerState, 972 stats.localConnectionInfoReceived, 973 stats.remoteConnectionInfoReceived, 974 stats.hasListeners, 975 stats.count); 976 } 977 buildStatsEvent(ImsRegistrationServiceDescStats stats)978 private static StatsEvent buildStatsEvent(ImsRegistrationServiceDescStats stats) { 979 return TelephonyStatsLog.buildStatsEvent( 980 IMS_REGISTRATION_SERVICE_DESC_STATS, 981 stats.carrierId, 982 stats.slotId, 983 stats.serviceIdName, 984 stats.serviceIdVersion, 985 stats.registrationTech, 986 (int) (round(stats.publishedMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS)); 987 } 988 buildStatsEvent(UceEventStats stats)989 private static StatsEvent buildStatsEvent(UceEventStats stats) { 990 return TelephonyStatsLog.buildStatsEvent( 991 UCE_EVENT_STATS, 992 stats.carrierId, 993 stats.slotId, 994 stats.type, 995 stats.successful, 996 stats.commandCode, 997 stats.networkResponse, 998 stats.count); 999 } 1000 buildStatsEvent(PresenceNotifyEvent stats)1001 private static StatsEvent buildStatsEvent(PresenceNotifyEvent stats) { 1002 return TelephonyStatsLog.buildStatsEvent( 1003 PRESENCE_NOTIFY_EVENT, 1004 stats.carrierId, 1005 stats.slotId, 1006 stats.reason, 1007 stats.contentBodyReceived, 1008 stats.rcsCapsCount, 1009 stats.mmtelCapsCount, 1010 stats.noCapsCount, 1011 stats.count); 1012 } 1013 buildStatsEvent(GbaEvent stats)1014 private static StatsEvent buildStatsEvent(GbaEvent stats) { 1015 return TelephonyStatsLog.buildStatsEvent( 1016 GBA_EVENT, 1017 stats.carrierId, 1018 stats.slotId, 1019 stats.successful, 1020 stats.failedReason, 1021 stats.count); 1022 } 1023 1024 /** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */ getPhonesIfAny()1025 private static Phone[] getPhonesIfAny() { 1026 try { 1027 return PhoneFactory.getPhones(); 1028 } catch (IllegalStateException e) { 1029 // Phones have not been made yet 1030 return new Phone[0]; 1031 } 1032 } 1033 1034 /** Returns the value rounded to the bucket. */ round(long value, long bucket)1035 private static long round(long value, long bucket) { 1036 return bucket == 0 ? value : ((value + bucket / 2) / bucket) * bucket; 1037 } 1038 } 1039