• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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