• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.MINUTE_IN_MILLIS;
20 
21 import static com.android.internal.telephony.InboundSmsHandler.SOURCE_INJECTED_FROM_IMS;
22 import static com.android.internal.telephony.InboundSmsHandler.SOURCE_NOT_INJECTED;
23 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ANSWER;
24 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CDMA_SEND_SMS;
25 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE_DATA_CALL;
26 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DIAL;
27 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP;
28 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND;
29 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND;
30 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IMS_SEND_SMS;
31 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS;
32 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE;
33 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL;
34 import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.NUM_SIGNAL_LEVEL;
35 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IP;
36 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;
37 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV6;
38 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_NON_IP;
39 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_PPP;
40 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_UNSTRUCTURED;
41 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_UNKNOWN;
42 
43 import android.content.Context;
44 import android.net.NetworkCapabilities;
45 import android.os.BatteryStatsManager;
46 import android.os.Build;
47 import android.os.SystemClock;
48 import android.os.SystemProperties;
49 import android.provider.Telephony.Sms.Intents;
50 import android.telephony.AccessNetworkConstants;
51 import android.telephony.Annotation.RadioPowerState;
52 import android.telephony.CallQuality;
53 import android.telephony.DisconnectCause;
54 import android.telephony.NetworkRegistrationInfo;
55 import android.telephony.ServiceState;
56 import android.telephony.SmsManager;
57 import android.telephony.SmsMessage;
58 import android.telephony.SubscriptionInfo;
59 import android.telephony.SubscriptionManager;
60 import android.telephony.TelephonyHistogram;
61 import android.telephony.TelephonyManager;
62 import android.telephony.TelephonyManager.PrefNetworkMode;
63 import android.telephony.data.DataCallResponse;
64 import android.telephony.data.DataService;
65 import android.telephony.emergency.EmergencyNumber;
66 import android.telephony.ims.ImsCallProfile;
67 import android.telephony.ims.ImsCallSession;
68 import android.telephony.ims.ImsReasonInfo;
69 import android.telephony.ims.ImsStreamMediaProfile;
70 import android.telephony.ims.feature.MmTelFeature;
71 import android.telephony.ims.stub.ImsRegistrationImplBase;
72 import android.telephony.ims.stub.ImsSmsImplBase;
73 import android.text.TextUtils;
74 import android.util.ArrayMap;
75 import android.util.Base64;
76 import android.util.SparseArray;
77 
78 import com.android.internal.telephony.CarrierResolver;
79 import com.android.internal.telephony.DriverCall;
80 import com.android.internal.telephony.GsmCdmaConnection;
81 import com.android.internal.telephony.InboundSmsHandler;
82 import com.android.internal.telephony.PhoneConstants;
83 import com.android.internal.telephony.RIL;
84 import com.android.internal.telephony.RILConstants;
85 import com.android.internal.telephony.SmsController;
86 import com.android.internal.telephony.SmsResponse;
87 import com.android.internal.telephony.UUSInfo;
88 import com.android.internal.telephony.dataconnection.LinkBandwidthEstimator;
89 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
90 import com.android.internal.telephony.imsphone.ImsPhoneCall;
91 import com.android.internal.telephony.nano.TelephonyProto;
92 import com.android.internal.telephony.nano.TelephonyProto.ActiveSubscriptionInfo;
93 import com.android.internal.telephony.nano.TelephonyProto.BandwidthEstimatorStats;
94 import com.android.internal.telephony.nano.TelephonyProto.EmergencyNumberInfo;
95 import com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities;
96 import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
97 import com.android.internal.telephony.nano.TelephonyProto.ModemPowerStats;
98 import com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
99 import com.android.internal.telephony.nano.TelephonyProto.SimState;
100 import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
101 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
102 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.CallState;
103 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.RilCall;
104 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.RilCall.Type;
105 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
106 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatching;
107 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatchingResult;
108 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierKeyChange;
109 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch;
110 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart;
111 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.NetworkCapabilitiesInfo;
112 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch;
113 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RadioState;
114 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
115 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall.DeactivateReason;
116 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCall;
117 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse;
118 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse.RilDataCallFailCause;
119 import com.android.internal.telephony.nano.TelephonyProto.TelephonyLog;
120 import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState;
121 import com.android.internal.telephony.nano.TelephonyProto.TelephonySettings;
122 import com.android.internal.telephony.nano.TelephonyProto.TimeInterval;
123 import com.android.internal.telephony.protobuf.nano.MessageNano;
124 import com.android.internal.telephony.util.TelephonyUtils;
125 import com.android.internal.util.IndentingPrintWriter;
126 import com.android.telephony.Rlog;
127 
128 import java.io.FileDescriptor;
129 import java.io.PrintWriter;
130 import java.text.DecimalFormat;
131 import java.util.ArrayDeque;
132 import java.util.ArrayList;
133 import java.util.Arrays;
134 import java.util.Deque;
135 import java.util.List;
136 import java.util.Map;
137 import java.util.concurrent.ThreadLocalRandom;
138 
139 /**
140  * Telephony metrics holds all metrics events and convert it into telephony proto buf.
141  * @hide
142  */
143 public class TelephonyMetrics {
144 
145     private static final String TAG = TelephonyMetrics.class.getSimpleName();
146 
147     private static final boolean DBG = true;
148     private static final boolean VDBG = false; // STOPSHIP if true
149 
150     /** Maximum telephony events stored */
151     private static final int MAX_TELEPHONY_EVENTS = 1000;
152 
153     /** Maximum call sessions stored */
154     private static final int MAX_COMPLETED_CALL_SESSIONS = 50;
155 
156     /** Maximum sms sessions stored */
157     private static final int MAX_COMPLETED_SMS_SESSIONS = 500;
158 
159     /** For reducing the timing precision for privacy purposes */
160     private static final int SESSION_START_PRECISION_MINUTES = 5;
161 
162     /** The TelephonyMetrics singleton instance */
163     private static TelephonyMetrics sInstance;
164 
165     /** Telephony events */
166     private final Deque<TelephonyEvent> mTelephonyEvents = new ArrayDeque<>();
167 
168     /**
169      * In progress call sessions. Note that each phone can only have up to 1 in progress call
170      * session (might contains multiple calls). Having a sparse array in case we need to support
171      * DSDA in the future.
172      */
173     private final SparseArray<InProgressCallSession> mInProgressCallSessions = new SparseArray<>();
174 
175     /** The completed call sessions */
176     private final Deque<TelephonyCallSession> mCompletedCallSessions = new ArrayDeque<>();
177 
178     /** The in-progress SMS sessions. When finished, it will be moved into the completed sessions */
179     private final SparseArray<InProgressSmsSession> mInProgressSmsSessions = new SparseArray<>();
180 
181     /** The completed SMS sessions */
182     private final Deque<SmsSession> mCompletedSmsSessions = new ArrayDeque<>();
183 
184     /** Last service state. This is for injecting the base of a new log or a new call/sms session */
185     private final SparseArray<TelephonyServiceState> mLastServiceState = new SparseArray<>();
186 
187     /**
188      * Last ims capabilities. This is for injecting the base of a new log or a new call/sms session
189      */
190     private final SparseArray<ImsCapabilities> mLastImsCapabilities = new SparseArray<>();
191 
192     /**
193      * Last IMS connection state. This is for injecting the base of a new log or a new call/sms
194      * session
195      */
196     private final SparseArray<ImsConnectionState> mLastImsConnectionState = new SparseArray<>();
197 
198     /** Last settings state. This is for deduping same settings event logged. */
199     private final SparseArray<TelephonySettings> mLastSettings = new SparseArray<>();
200 
201     /** Last sim state, indexed by phone id. */
202     private final SparseArray<Integer> mLastSimState = new SparseArray<>();
203 
204     /** Last radio state, indexed by phone id. */
205     private final SparseArray<Integer> mLastRadioState = new SparseArray<>();
206 
207     /** Last active subscription information, indexed by phone id. */
208     private final SparseArray<ActiveSubscriptionInfo> mLastActiveSubscriptionInfos =
209             new SparseArray<>();
210 
211     /**
212      * The last modem state represent by a bitmap, the i-th bit(LSB) indicates the i-th modem
213      * state(0 - disabled, 1 - enabled).
214      *
215      * TODO: initialize the enabled modem bitmap when it's possible to get the modem state.
216      */
217     private int mLastEnabledModemBitmap = (1 << TelephonyManager.getDefault().getPhoneCount()) - 1;
218 
219     /** Last carrier id matching. */
220     private final SparseArray<CarrierIdMatching> mLastCarrierId = new SparseArray<>();
221 
222     /** Last NetworkCapabilitiesInfo, indexed by phone id. */
223     private final SparseArray<NetworkCapabilitiesInfo> mLastNetworkCapabilitiesInfos =
224             new SparseArray<>();
225 
226     /** Last RilDataCall Events (indexed by cid), indexed by phone id */
227     private final SparseArray<SparseArray<RilDataCall>> mLastRilDataCallEvents =
228             new SparseArray<>();
229 
230     /** List of Tx and Rx Bandwidth estimation stats maps */
231     private final List<Map<String, BwEstimationStats>> mBwEstStatsMapList = new ArrayList<>(
232             Arrays.asList(new ArrayMap<>(), new ArrayMap<>()));
233 
234     /** The start system time of the TelephonyLog in milliseconds*/
235     private long mStartSystemTimeMs;
236 
237     /** The start elapsed time of the TelephonyLog in milliseconds*/
238     private long mStartElapsedTimeMs;
239 
240     /** Indicating if some of the telephony events are dropped in this log */
241     private boolean mTelephonyEventsDropped = false;
242 
243     private Context mContext;
244 
TelephonyMetrics()245     public TelephonyMetrics() {
246         mStartSystemTimeMs = System.currentTimeMillis();
247         mStartElapsedTimeMs = SystemClock.elapsedRealtime();
248     }
249 
250     /**
251      * Get the singleton instance of telephony metrics.
252      *
253      * @return The instance
254      */
getInstance()255     public synchronized static TelephonyMetrics getInstance() {
256         if (sInstance == null) {
257             sInstance = new TelephonyMetrics();
258         }
259 
260         return sInstance;
261     }
262 
263     /**
264      * Set the context for telephony metrics.
265      *
266      * @param context Context
267      * @hide
268      */
setContext(Context context)269     public void setContext(Context context) {
270         mContext = context;
271     }
272 
273     /**
274      * Dump the state of various objects, add calls to other objects as desired.
275      *
276      * @param fd File descriptor
277      * @param pw Print writer
278      * @param args Arguments
279      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)280     public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
281         if (args != null && args.length > 0) {
282             boolean reset = true;
283             if (args.length > 1 && "--keep".equals(args[1])) {
284                 reset = false;
285             }
286 
287             switch (args[0]) {
288                 case "--metrics":
289                     printAllMetrics(pw);
290                     break;
291                 case "--metricsproto":
292                     pw.println(convertProtoToBase64String(buildProto()));
293                     if (reset) {
294                         reset();
295                     }
296                     break;
297                 case "--metricsprototext":
298                     pw.println(buildProto().toString());
299                     break;
300             }
301         }
302     }
303 
logv(String log)304     private void logv(String log) {
305         if (VDBG) {
306             Rlog.v(TAG, log);
307         }
308     }
309 
310     /**
311      * Convert the telephony event to string
312      *
313      * @param event The event in integer
314      * @return The event in string
315      */
telephonyEventToString(int event)316     private static String telephonyEventToString(int event) {
317         switch (event) {
318             case TelephonyEvent.Type.UNKNOWN:
319                 return "UNKNOWN";
320             case TelephonyEvent.Type.SETTINGS_CHANGED:
321                 return "SETTINGS_CHANGED";
322             case TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED:
323                 return "RIL_SERVICE_STATE_CHANGED";
324             case TelephonyEvent.Type.IMS_CONNECTION_STATE_CHANGED:
325                 return "IMS_CONNECTION_STATE_CHANGED";
326             case TelephonyEvent.Type.IMS_CAPABILITIES_CHANGED:
327                 return "IMS_CAPABILITIES_CHANGED";
328             case TelephonyEvent.Type.DATA_CALL_SETUP:
329                 return "DATA_CALL_SETUP";
330             case TelephonyEvent.Type.DATA_CALL_SETUP_RESPONSE:
331                 return "DATA_CALL_SETUP_RESPONSE";
332             case TelephonyEvent.Type.DATA_CALL_LIST_CHANGED:
333                 return "DATA_CALL_LIST_CHANGED";
334             case TelephonyEvent.Type.DATA_CALL_DEACTIVATE:
335                 return "DATA_CALL_DEACTIVATE";
336             case TelephonyEvent.Type.DATA_CALL_DEACTIVATE_RESPONSE:
337                 return "DATA_CALL_DEACTIVATE_RESPONSE";
338             case TelephonyEvent.Type.DATA_STALL_ACTION:
339                 return "DATA_STALL_ACTION";
340             case TelephonyEvent.Type.MODEM_RESTART:
341                 return "MODEM_RESTART";
342             case TelephonyEvent.Type.CARRIER_ID_MATCHING:
343                 return "CARRIER_ID_MATCHING";
344             case TelephonyEvent.Type.NITZ_TIME:
345                 return "NITZ_TIME";
346             case TelephonyEvent.Type.EMERGENCY_NUMBER_REPORT:
347                 return "EMERGENCY_NUMBER_REPORT";
348             case TelephonyEvent.Type.NETWORK_CAPABILITIES_CHANGED:
349                 return "NETWORK_CAPABILITIES_CHANGED";
350             default:
351                 return Integer.toString(event);
352         }
353     }
354 
355     /**
356      * Convert the call session event into string
357      *
358      * @param event The event in integer
359      * @return The event in String
360      */
callSessionEventToString(int event)361     private static String callSessionEventToString(int event) {
362         switch (event) {
363             case TelephonyCallSession.Event.Type.EVENT_UNKNOWN:
364                 return "EVENT_UNKNOWN";
365             case TelephonyCallSession.Event.Type.SETTINGS_CHANGED:
366                 return "SETTINGS_CHANGED";
367             case TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED:
368                 return "RIL_SERVICE_STATE_CHANGED";
369             case TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED:
370                 return "IMS_CONNECTION_STATE_CHANGED";
371             case TelephonyCallSession.Event.Type.IMS_CAPABILITIES_CHANGED:
372                 return "IMS_CAPABILITIES_CHANGED";
373             case TelephonyCallSession.Event.Type.DATA_CALL_LIST_CHANGED:
374                 return "DATA_CALL_LIST_CHANGED";
375             case TelephonyCallSession.Event.Type.RIL_REQUEST:
376                 return "RIL_REQUEST";
377             case TelephonyCallSession.Event.Type.RIL_RESPONSE:
378                 return "RIL_RESPONSE";
379             case TelephonyCallSession.Event.Type.RIL_CALL_RING:
380                 return "RIL_CALL_RING";
381             case TelephonyCallSession.Event.Type.RIL_CALL_SRVCC:
382                 return "RIL_CALL_SRVCC";
383             case TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED:
384                 return "RIL_CALL_LIST_CHANGED";
385             case TelephonyCallSession.Event.Type.IMS_COMMAND:
386                 return "IMS_COMMAND";
387             case TelephonyCallSession.Event.Type.IMS_COMMAND_RECEIVED:
388                 return "IMS_COMMAND_RECEIVED";
389             case TelephonyCallSession.Event.Type.IMS_COMMAND_FAILED:
390                 return "IMS_COMMAND_FAILED";
391             case TelephonyCallSession.Event.Type.IMS_COMMAND_COMPLETE:
392                 return "IMS_COMMAND_COMPLETE";
393             case TelephonyCallSession.Event.Type.IMS_CALL_RECEIVE:
394                 return "IMS_CALL_RECEIVE";
395             case TelephonyCallSession.Event.Type.IMS_CALL_STATE_CHANGED:
396                 return "IMS_CALL_STATE_CHANGED";
397             case TelephonyCallSession.Event.Type.IMS_CALL_TERMINATED:
398                 return "IMS_CALL_TERMINATED";
399             case TelephonyCallSession.Event.Type.IMS_CALL_HANDOVER:
400                 return "IMS_CALL_HANDOVER";
401             case TelephonyCallSession.Event.Type.IMS_CALL_HANDOVER_FAILED:
402                 return "IMS_CALL_HANDOVER_FAILED";
403             case TelephonyCallSession.Event.Type.PHONE_STATE_CHANGED:
404                 return "PHONE_STATE_CHANGED";
405             case TelephonyCallSession.Event.Type.NITZ_TIME:
406                 return "NITZ_TIME";
407             case TelephonyCallSession.Event.Type.AUDIO_CODEC:
408                 return "AUDIO_CODEC";
409             default:
410                 return Integer.toString(event);
411         }
412     }
413 
414     /**
415      * Convert the SMS session event into string
416      * @param event The event in integer
417      * @return The event in String
418      */
smsSessionEventToString(int event)419     private static String smsSessionEventToString(int event) {
420         switch (event) {
421             case SmsSession.Event.Type.EVENT_UNKNOWN:
422                 return "EVENT_UNKNOWN";
423             case SmsSession.Event.Type.SETTINGS_CHANGED:
424                 return "SETTINGS_CHANGED";
425             case SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED:
426                 return "RIL_SERVICE_STATE_CHANGED";
427             case SmsSession.Event.Type.IMS_CONNECTION_STATE_CHANGED:
428                 return "IMS_CONNECTION_STATE_CHANGED";
429             case SmsSession.Event.Type.IMS_CAPABILITIES_CHANGED:
430                 return "IMS_CAPABILITIES_CHANGED";
431             case SmsSession.Event.Type.DATA_CALL_LIST_CHANGED:
432                 return "DATA_CALL_LIST_CHANGED";
433             case SmsSession.Event.Type.SMS_SEND:
434                 return "SMS_SEND";
435             case SmsSession.Event.Type.SMS_SEND_RESULT:
436                 return "SMS_SEND_RESULT";
437             case SmsSession.Event.Type.SMS_RECEIVED:
438                 return "SMS_RECEIVED";
439             case SmsSession.Event.Type.INCOMPLETE_SMS_RECEIVED:
440                 return "INCOMPLETE_SMS_RECEIVED";
441             default:
442                 return Integer.toString(event);
443         }
444     }
445 
446     /**
447      * Print all metrics data for debugging purposes
448      *
449      * @param rawWriter Print writer
450      */
printAllMetrics(PrintWriter rawWriter)451     private synchronized void printAllMetrics(PrintWriter rawWriter) {
452         final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, "  ");
453 
454         pw.println("Telephony metrics proto:");
455         pw.println("------------------------------------------");
456         pw.println("Telephony events:");
457         pw.increaseIndent();
458         for (TelephonyEvent event : mTelephonyEvents) {
459             pw.print(event.timestampMillis);
460             pw.print(" [");
461             pw.print(event.phoneId);
462             pw.print("] ");
463 
464             pw.print("T=");
465             if (event.type == TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED) {
466                 pw.print(telephonyEventToString(event.type)
467                         + "(" + "Data RAT " + event.serviceState.dataRat
468                         + " Voice RAT " + event.serviceState.voiceRat
469                         + " Channel Number " + event.serviceState.channelNumber
470                         + " NR Frequency Range " + event.serviceState.nrFrequencyRange
471                         + " NR State " + event.serviceState.nrState
472                         + ")");
473                 for (int i = 0; i < event.serviceState.networkRegistrationInfo.length; i++) {
474                     pw.print("reg info: domain="
475                             + event.serviceState.networkRegistrationInfo[i].domain
476                             + ", rat=" + event.serviceState.networkRegistrationInfo[i].rat);
477                 }
478             } else {
479                 pw.print(telephonyEventToString(event.type));
480             }
481 
482             pw.println("");
483         }
484 
485         pw.decreaseIndent();
486         pw.println("Call sessions:");
487         pw.increaseIndent();
488 
489         for (TelephonyCallSession callSession : mCompletedCallSessions) {
490             pw.print("Start time in minutes: " + callSession.startTimeMinutes);
491             pw.print(", phone: " + callSession.phoneId);
492             if (callSession.eventsDropped) {
493                 pw.println(", events dropped: " + callSession.eventsDropped);
494             } else {
495                 pw.println("");
496             }
497 
498             pw.println("Events: ");
499             pw.increaseIndent();
500             for (TelephonyCallSession.Event event : callSession.events) {
501                 pw.print(event.delay);
502                 pw.print(" T=");
503                 if (event.type == TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED) {
504                     pw.println(callSessionEventToString(event.type)
505                             + "(" + "Data RAT " + event.serviceState.dataRat
506                             + " Voice RAT " + event.serviceState.voiceRat
507                             + " Channel Number " + event.serviceState.channelNumber
508                             + " NR Frequency Range " + event.serviceState.nrFrequencyRange
509                             + " NR State " + event.serviceState.nrState
510                             + ")");
511                 } else if (event.type == TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED) {
512                     pw.println(callSessionEventToString(event.type));
513                     pw.increaseIndent();
514                     for (RilCall call : event.calls) {
515                         pw.println(call.index + ". Type = " + call.type + " State = "
516                                 + call.state + " End Reason " + call.callEndReason
517                                 + " Precise Disconnect Cause " + call.preciseDisconnectCause
518                                 + " isMultiparty = " + call.isMultiparty);
519                     }
520                     pw.decreaseIndent();
521                 } else if (event.type == TelephonyCallSession.Event.Type.AUDIO_CODEC) {
522                     pw.println(callSessionEventToString(event.type)
523                             + "(" + event.audioCodec + ")");
524                 } else {
525                     pw.println(callSessionEventToString(event.type));
526                 }
527             }
528             pw.decreaseIndent();
529         }
530 
531         pw.decreaseIndent();
532         pw.println("Sms sessions:");
533         pw.increaseIndent();
534 
535         int count = 0;
536         for (SmsSession smsSession : mCompletedSmsSessions) {
537             count++;
538             pw.print("[" + count + "] Start time in minutes: "
539                     + smsSession.startTimeMinutes);
540             pw.print(", phone: " + smsSession.phoneId);
541             if (smsSession.eventsDropped) {
542                 pw.println(", events dropped: " + smsSession.eventsDropped);
543             } else {
544                 pw.println("");
545             }
546             pw.println("Events: ");
547             pw.increaseIndent();
548             for (SmsSession.Event event : smsSession.events) {
549                 pw.print(event.delay);
550                 pw.print(" T=");
551                 if (event.type == SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED) {
552                     pw.println(smsSessionEventToString(event.type)
553                             + "(" + "Data RAT " + event.serviceState.dataRat
554                             + " Voice RAT " + event.serviceState.voiceRat
555                             + " Channel Number " + event.serviceState.channelNumber
556                             + " NR Frequency Range " + event.serviceState.nrFrequencyRange
557                             + " NR State " + event.serviceState.nrState
558                             + ")");
559                 } else if (event.type == SmsSession.Event.Type.SMS_RECEIVED) {
560                     pw.println(smsSessionEventToString(event.type));
561                     pw.increaseIndent();
562                     switch (event.smsType) {
563                         case SmsSession.Event.SmsType.SMS_TYPE_SMS_PP:
564                             pw.println("Type: SMS-PP");
565                             break;
566                         case SmsSession.Event.SmsType.SMS_TYPE_VOICEMAIL_INDICATION:
567                             pw.println("Type: Voicemail indication");
568                             break;
569                         case SmsSession.Event.SmsType.SMS_TYPE_ZERO:
570                             pw.println("Type: zero");
571                             break;
572                         case SmsSession.Event.SmsType.SMS_TYPE_WAP_PUSH:
573                             pw.println("Type: WAP PUSH");
574                             break;
575                         default:
576                             break;
577                     }
578                     if (event.errorCode != SmsManager.RESULT_ERROR_NONE) {
579                         pw.println("E=" + event.errorCode);
580                     }
581                     pw.decreaseIndent();
582                 } else if (event.type == SmsSession.Event.Type.SMS_SEND
583                         || event.type == SmsSession.Event.Type.SMS_SEND_RESULT) {
584                     pw.println(smsSessionEventToString(event.type));
585                     pw.increaseIndent();
586                     pw.println("ReqId=" + event.rilRequestId);
587                     pw.println("E=" + event.errorCode);
588                     pw.println("RilE=" + event.error);
589                     pw.println("ImsE=" + event.imsError);
590                     pw.decreaseIndent();
591                 } else if (event.type == SmsSession.Event.Type.INCOMPLETE_SMS_RECEIVED) {
592                     pw.println(smsSessionEventToString(event.type));
593                     pw.increaseIndent();
594                     pw.println("Received: " + event.incompleteSms.receivedParts + "/"
595                             + event.incompleteSms.totalParts);
596                     pw.decreaseIndent();
597                 }
598             }
599             pw.decreaseIndent();
600         }
601 
602         pw.decreaseIndent();
603         pw.println("Modem power stats:");
604         pw.increaseIndent();
605 
606         BatteryStatsManager batteryStatsManager = mContext == null ? null :
607                 (BatteryStatsManager) mContext.getSystemService(Context.BATTERY_STATS_SERVICE);
608         ModemPowerStats s = new ModemPowerMetrics(batteryStatsManager).buildProto();
609 
610         pw.println("Power log duration (battery time) (ms): " + s.loggingDurationMs);
611         pw.println("Energy consumed by modem (mAh): " + s.energyConsumedMah);
612         pw.println("Number of packets sent (tx): " + s.numPacketsTx);
613         pw.println("Number of bytes sent (tx): " + s.numBytesTx);
614         pw.println("Number of packets received (rx): " + s.numPacketsRx);
615         pw.println("Number of bytes received (rx): " + s.numBytesRx);
616         pw.println("Amount of time kernel is active because of cellular data (ms): "
617                 + s.cellularKernelActiveTimeMs);
618         pw.println("Amount of time spent in very poor rx signal level (ms): "
619                 + s.timeInVeryPoorRxSignalLevelMs);
620         pw.println("Amount of time modem is in sleep (ms): " + s.sleepTimeMs);
621         pw.println("Amount of time modem is in idle (ms): " + s.idleTimeMs);
622         pw.println("Amount of time modem is in rx (ms): " + s.rxTimeMs);
623         pw.println("Amount of time modem is in tx (ms): " + Arrays.toString(s.txTimeMs));
624         pw.println("Amount of time phone spent in various Radio Access Technologies (ms): "
625                 + Arrays.toString(s.timeInRatMs));
626         pw.println("Amount of time phone spent in various cellular "
627                 + "rx signal strength levels (ms): "
628                 + Arrays.toString(s.timeInRxSignalStrengthLevelMs));
629         pw.println("Energy consumed across measured modem rails (mAh): "
630                 + new DecimalFormat("#.##").format(s.monitoredRailEnergyConsumedMah));
631         pw.decreaseIndent();
632         pw.println("Hardware Version: " + SystemProperties.get("ro.boot.revision", ""));
633 
634         pw.decreaseIndent();
635         pw.println("LinkBandwidthEstimator stats:");
636         pw.increaseIndent();
637 
638         pw.println("Tx");
639         for (BwEstimationStats stats : mBwEstStatsMapList.get(0).values()) {
640             pw.println(stats.toString());
641         }
642 
643         pw.println("Rx");
644         for (BwEstimationStats stats : mBwEstStatsMapList.get(1).values()) {
645             pw.println(stats.toString());
646         }
647     }
648 
649     /**
650      * Convert the telephony proto into Base-64 encoded string
651      *
652      * @param proto Telephony proto
653      * @return Encoded string
654      */
convertProtoToBase64String(TelephonyLog proto)655     private static String convertProtoToBase64String(TelephonyLog proto) {
656         return Base64.encodeToString(
657                 TelephonyProto.TelephonyLog.toByteArray(proto), Base64.DEFAULT);
658     }
659 
660     /**
661      * Reset all events and sessions
662      */
reset()663     private synchronized void reset() {
664         mTelephonyEvents.clear();
665         mCompletedCallSessions.clear();
666         mCompletedSmsSessions.clear();
667         mBwEstStatsMapList.get(0).clear();
668         mBwEstStatsMapList.get(1).clear();
669 
670         mTelephonyEventsDropped = false;
671 
672         mStartSystemTimeMs = System.currentTimeMillis();
673         mStartElapsedTimeMs = SystemClock.elapsedRealtime();
674 
675         // Insert the last known sim state, enabled modem bitmap, active subscription info,
676         // service state, ims capabilities, ims connection states, carrier id and Data call
677         // events as the base.
678         // Sim state, modem bitmap and active subscription info events are logged before
679         // other events.
680         addTelephonyEvent(new TelephonyEventBuilder(mStartElapsedTimeMs, -1 /* phoneId */)
681                 .setSimStateChange(mLastSimState).build());
682 
683         addTelephonyEvent(new TelephonyEventBuilder(mStartElapsedTimeMs, -1 /* phoneId */)
684                 .setEnabledModemBitmap(mLastEnabledModemBitmap).build());
685 
686         for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) {
687           final int key = mLastActiveSubscriptionInfos.keyAt(i);
688           TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
689                   .setActiveSubscriptionInfoChange(mLastActiveSubscriptionInfos.get(key)).build();
690           addTelephonyEvent(event);
691         }
692 
693         for (int i = 0; i < mLastServiceState.size(); i++) {
694             final int key = mLastServiceState.keyAt(i);
695 
696             TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
697                     .setServiceState(mLastServiceState.get(key)).build();
698             addTelephonyEvent(event);
699         }
700 
701         for (int i = 0; i < mLastImsCapabilities.size(); i++) {
702             final int key = mLastImsCapabilities.keyAt(i);
703 
704             TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
705                     .setImsCapabilities(mLastImsCapabilities.get(key)).build();
706             addTelephonyEvent(event);
707         }
708 
709         for (int i = 0; i < mLastImsConnectionState.size(); i++) {
710             final int key = mLastImsConnectionState.keyAt(i);
711 
712             TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
713                     .setImsConnectionState(mLastImsConnectionState.get(key)).build();
714             addTelephonyEvent(event);
715         }
716 
717         for (int i = 0; i < mLastCarrierId.size(); i++) {
718             final int key = mLastCarrierId.keyAt(i);
719             TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
720                     .setCarrierIdMatching(mLastCarrierId.get(key)).build();
721             addTelephonyEvent(event);
722         }
723 
724         for (int i = 0; i < mLastNetworkCapabilitiesInfos.size(); i++) {
725             final int key = mLastNetworkCapabilitiesInfos.keyAt(i);
726             TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
727                     .setNetworkCapabilities(mLastNetworkCapabilitiesInfos.get(key)).build();
728             addTelephonyEvent(event);
729         }
730 
731         for (int i = 0; i < mLastRilDataCallEvents.size(); i++) {
732             final int key = mLastRilDataCallEvents.keyAt(i);
733             for (int j = 0; j < mLastRilDataCallEvents.get(key).size(); j++) {
734                 final int cidKey = mLastRilDataCallEvents.get(key).keyAt(j);
735                 RilDataCall[] dataCalls = new RilDataCall[1];
736                 dataCalls[0] = mLastRilDataCallEvents.get(key).get(cidKey);
737                 addTelephonyEvent(new TelephonyEventBuilder(mStartElapsedTimeMs, key)
738                         .setDataCalls(dataCalls).build());
739             }
740         }
741 
742         for (int i = 0; i < mLastRadioState.size(); i++) {
743             final int key = mLastRadioState.keyAt(i);
744             TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
745                     .setRadioState(mLastRadioState.get(key)).build();
746             addTelephonyEvent(event);
747         }
748     }
749 
750     /**
751      * Build the telephony proto
752      *
753      * @return Telephony proto
754      */
buildProto()755     private synchronized TelephonyLog buildProto() {
756 
757         TelephonyLog log = new TelephonyLog();
758         // Build telephony events
759         log.events = new TelephonyEvent[mTelephonyEvents.size()];
760         mTelephonyEvents.toArray(log.events);
761         log.eventsDropped = mTelephonyEventsDropped;
762 
763         // Build call sessions
764         log.callSessions = new TelephonyCallSession[mCompletedCallSessions.size()];
765         mCompletedCallSessions.toArray(log.callSessions);
766 
767         // Build SMS sessions
768         log.smsSessions = new SmsSession[mCompletedSmsSessions.size()];
769         mCompletedSmsSessions.toArray(log.smsSessions);
770 
771         // Build histogram. Currently we only support RIL histograms.
772         List<TelephonyHistogram> rilHistograms = RIL.getTelephonyRILTimingHistograms();
773         log.histograms = new TelephonyProto.TelephonyHistogram[rilHistograms.size()];
774         for (int i = 0; i < rilHistograms.size(); i++) {
775             log.histograms[i] = new TelephonyProto.TelephonyHistogram();
776             TelephonyHistogram rilHistogram = rilHistograms.get(i);
777             TelephonyProto.TelephonyHistogram histogramProto = log.histograms[i];
778 
779             histogramProto.category = rilHistogram.getCategory();
780             histogramProto.id = rilHistogram.getId();
781             histogramProto.minTimeMillis = rilHistogram.getMinTime();
782             histogramProto.maxTimeMillis = rilHistogram.getMaxTime();
783             histogramProto.avgTimeMillis = rilHistogram.getAverageTime();
784             histogramProto.count = rilHistogram.getSampleCount();
785             histogramProto.bucketCount = rilHistogram.getBucketCount();
786             histogramProto.bucketEndPoints = rilHistogram.getBucketEndPoints();
787             histogramProto.bucketCounters = rilHistogram.getBucketCounters();
788         }
789 
790         // Build modem power metrics
791         BatteryStatsManager batteryStatsManager = mContext == null ? null :
792                 (BatteryStatsManager) mContext.getSystemService(Context.BATTERY_STATS_SERVICE);
793         log.modemPowerStats = new ModemPowerMetrics(batteryStatsManager).buildProto();
794 
795         // Log the hardware revision
796         log.hardwareRevision = SystemProperties.get("ro.boot.revision", "");
797 
798         // Log the starting system time
799         log.startTime = new TelephonyProto.Time();
800         log.startTime.systemTimestampMillis = mStartSystemTimeMs;
801         log.startTime.elapsedTimestampMillis = mStartElapsedTimeMs;
802 
803         log.endTime = new TelephonyProto.Time();
804         log.endTime.systemTimestampMillis = System.currentTimeMillis();
805         log.endTime.elapsedTimestampMillis = SystemClock.elapsedRealtime();
806 
807         // Log the last active subscription information.
808         int phoneCount = TelephonyManager.getDefault().getPhoneCount();
809         ActiveSubscriptionInfo[] activeSubscriptionInfo =
810                 new ActiveSubscriptionInfo[phoneCount];
811         for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) {
812             int key = mLastActiveSubscriptionInfos.keyAt(i);
813             activeSubscriptionInfo[key] = mLastActiveSubscriptionInfos.get(key);
814         }
815         for (int i = 0; i < phoneCount; i++) {
816             if (activeSubscriptionInfo[i] == null) {
817                 activeSubscriptionInfo[i] = makeInvalidSubscriptionInfo(i);
818             }
819         }
820         log.lastActiveSubscriptionInfo = activeSubscriptionInfo;
821         log.bandwidthEstimatorStats = buildBandwidthEstimatorStats();
822         return log;
823     }
824 
825     /** Update the sim state. */
updateSimState(int phoneId, int simState)826     public void updateSimState(int phoneId, int simState) {
827         int state = mapSimStateToProto(simState);
828         Integer lastSimState = mLastSimState.get(phoneId);
829         if (lastSimState == null || !lastSimState.equals(state)) {
830             mLastSimState.put(phoneId, state);
831             addTelephonyEvent(
832                     new TelephonyEventBuilder(phoneId).setSimStateChange(mLastSimState).build());
833         }
834     }
835 
836     /** Update active subscription info list. */
updateActiveSubscriptionInfoList(List<SubscriptionInfo> subInfos)837     public synchronized void updateActiveSubscriptionInfoList(List<SubscriptionInfo> subInfos) {
838         List<Integer> inActivePhoneList = new ArrayList<>();
839         for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) {
840             inActivePhoneList.add(mLastActiveSubscriptionInfos.keyAt(i));
841         }
842 
843         for (SubscriptionInfo info : subInfos) {
844             int phoneId = info.getSimSlotIndex();
845             inActivePhoneList.removeIf(value -> value.equals(phoneId));
846             ActiveSubscriptionInfo activeSubscriptionInfo = new ActiveSubscriptionInfo();
847             activeSubscriptionInfo.slotIndex = phoneId;
848             activeSubscriptionInfo.isOpportunistic = info.isOpportunistic() ? 1 : 0;
849             activeSubscriptionInfo.carrierId = info.getCarrierId();
850             if (info.getMccString() != null && info.getMncString() != null) {
851                 activeSubscriptionInfo.simMccmnc = info.getMccString() + info.getMncString();
852             }
853             if (!MessageNano.messageNanoEquals(
854                     mLastActiveSubscriptionInfos.get(phoneId), activeSubscriptionInfo)) {
855                 addTelephonyEvent(new TelephonyEventBuilder(phoneId)
856                         .setActiveSubscriptionInfoChange(activeSubscriptionInfo).build());
857 
858                 mLastActiveSubscriptionInfos.put(phoneId, activeSubscriptionInfo);
859             }
860         }
861 
862         for (int phoneId : inActivePhoneList) {
863             mLastActiveSubscriptionInfos.remove(phoneId);
864             addTelephonyEvent(new TelephonyEventBuilder(phoneId)
865                     .setActiveSubscriptionInfoChange(makeInvalidSubscriptionInfo(phoneId)).build());
866         }
867     }
868 
869     /** Update the enabled modem bitmap. */
updateEnabledModemBitmap(int enabledModemBitmap)870     public void updateEnabledModemBitmap(int enabledModemBitmap) {
871         if (mLastEnabledModemBitmap == enabledModemBitmap) return;
872         mLastEnabledModemBitmap = enabledModemBitmap;
873         addTelephonyEvent(new TelephonyEventBuilder()
874                 .setEnabledModemBitmap(mLastEnabledModemBitmap).build());
875     }
876 
makeInvalidSubscriptionInfo(int phoneId)877     private static ActiveSubscriptionInfo makeInvalidSubscriptionInfo(int phoneId) {
878         ActiveSubscriptionInfo invalidSubscriptionInfo = new ActiveSubscriptionInfo();
879         invalidSubscriptionInfo.slotIndex = phoneId;
880         invalidSubscriptionInfo.carrierId = -1;
881         invalidSubscriptionInfo.isOpportunistic = -1;
882         return invalidSubscriptionInfo;
883     }
884 
885     /**
886      * Reduce precision to meet privacy requirements.
887      *
888      * @param timestamp timestamp in milliseconds
889      * @return Precision reduced timestamp in minutes
890      */
roundSessionStart(long timestamp)891     static int roundSessionStart(long timestamp) {
892         return (int) ((timestamp) / (MINUTE_IN_MILLIS * SESSION_START_PRECISION_MINUTES)
893                 * (SESSION_START_PRECISION_MINUTES));
894     }
895 
896     /**
897      * Write the Carrier Key change event
898      *
899      * @param phoneId Phone id
900      * @param keyType type of key
901      * @param isDownloadSuccessful true if the key was successfully downloaded
902      */
writeCarrierKeyEvent(int phoneId, int keyType, boolean isDownloadSuccessful)903     public void writeCarrierKeyEvent(int phoneId, int keyType,  boolean isDownloadSuccessful) {
904         final CarrierKeyChange carrierKeyChange = new CarrierKeyChange();
905         carrierKeyChange.keyType = keyType;
906         carrierKeyChange.isDownloadSuccessful = isDownloadSuccessful;
907         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setCarrierKeyChange(
908                 carrierKeyChange).build();
909         addTelephonyEvent(event);
910     }
911 
912 
913     /**
914      * Get the time interval with reduced prevision
915      *
916      * @param previousTimestamp Previous timestamp in milliseconds
917      * @param currentTimestamp Current timestamp in milliseconds
918      * @return The time interval
919      */
toPrivacyFuzzedTimeInterval(long previousTimestamp, long currentTimestamp)920     static int toPrivacyFuzzedTimeInterval(long previousTimestamp, long currentTimestamp) {
921         long diff = currentTimestamp - previousTimestamp;
922         if (diff < 0) {
923             return TimeInterval.TI_UNKNOWN;
924         } else if (diff <= 10) {
925             return TimeInterval.TI_10_MILLIS;
926         } else if (diff <= 20) {
927             return TimeInterval.TI_20_MILLIS;
928         } else if (diff <= 50) {
929             return TimeInterval.TI_50_MILLIS;
930         } else if (diff <= 100) {
931             return TimeInterval.TI_100_MILLIS;
932         } else if (diff <= 200) {
933             return TimeInterval.TI_200_MILLIS;
934         } else if (diff <= 500) {
935             return TimeInterval.TI_500_MILLIS;
936         } else if (diff <= 1000) {
937             return TimeInterval.TI_1_SEC;
938         } else if (diff <= 2000) {
939             return TimeInterval.TI_2_SEC;
940         } else if (diff <= 5000) {
941             return TimeInterval.TI_5_SEC;
942         } else if (diff <= 10000) {
943             return TimeInterval.TI_10_SEC;
944         } else if (diff <= 30000) {
945             return TimeInterval.TI_30_SEC;
946         } else if (diff <= 60000) {
947             return TimeInterval.TI_1_MINUTE;
948         } else if (diff <= 180000) {
949             return TimeInterval.TI_3_MINUTES;
950         } else if (diff <= 600000) {
951             return TimeInterval.TI_10_MINUTES;
952         } else if (diff <= 1800000) {
953             return TimeInterval.TI_30_MINUTES;
954         } else if (diff <= 3600000) {
955             return TimeInterval.TI_1_HOUR;
956         } else if (diff <= 7200000) {
957             return TimeInterval.TI_2_HOURS;
958         } else if (diff <= 14400000) {
959             return TimeInterval.TI_4_HOURS;
960         } else {
961             return TimeInterval.TI_MANY_HOURS;
962         }
963     }
964 
965     /**
966      * Convert the service state into service state proto
967      *
968      * @param serviceState Service state
969      * @return Service state proto
970      */
toServiceStateProto(ServiceState serviceState)971     private TelephonyServiceState toServiceStateProto(ServiceState serviceState) {
972         TelephonyServiceState ssProto = new TelephonyServiceState();
973 
974         ssProto.voiceRoamingType = serviceState.getVoiceRoamingType();
975         ssProto.dataRoamingType = serviceState.getDataRoamingType();
976 
977         ssProto.voiceOperator = new TelephonyServiceState.TelephonyOperator();
978         ssProto.dataOperator = new TelephonyServiceState.TelephonyOperator();
979         if (serviceState.getOperatorAlphaLong() != null) {
980             ssProto.voiceOperator.alphaLong = serviceState.getOperatorAlphaLong();
981             ssProto.dataOperator.alphaLong = serviceState.getOperatorAlphaLong();
982         }
983 
984         if (serviceState.getOperatorAlphaShort() != null) {
985             ssProto.voiceOperator.alphaShort = serviceState.getOperatorAlphaShort();
986             ssProto.dataOperator.alphaShort = serviceState.getOperatorAlphaShort();
987         }
988 
989         if (serviceState.getOperatorNumeric() != null) {
990             ssProto.voiceOperator.numeric = serviceState.getOperatorNumeric();
991             ssProto.dataOperator.numeric = serviceState.getOperatorNumeric();
992         }
993 
994         // Log PS WWAN only because CS WWAN would be exactly the same as voiceRat, and PS WLAN
995         // would be always IWLAN in the rat field.
996         // Note that we intentionally do not log reg state because it changes too frequently that
997         // will grow the proto size too much.
998         List<TelephonyServiceState.NetworkRegistrationInfo> nriList = new ArrayList<>();
999         NetworkRegistrationInfo nri = serviceState.getNetworkRegistrationInfo(
1000                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
1001         if (nri != null) {
1002             TelephonyServiceState.NetworkRegistrationInfo nriProto =
1003                     new TelephonyServiceState.NetworkRegistrationInfo();
1004             nriProto.domain = TelephonyServiceState.Domain.DOMAIN_PS;
1005             nriProto.transport = TelephonyServiceState.Transport.TRANSPORT_WWAN;
1006             nriProto.rat = ServiceState.networkTypeToRilRadioTechnology(
1007                     nri.getAccessNetworkTechnology());
1008             nriList.add(nriProto);
1009             ssProto.networkRegistrationInfo =
1010                     new TelephonyServiceState.NetworkRegistrationInfo[nriList.size()];
1011             nriList.toArray(ssProto.networkRegistrationInfo);
1012         }
1013 
1014         ssProto.voiceRat = serviceState.getRilVoiceRadioTechnology();
1015         ssProto.dataRat = serviceState.getRilDataRadioTechnology();
1016         ssProto.channelNumber = serviceState.getChannelNumber();
1017         ssProto.nrFrequencyRange = serviceState.getNrFrequencyRange();
1018         ssProto.nrState = serviceState.getNrState();
1019         return ssProto;
1020     }
1021 
1022     /**
1023      * Annotate the call session with events
1024      *
1025      * @param timestamp Event timestamp
1026      * @param phoneId Phone id
1027      * @param eventBuilder Call session event builder
1028      */
annotateInProgressCallSession(long timestamp, int phoneId, CallSessionEventBuilder eventBuilder)1029     private synchronized void annotateInProgressCallSession(long timestamp, int phoneId,
1030                                                             CallSessionEventBuilder eventBuilder) {
1031         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1032         if (callSession != null) {
1033             callSession.addEvent(timestamp, eventBuilder);
1034         }
1035     }
1036 
1037     /**
1038      * Annotate the SMS session with events
1039      *
1040      * @param timestamp Event timestamp
1041      * @param phoneId Phone id
1042      * @param eventBuilder SMS session event builder
1043      */
annotateInProgressSmsSession(long timestamp, int phoneId, SmsSessionEventBuilder eventBuilder)1044     private synchronized void annotateInProgressSmsSession(long timestamp, int phoneId,
1045                                                            SmsSessionEventBuilder eventBuilder) {
1046         InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId);
1047         if (smsSession != null) {
1048             smsSession.addEvent(timestamp, eventBuilder);
1049         }
1050     }
1051 
1052     /**
1053      * Create the call session if there isn't any existing one
1054      *
1055      * @param phoneId Phone id
1056      * @return The call session
1057      */
startNewCallSessionIfNeeded(int phoneId)1058     private synchronized InProgressCallSession startNewCallSessionIfNeeded(int phoneId) {
1059         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1060         if (callSession == null) {
1061             logv("Starting a new call session on phone " + phoneId);
1062             callSession = new InProgressCallSession(phoneId);
1063             mInProgressCallSessions.append(phoneId, callSession);
1064 
1065             // Insert the latest service state, ims capabilities, and ims connection states as the
1066             // base.
1067             TelephonyServiceState serviceState = mLastServiceState.get(phoneId);
1068             if (serviceState != null) {
1069                 callSession.addEvent(callSession.startElapsedTimeMs, new CallSessionEventBuilder(
1070                         TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
1071                         .setServiceState(serviceState));
1072             }
1073 
1074             ImsCapabilities imsCapabilities = mLastImsCapabilities.get(phoneId);
1075             if (imsCapabilities != null) {
1076                 callSession.addEvent(callSession.startElapsedTimeMs, new CallSessionEventBuilder(
1077                         TelephonyCallSession.Event.Type.IMS_CAPABILITIES_CHANGED)
1078                         .setImsCapabilities(imsCapabilities));
1079             }
1080 
1081             ImsConnectionState imsConnectionState = mLastImsConnectionState.get(phoneId);
1082             if (imsConnectionState != null) {
1083                 callSession.addEvent(callSession.startElapsedTimeMs, new CallSessionEventBuilder(
1084                         TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED)
1085                         .setImsConnectionState(imsConnectionState));
1086             }
1087         }
1088         return callSession;
1089     }
1090 
1091     /**
1092      * Create the SMS session if there isn't any existing one
1093      *
1094      * @param phoneId Phone id
1095      * @return The SMS session
1096      */
startNewSmsSessionIfNeeded(int phoneId)1097     private synchronized InProgressSmsSession startNewSmsSessionIfNeeded(int phoneId) {
1098         InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId);
1099         if (smsSession == null) {
1100             logv("Starting a new sms session on phone " + phoneId);
1101             smsSession = startNewSmsSession(phoneId);
1102             mInProgressSmsSessions.append(phoneId, smsSession);
1103         }
1104         return smsSession;
1105     }
1106 
1107     /**
1108      * Create a new SMS session
1109      *
1110      * @param phoneId Phone id
1111      * @return The SMS session
1112      */
startNewSmsSession(int phoneId)1113     private InProgressSmsSession startNewSmsSession(int phoneId) {
1114         InProgressSmsSession smsSession = new InProgressSmsSession(phoneId);
1115 
1116         // Insert the latest service state, ims capabilities, and ims connection state as the
1117         // base.
1118         TelephonyServiceState serviceState = mLastServiceState.get(phoneId);
1119         if (serviceState != null) {
1120             smsSession.addEvent(smsSession.startElapsedTimeMs, new SmsSessionEventBuilder(
1121                     SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
1122                     .setServiceState(serviceState));
1123         }
1124 
1125         ImsCapabilities imsCapabilities = mLastImsCapabilities.get(phoneId);
1126         if (imsCapabilities != null) {
1127             smsSession.addEvent(smsSession.startElapsedTimeMs, new SmsSessionEventBuilder(
1128                     SmsSession.Event.Type.IMS_CAPABILITIES_CHANGED)
1129                     .setImsCapabilities(imsCapabilities));
1130         }
1131 
1132         ImsConnectionState imsConnectionState = mLastImsConnectionState.get(phoneId);
1133         if (imsConnectionState != null) {
1134             smsSession.addEvent(smsSession.startElapsedTimeMs, new SmsSessionEventBuilder(
1135                     SmsSession.Event.Type.IMS_CONNECTION_STATE_CHANGED)
1136                     .setImsConnectionState(imsConnectionState));
1137         }
1138         return smsSession;
1139     }
1140 
1141     /**
1142      * Finish the call session and move it into the completed session
1143      *
1144      * @param inProgressCallSession The in progress call session
1145      */
finishCallSession(InProgressCallSession inProgressCallSession)1146     private synchronized void finishCallSession(InProgressCallSession inProgressCallSession) {
1147         TelephonyCallSession callSession = new TelephonyCallSession();
1148         callSession.events = new TelephonyCallSession.Event[inProgressCallSession.events.size()];
1149         inProgressCallSession.events.toArray(callSession.events);
1150         callSession.startTimeMinutes = inProgressCallSession.startSystemTimeMin;
1151         callSession.phoneId = inProgressCallSession.phoneId;
1152         callSession.eventsDropped = inProgressCallSession.isEventsDropped();
1153         if (mCompletedCallSessions.size() >= MAX_COMPLETED_CALL_SESSIONS) {
1154             mCompletedCallSessions.removeFirst();
1155         }
1156         mCompletedCallSessions.add(callSession);
1157         mInProgressCallSessions.remove(inProgressCallSession.phoneId);
1158         logv("Call session finished");
1159     }
1160 
1161     /**
1162      * Finish the SMS session and move it into the completed session
1163      *
1164      * @param inProgressSmsSession The in progress SMS session
1165      */
finishSmsSessionIfNeeded(InProgressSmsSession inProgressSmsSession)1166     private synchronized void finishSmsSessionIfNeeded(InProgressSmsSession inProgressSmsSession) {
1167         if (inProgressSmsSession.getNumExpectedResponses() == 0) {
1168             SmsSession smsSession = finishSmsSession(inProgressSmsSession);
1169 
1170             mInProgressSmsSessions.remove(inProgressSmsSession.phoneId);
1171             logv("SMS session finished");
1172         }
1173     }
1174 
finishSmsSession(InProgressSmsSession inProgressSmsSession)1175     private synchronized SmsSession finishSmsSession(InProgressSmsSession inProgressSmsSession) {
1176         SmsSession smsSession = new SmsSession();
1177         smsSession.events = new SmsSession.Event[inProgressSmsSession.events.size()];
1178         inProgressSmsSession.events.toArray(smsSession.events);
1179         smsSession.startTimeMinutes = inProgressSmsSession.startSystemTimeMin;
1180         smsSession.phoneId = inProgressSmsSession.phoneId;
1181         smsSession.eventsDropped = inProgressSmsSession.isEventsDropped();
1182 
1183         if (mCompletedSmsSessions.size() >= MAX_COMPLETED_SMS_SESSIONS) {
1184             mCompletedSmsSessions.removeFirst();
1185         }
1186         mCompletedSmsSessions.add(smsSession);
1187         return smsSession;
1188     }
1189 
1190     /**
1191      * Add telephony event into the queue
1192      *
1193      * @param event Telephony event
1194      */
addTelephonyEvent(TelephonyEvent event)1195     private synchronized void addTelephonyEvent(TelephonyEvent event) {
1196         if (mTelephonyEvents.size() >= MAX_TELEPHONY_EVENTS) {
1197             mTelephonyEvents.removeFirst();
1198             mTelephonyEventsDropped = true;
1199         }
1200         mTelephonyEvents.add(event);
1201     }
1202 
1203     /**
1204      * Write service changed event
1205      *
1206      * @param phoneId Phone id
1207      * @param serviceState Service state
1208      */
writeServiceStateChanged(int phoneId, ServiceState serviceState)1209     public synchronized void writeServiceStateChanged(int phoneId, ServiceState serviceState) {
1210 
1211         TelephonyEvent event = new TelephonyEventBuilder(phoneId)
1212                 .setServiceState(toServiceStateProto(serviceState)).build();
1213 
1214         // If service state doesn't change, we don't log the event.
1215         if (mLastServiceState.get(phoneId) != null &&
1216                 Arrays.equals(TelephonyServiceState.toByteArray(mLastServiceState.get(phoneId)),
1217                         TelephonyServiceState.toByteArray(event.serviceState))) {
1218             return;
1219         }
1220 
1221         mLastServiceState.put(phoneId, event.serviceState);
1222         addTelephonyEvent(event);
1223 
1224         annotateInProgressCallSession(event.timestampMillis, phoneId,
1225                 new CallSessionEventBuilder(
1226                         TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
1227                         .setServiceState(event.serviceState));
1228         annotateInProgressSmsSession(event.timestampMillis, phoneId,
1229                 new SmsSessionEventBuilder(
1230                         SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
1231                         .setServiceState(event.serviceState));
1232     }
1233 
1234     /**
1235      * Write data stall event
1236      *
1237      * @param phoneId Phone id
1238      * @param recoveryAction Data stall recovery action
1239      */
writeDataStallEvent(int phoneId, int recoveryAction)1240     public void writeDataStallEvent(int phoneId, int recoveryAction) {
1241         addTelephonyEvent(new TelephonyEventBuilder(phoneId)
1242                 .setDataStallRecoveryAction(recoveryAction).build());
1243     }
1244 
1245     /**
1246      * Write SignalStrength event
1247      *
1248      * @param phoneId Phone id
1249      * @param signalStrength Signal strength at the time of data stall recovery
1250      */
writeSignalStrengthEvent(int phoneId, int signalStrength)1251     public void writeSignalStrengthEvent(int phoneId, int signalStrength) {
1252         addTelephonyEvent(new TelephonyEventBuilder(phoneId)
1253                 .setSignalStrength(signalStrength).build());
1254     }
1255 
cloneCurrentTelephonySettings(int phoneId)1256     private TelephonySettings cloneCurrentTelephonySettings(int phoneId) {
1257         TelephonySettings newSettings = new TelephonySettings();
1258         TelephonySettings lastSettings = mLastSettings.get(phoneId);
1259         if (lastSettings != null) {
1260             // No clone method available, so each relevant field is copied individually.
1261             newSettings.preferredNetworkMode = lastSettings.preferredNetworkMode;
1262             newSettings.isEnhanced4GLteModeEnabled = lastSettings.isEnhanced4GLteModeEnabled;
1263             newSettings.isVtOverLteEnabled = lastSettings.isVtOverLteEnabled;
1264             newSettings.isWifiCallingEnabled = lastSettings.isWifiCallingEnabled;
1265             newSettings.isVtOverWifiEnabled = lastSettings.isVtOverWifiEnabled;
1266         }
1267         return newSettings;
1268     }
1269 
1270     /**
1271      * Write IMS feature settings changed event
1272      *
1273      * @param phoneId Phone id
1274      * @param feature IMS feature
1275      * @param network The IMS network type
1276      * @param value The settings. 0 indicates disabled, otherwise enabled.
1277      */
writeImsSetFeatureValue(int phoneId, int feature, int network, int value)1278     public synchronized void writeImsSetFeatureValue(int phoneId, int feature, int network,
1279             int value) {
1280         TelephonySettings s = cloneCurrentTelephonySettings(phoneId);
1281         if (network == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
1282             switch (feature) {
1283                 case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE:
1284                     s.isEnhanced4GLteModeEnabled = (value != 0);
1285                     break;
1286                 case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO:
1287                     s.isVtOverLteEnabled = (value != 0);
1288                     break;
1289             }
1290         } else if (network == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) {
1291             switch (feature) {
1292                 case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE:
1293                     s.isWifiCallingEnabled = (value != 0);
1294                     break;
1295                 case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO:
1296                     s.isVtOverWifiEnabled = (value != 0);
1297                     break;
1298             }
1299         }
1300 
1301         // If the settings don't change, we don't log the event.
1302         if (mLastSettings.get(phoneId) != null &&
1303                 Arrays.equals(TelephonySettings.toByteArray(mLastSettings.get(phoneId)),
1304                         TelephonySettings.toByteArray(s))) {
1305             return;
1306         }
1307 
1308         mLastSettings.put(phoneId, s);
1309 
1310         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setSettings(s).build();
1311         addTelephonyEvent(event);
1312 
1313         annotateInProgressCallSession(event.timestampMillis, phoneId,
1314                 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.SETTINGS_CHANGED)
1315                         .setSettings(s));
1316         annotateInProgressSmsSession(event.timestampMillis, phoneId,
1317                 new SmsSessionEventBuilder(SmsSession.Event.Type.SETTINGS_CHANGED)
1318                         .setSettings(s));
1319     }
1320 
1321     /**
1322      * Write the preferred network settings changed event
1323      *
1324      * @param phoneId Phone id
1325      * @param networkType The preferred network
1326      */
writeSetPreferredNetworkType(int phoneId, @PrefNetworkMode int networkType)1327     public synchronized void writeSetPreferredNetworkType(int phoneId,
1328             @PrefNetworkMode int networkType) {
1329         TelephonySettings s = cloneCurrentTelephonySettings(phoneId);
1330         s.preferredNetworkMode = networkType + 1;
1331 
1332         // If the settings don't change, we don't log the event.
1333         if (mLastSettings.get(phoneId) != null &&
1334                 Arrays.equals(TelephonySettings.toByteArray(mLastSettings.get(phoneId)),
1335                         TelephonySettings.toByteArray(s))) {
1336             return;
1337         }
1338 
1339         mLastSettings.put(phoneId, s);
1340 
1341         addTelephonyEvent(new TelephonyEventBuilder(phoneId).setSettings(s).build());
1342     }
1343 
1344     /**
1345      * Write the IMS connection state changed event
1346      *
1347      * @param phoneId Phone id
1348      * @param state IMS connection state
1349      * @param reasonInfo The reason info. Only used for disconnected state.
1350      */
writeOnImsConnectionState(int phoneId, int state, ImsReasonInfo reasonInfo)1351     public synchronized void writeOnImsConnectionState(int phoneId, int state,
1352                                                        ImsReasonInfo reasonInfo) {
1353         ImsConnectionState imsState = new ImsConnectionState();
1354         imsState.state = state;
1355 
1356         if (reasonInfo != null) {
1357             TelephonyProto.ImsReasonInfo ri = new TelephonyProto.ImsReasonInfo();
1358 
1359             ri.reasonCode = reasonInfo.getCode();
1360             ri.extraCode = reasonInfo.getExtraCode();
1361             String extraMessage = reasonInfo.getExtraMessage();
1362             if (extraMessage != null) {
1363                 ri.extraMessage = extraMessage;
1364             }
1365 
1366             imsState.reasonInfo = ri;
1367         }
1368 
1369         // If the connection state does not change, do not log it.
1370         if (mLastImsConnectionState.get(phoneId) != null &&
1371                 Arrays.equals(ImsConnectionState.toByteArray(mLastImsConnectionState.get(phoneId)),
1372                         ImsConnectionState.toByteArray(imsState))) {
1373             return;
1374         }
1375 
1376         mLastImsConnectionState.put(phoneId, imsState);
1377 
1378         TelephonyEvent event = new TelephonyEventBuilder(phoneId)
1379                 .setImsConnectionState(imsState).build();
1380         addTelephonyEvent(event);
1381 
1382         annotateInProgressCallSession(event.timestampMillis, phoneId,
1383                 new CallSessionEventBuilder(
1384                         TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED)
1385                         .setImsConnectionState(event.imsConnectionState));
1386         annotateInProgressSmsSession(event.timestampMillis, phoneId,
1387                 new SmsSessionEventBuilder(
1388                         SmsSession.Event.Type.IMS_CONNECTION_STATE_CHANGED)
1389                         .setImsConnectionState(event.imsConnectionState));
1390     }
1391 
1392     /**
1393      * Write the IMS capabilities changed event
1394      *
1395      * @param phoneId Phone id
1396      * @param capabilities IMS capabilities array
1397      */
writeOnImsCapabilities(int phoneId, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech, MmTelFeature.MmTelCapabilities capabilities)1398     public synchronized void writeOnImsCapabilities(int phoneId,
1399             @ImsRegistrationImplBase.ImsRegistrationTech int radioTech,
1400             MmTelFeature.MmTelCapabilities capabilities) {
1401         ImsCapabilities cap = new ImsCapabilities();
1402 
1403         if (radioTech == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
1404             cap.voiceOverLte = capabilities.isCapable(
1405                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
1406             cap.videoOverLte = capabilities.isCapable(
1407                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO);
1408             cap.utOverLte = capabilities.isCapable(
1409                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT);
1410 
1411         } else if (radioTech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) {
1412             cap.voiceOverWifi = capabilities.isCapable(
1413                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
1414             cap.videoOverWifi = capabilities.isCapable(
1415                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO);
1416             cap.utOverWifi = capabilities.isCapable(
1417                     MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT);
1418         }
1419 
1420         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setImsCapabilities(cap).build();
1421 
1422         // If the capabilities don't change, we don't log the event.
1423         if (mLastImsCapabilities.get(phoneId) != null &&
1424                 Arrays.equals(ImsCapabilities.toByteArray(mLastImsCapabilities.get(phoneId)),
1425                 ImsCapabilities.toByteArray(cap))) {
1426             return;
1427         }
1428 
1429         mLastImsCapabilities.put(phoneId, cap);
1430         addTelephonyEvent(event);
1431 
1432         annotateInProgressCallSession(event.timestampMillis, phoneId,
1433                 new CallSessionEventBuilder(
1434                         TelephonyCallSession.Event.Type.IMS_CAPABILITIES_CHANGED)
1435                         .setImsCapabilities(event.imsCapabilities));
1436         annotateInProgressSmsSession(event.timestampMillis, phoneId,
1437                 new SmsSessionEventBuilder(
1438                         SmsSession.Event.Type.IMS_CAPABILITIES_CHANGED)
1439                         .setImsCapabilities(event.imsCapabilities));
1440     }
1441 
1442     /**
1443      * Convert PDP type into the enumeration
1444      *
1445      * @param type PDP type
1446      * @return The proto defined enumeration
1447      */
toPdpType(String type)1448     private int toPdpType(String type) {
1449         switch (type) {
1450             case "IP":
1451                 return PDP_TYPE_IP;
1452             case "IPV6":
1453                 return PDP_TYPE_IPV6;
1454             case "IPV4V6":
1455                 return PDP_TYPE_IPV4V6;
1456             case "PPP":
1457                 return PDP_TYPE_PPP;
1458             case "NON-IP":
1459                 return PDP_TYPE_NON_IP;
1460             case "UNSTRUCTURED":
1461                 return PDP_TYPE_UNSTRUCTURED;
1462         }
1463         Rlog.e(TAG, "Unknown type: " + type);
1464         return PDP_UNKNOWN;
1465     }
1466 
1467     /**
1468      * Write setup data call event
1469      *
1470      * @param phoneId Phone id
1471      * @param radioTechnology The data call RAT
1472      * @param profileId Data profile id
1473      * @param apn APN in string
1474      * @param protocol Data connection protocol
1475      */
writeSetupDataCall(int phoneId, int radioTechnology, int profileId, String apn, int protocol)1476     public void writeSetupDataCall(int phoneId, int radioTechnology, int profileId, String apn,
1477                                    int protocol) {
1478 
1479         RilSetupDataCall setupDataCall = new RilSetupDataCall();
1480         setupDataCall.rat = radioTechnology;
1481         setupDataCall.dataProfile = profileId + 1;  // off by 1 between proto and RIL constants.
1482         if (apn != null) {
1483             setupDataCall.apn = apn;
1484         }
1485 
1486         setupDataCall.type = protocol + 1;
1487 
1488         addTelephonyEvent(new TelephonyEventBuilder(phoneId).setSetupDataCall(
1489                 setupDataCall).build());
1490     }
1491 
1492     /**
1493      * Write data call deactivate event
1494      *
1495      * @param phoneId Phone id
1496      * @param rilSerial RIL request serial number
1497      * @param cid call id
1498      * @param reason Deactivate reason
1499      */
writeRilDeactivateDataCall(int phoneId, int rilSerial, int cid, int reason)1500     public void writeRilDeactivateDataCall(int phoneId, int rilSerial, int cid, int reason) {
1501 
1502         RilDeactivateDataCall deactivateDataCall = new RilDeactivateDataCall();
1503         deactivateDataCall.cid = cid;
1504         switch (reason) {
1505             case DataService.REQUEST_REASON_NORMAL:
1506                 deactivateDataCall.reason = DeactivateReason.DEACTIVATE_REASON_NONE;
1507                 break;
1508             case DataService.REQUEST_REASON_SHUTDOWN:
1509                 deactivateDataCall.reason = DeactivateReason.DEACTIVATE_REASON_RADIO_OFF;
1510                 break;
1511             case DataService.REQUEST_REASON_HANDOVER:
1512                 deactivateDataCall.reason = DeactivateReason.DEACTIVATE_REASON_HANDOVER;
1513                 break;
1514             default:
1515                 deactivateDataCall.reason = DeactivateReason.DEACTIVATE_REASON_UNKNOWN;
1516         }
1517 
1518         addTelephonyEvent(new TelephonyEventBuilder(phoneId).setDeactivateDataCall(
1519                 deactivateDataCall).build());
1520     }
1521 
1522     /**
1523      * Write data call list event when connected
1524      * @param phoneId          Phone id
1525      * @param cid              Context Id, uniquely identifies the call
1526      * @param apnTypeBitmask   Bitmask of supported APN types
1527      * @param state            State of the data call event
1528      */
writeRilDataCallEvent(int phoneId, int cid, int apnTypeBitmask, int state)1529     public void writeRilDataCallEvent(int phoneId, int cid,
1530             int apnTypeBitmask, int state) {
1531         RilDataCall[] dataCalls = new RilDataCall[1];
1532         dataCalls[0] = new RilDataCall();
1533         dataCalls[0].cid = cid;
1534         dataCalls[0].apnTypeBitmask = apnTypeBitmask;
1535         dataCalls[0].state = state;
1536 
1537         SparseArray<RilDataCall> dataCallList;
1538         if (mLastRilDataCallEvents.get(phoneId) != null) {
1539             // If the Data call event does not change, do not log it.
1540             if (mLastRilDataCallEvents.get(phoneId).get(cid) != null
1541                     && Arrays.equals(
1542                         RilDataCall.toByteArray(mLastRilDataCallEvents.get(phoneId).get(cid)),
1543                         RilDataCall.toByteArray(dataCalls[0]))) {
1544                 return;
1545             }
1546             dataCallList =  mLastRilDataCallEvents.get(phoneId);
1547         } else {
1548             dataCallList = new SparseArray<>();
1549         }
1550 
1551         dataCallList.put(cid, dataCalls[0]);
1552         mLastRilDataCallEvents.put(phoneId, dataCallList);
1553         addTelephonyEvent(new TelephonyEventBuilder(phoneId).setDataCalls(dataCalls).build());
1554     }
1555 
1556     /**
1557      * Write CS call list event
1558      *
1559      * @param phoneId    Phone id
1560      * @param connections Array of GsmCdmaConnection objects
1561      */
writeRilCallList(int phoneId, ArrayList<GsmCdmaConnection> connections, String countryIso)1562     public void writeRilCallList(int phoneId, ArrayList<GsmCdmaConnection> connections,
1563                                  String countryIso) {
1564         logv("Logging CallList Changed Connections Size = " + connections.size());
1565         InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
1566         if (callSession == null) {
1567             Rlog.e(TAG, "writeRilCallList: Call session is missing");
1568         } else {
1569             RilCall[] calls = convertConnectionsToRilCalls(connections, countryIso);
1570             callSession.addEvent(
1571                     new CallSessionEventBuilder(
1572                             TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED)
1573                             .setRilCalls(calls)
1574             );
1575             logv("Logged Call list changed");
1576             if (callSession.isPhoneIdle() && disconnectReasonsKnown(calls)) {
1577                 finishCallSession(callSession);
1578             }
1579         }
1580     }
1581 
disconnectReasonsKnown(RilCall[] calls)1582     private boolean disconnectReasonsKnown(RilCall[] calls) {
1583         for (RilCall call : calls) {
1584             if (call.callEndReason == 0) return false;
1585         }
1586         return true;
1587     }
1588 
convertConnectionsToRilCalls(ArrayList<GsmCdmaConnection> mConnections, String countryIso)1589     private RilCall[] convertConnectionsToRilCalls(ArrayList<GsmCdmaConnection> mConnections,
1590                                                    String countryIso) {
1591         RilCall[] calls = new RilCall[mConnections.size()];
1592         for (int i = 0; i < mConnections.size(); i++) {
1593             calls[i] = new RilCall();
1594             calls[i].index = i;
1595             convertConnectionToRilCall(mConnections.get(i), calls[i], countryIso);
1596         }
1597         return calls;
1598     }
1599 
convertEmergencyNumberToEmergencyNumberInfo(EmergencyNumber num)1600     private EmergencyNumberInfo convertEmergencyNumberToEmergencyNumberInfo(EmergencyNumber num) {
1601         EmergencyNumberInfo emergencyNumberInfo = new EmergencyNumberInfo();
1602         emergencyNumberInfo.address = num.getNumber();
1603         emergencyNumberInfo.countryIso = num.getCountryIso();
1604         emergencyNumberInfo.mnc = num.getMnc();
1605         emergencyNumberInfo.serviceCategoriesBitmask = num.getEmergencyServiceCategoryBitmask();
1606         emergencyNumberInfo.urns = num.getEmergencyUrns().stream().toArray(String[]::new);
1607         emergencyNumberInfo.numberSourcesBitmask = num.getEmergencyNumberSourceBitmask();
1608         emergencyNumberInfo.routing = num.getEmergencyCallRouting();
1609         return emergencyNumberInfo;
1610     }
1611 
convertConnectionToRilCall(GsmCdmaConnection conn, RilCall call, String countryIso)1612     private void convertConnectionToRilCall(GsmCdmaConnection conn, RilCall call,
1613                                             String countryIso) {
1614         if (conn.isIncoming()) {
1615             call.type = Type.MT;
1616         } else {
1617             call.type = Type.MO;
1618         }
1619         switch (conn.getState()) {
1620             case IDLE:
1621                 call.state = CallState.CALL_IDLE;
1622                 break;
1623             case ACTIVE:
1624                 call.state = CallState.CALL_ACTIVE;
1625                 break;
1626             case HOLDING:
1627                 call.state = CallState.CALL_HOLDING;
1628                 break;
1629             case DIALING:
1630                 call.state = CallState.CALL_DIALING;
1631                 break;
1632             case ALERTING:
1633                 call.state = CallState.CALL_ALERTING;
1634                 break;
1635             case INCOMING:
1636                 call.state = CallState.CALL_INCOMING;
1637                 break;
1638             case WAITING:
1639                 call.state = CallState.CALL_WAITING;
1640                 break;
1641             case DISCONNECTED:
1642                 call.state = CallState.CALL_DISCONNECTED;
1643                 break;
1644             case DISCONNECTING:
1645                 call.state = CallState.CALL_DISCONNECTING;
1646                 break;
1647             default:
1648                 call.state = CallState.CALL_UNKNOWN;
1649                 break;
1650         }
1651         call.callEndReason = conn.getDisconnectCause();
1652         call.isMultiparty = conn.isMultiparty();
1653         call.preciseDisconnectCause = conn.getPreciseDisconnectCause();
1654 
1655         // Emergency call metrics when call ends
1656         if (conn.getDisconnectCause() != DisconnectCause.NOT_DISCONNECTED
1657                 && conn.isEmergencyCall() && conn.getEmergencyNumberInfo() != null) {
1658             /** Only collect this emergency number information per sample percentage */
1659             if (ThreadLocalRandom.current().nextDouble(0, 100)
1660                     < getSamplePercentageForEmergencyCall(countryIso)) {
1661                 call.isEmergencyCall = conn.isEmergencyCall();
1662                 call.emergencyNumberInfo = convertEmergencyNumberToEmergencyNumberInfo(
1663                         conn.getEmergencyNumberInfo());
1664                 EmergencyNumberTracker emergencyNumberTracker = conn.getEmergencyNumberTracker();
1665                 call.emergencyNumberDatabaseVersion = emergencyNumberTracker != null
1666                         ? emergencyNumberTracker.getEmergencyNumberDbVersion()
1667                         : TelephonyManager.INVALID_EMERGENCY_NUMBER_DB_VERSION;
1668             }
1669         }
1670     }
1671 
1672     /**
1673      * Write dial event
1674      *
1675      * @param phoneId Phone id
1676      * @param conn Connection object created to track this call
1677      * @param clirMode CLIR (Calling Line Identification Restriction) mode
1678      * @param uusInfo User-to-User signaling Info
1679      */
writeRilDial(int phoneId, GsmCdmaConnection conn, int clirMode, UUSInfo uusInfo)1680     public void writeRilDial(int phoneId, GsmCdmaConnection conn, int clirMode, UUSInfo uusInfo) {
1681 
1682         InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
1683         logv("Logging Dial Connection = " + conn);
1684         if (callSession == null) {
1685             Rlog.e(TAG, "writeRilDial: Call session is missing");
1686         } else {
1687             RilCall[] calls = new RilCall[1];
1688             calls[0] = new RilCall();
1689             calls[0].index = -1;
1690             convertConnectionToRilCall(conn, calls[0], "");
1691             callSession.addEvent(callSession.startElapsedTimeMs,
1692                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST)
1693                             .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL)
1694                             .setRilCalls(calls));
1695             logv("Logged Dial event");
1696         }
1697     }
1698 
1699     /**
1700      * Write incoming call event
1701      *
1702      * @param phoneId Phone id
1703      * @param response Unused today
1704      */
writeRilCallRing(int phoneId, char[] response)1705     public void writeRilCallRing(int phoneId, char[] response) {
1706         InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
1707 
1708         callSession.addEvent(callSession.startElapsedTimeMs,
1709                 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_CALL_RING));
1710     }
1711 
1712     /**
1713      * Write call hangup event
1714      *
1715      * @param phoneId Phone id
1716      * @param conn Connection object associated with the call that is being hung-up
1717      * @param callId Call id
1718      */
writeRilHangup(int phoneId, GsmCdmaConnection conn, int callId, String countryIso)1719     public void writeRilHangup(int phoneId, GsmCdmaConnection conn, int callId,
1720                                String countryIso) {
1721         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1722         if (callSession == null) {
1723             Rlog.e(TAG, "writeRilHangup: Call session is missing");
1724         } else {
1725             RilCall[] calls = new RilCall[1];
1726             calls[0] = new RilCall();
1727             calls[0].index = callId;
1728             convertConnectionToRilCall(conn, calls[0], countryIso);
1729             callSession.addEvent(
1730                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST)
1731                             .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_HANGUP)
1732                             .setRilCalls(calls));
1733             logv("Logged Hangup event");
1734         }
1735     }
1736 
1737     /**
1738      * Write call answer event
1739      *
1740      * @param phoneId Phone id
1741      * @param rilSerial RIL request serial number
1742      */
writeRilAnswer(int phoneId, int rilSerial)1743     public void writeRilAnswer(int phoneId, int rilSerial) {
1744         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1745         if (callSession == null) {
1746             Rlog.e(TAG, "writeRilAnswer: Call session is missing");
1747         } else {
1748             callSession.addEvent(
1749                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST)
1750                             .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_ANSWER)
1751                             .setRilRequestId(rilSerial));
1752         }
1753     }
1754 
1755     /**
1756      * Write IMS call SRVCC event
1757      *
1758      * @param phoneId Phone id
1759      * @param rilSrvccState SRVCC state
1760      */
writeRilSrvcc(int phoneId, int rilSrvccState)1761     public void writeRilSrvcc(int phoneId, int rilSrvccState) {
1762         InProgressCallSession callSession =  mInProgressCallSessions.get(phoneId);
1763         if (callSession == null) {
1764             Rlog.e(TAG, "writeRilSrvcc: Call session is missing");
1765         } else {
1766             callSession.addEvent(
1767                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_CALL_SRVCC)
1768                             .setSrvccState(rilSrvccState + 1));
1769         }
1770     }
1771 
1772     /**
1773      * Convert RIL request into proto defined RIL request
1774      *
1775      * @param r RIL request
1776      * @return RIL request defined in call session proto
1777      */
toCallSessionRilRequest(int r)1778     private int toCallSessionRilRequest(int r) {
1779         switch (r) {
1780             case RILConstants.RIL_REQUEST_DIAL:
1781                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL;
1782 
1783             case RILConstants.RIL_REQUEST_ANSWER:
1784                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_ANSWER;
1785 
1786             case RILConstants.RIL_REQUEST_HANGUP:
1787             case RILConstants.RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
1788             case RILConstants.RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
1789                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_HANGUP;
1790 
1791             case RILConstants.RIL_REQUEST_SET_CALL_WAITING:
1792                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_SET_CALL_WAITING;
1793 
1794             case RILConstants.RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
1795                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE;
1796 
1797             case RILConstants.RIL_REQUEST_CDMA_FLASH:
1798                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_CDMA_FLASH;
1799 
1800             case RILConstants.RIL_REQUEST_CONFERENCE:
1801                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_CONFERENCE;
1802         }
1803         Rlog.e(TAG, "Unknown RIL request: " + r);
1804         return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_UNKNOWN;
1805     }
1806 
1807     /**
1808      * Write setup data call response event
1809      *
1810      * @param phoneId Phone id
1811      * @param rilSerial RIL request serial number
1812      * @param rilError RIL error
1813      * @param rilRequest RIL request
1814      * @param result Data call result
1815      */
writeOnSetupDataCallResponse(int phoneId, int rilSerial, int rilError, int rilRequest, DataCallResponse response)1816     private void writeOnSetupDataCallResponse(int phoneId, int rilSerial, int rilError,
1817                                               int rilRequest, DataCallResponse response) {
1818 
1819         RilSetupDataCallResponse setupDataCallResponse = new RilSetupDataCallResponse();
1820         RilDataCall dataCall = new RilDataCall();
1821 
1822         if (response != null) {
1823             setupDataCallResponse.status = (response.getCause() == 0
1824                     ? RilDataCallFailCause.PDP_FAIL_NONE : response.getCause());
1825             setupDataCallResponse.suggestedRetryTimeMillis = response.getSuggestedRetryTime();
1826 
1827             dataCall.cid = response.getId();
1828             dataCall.type = response.getProtocolType() + 1;
1829 
1830             if (!TextUtils.isEmpty(response.getInterfaceName())) {
1831                 dataCall.ifname = response.getInterfaceName();
1832             }
1833         }
1834         setupDataCallResponse.call = dataCall;
1835 
1836         addTelephonyEvent(new TelephonyEventBuilder(phoneId)
1837                 .setSetupDataCallResponse(setupDataCallResponse).build());
1838     }
1839 
1840     /**
1841      * Write call related solicited response event
1842      *
1843      * @param phoneId Phone id
1844      * @param rilSerial RIL request serial number
1845      * @param rilError RIL error
1846      * @param rilRequest RIL request
1847      */
writeOnCallSolicitedResponse(int phoneId, int rilSerial, int rilError, int rilRequest)1848     private void writeOnCallSolicitedResponse(int phoneId, int rilSerial, int rilError,
1849                                               int rilRequest) {
1850         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1851         if (callSession == null) {
1852             Rlog.e(TAG, "writeOnCallSolicitedResponse: Call session is missing");
1853         } else {
1854             callSession.addEvent(new CallSessionEventBuilder(
1855                     TelephonyCallSession.Event.Type.RIL_RESPONSE)
1856                     .setRilRequest(toCallSessionRilRequest(rilRequest))
1857                     .setRilRequestId(rilSerial)
1858                     .setRilError(rilError + 1));
1859         }
1860     }
1861 
1862     /**
1863      * Write SMS related solicited response event
1864      *
1865      * @param phoneId Phone id
1866      * @param rilSerial RIL request serial number
1867      * @param rilError RIL error
1868      * @param response SMS response
1869      */
writeOnSmsSolicitedResponse(int phoneId, int rilSerial, int rilError, SmsResponse response)1870     private synchronized void writeOnSmsSolicitedResponse(int phoneId, int rilSerial, int rilError,
1871                                                           SmsResponse response) {
1872         InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId);
1873         if (smsSession == null) {
1874             Rlog.e(TAG, "SMS session is missing");
1875         } else {
1876             int errorCode = SmsResponse.NO_ERROR_CODE;
1877             long messageId = 0L;
1878             if (response != null) {
1879                 errorCode = response.mErrorCode;
1880                 messageId = response.mMessageId;
1881             }
1882 
1883             smsSession.addEvent(new SmsSessionEventBuilder(
1884                     SmsSession.Event.Type.SMS_SEND_RESULT)
1885                     .setErrorCode(errorCode)
1886                     .setRilErrno(rilError + 1)
1887                     .setRilRequestId(rilSerial)
1888                     .setMessageId(messageId)
1889             );
1890 
1891             smsSession.decreaseExpectedResponse();
1892             finishSmsSessionIfNeeded(smsSession);
1893         }
1894     }
1895 
1896     /**
1897      * Write SMS related solicited response event
1898      *
1899      * @param phoneId Phone id
1900      * @param errorReason Defined in {@link SmsManager} RESULT_XXX.
1901      * @param messageId Unique id for this message.
1902      */
writeOnImsServiceSmsSolicitedResponse(int phoneId, @ImsSmsImplBase.SendStatusResult int resultCode, int errorReason, long messageId)1903     public synchronized void writeOnImsServiceSmsSolicitedResponse(int phoneId,
1904             @ImsSmsImplBase.SendStatusResult int resultCode, int errorReason,
1905             long messageId) {
1906 
1907         InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId);
1908         if (smsSession == null) {
1909             Rlog.e(TAG, "SMS session is missing");
1910         } else {
1911 
1912             smsSession.addEvent(new SmsSessionEventBuilder(
1913                     SmsSession.Event.Type.SMS_SEND_RESULT)
1914                     .setImsServiceErrno(resultCode)
1915                     .setErrorCode(errorReason)
1916                     .setMessageId(messageId)
1917             );
1918 
1919             smsSession.decreaseExpectedResponse();
1920             finishSmsSessionIfNeeded(smsSession);
1921         }
1922     }
1923 
1924     /**
1925      * Write deactivate data call response event
1926      *
1927      * @param phoneId Phone id
1928      * @param rilError RIL error
1929      */
writeOnDeactivateDataCallResponse(int phoneId, int rilError)1930     private void writeOnDeactivateDataCallResponse(int phoneId, int rilError) {
1931         addTelephonyEvent(new TelephonyEventBuilder(phoneId)
1932                 .setDeactivateDataCallResponse(rilError + 1).build());
1933     }
1934 
1935     /**
1936      * Write RIL solicited response event
1937      *
1938      * @param phoneId Phone id
1939      * @param rilSerial RIL request serial number
1940      * @param rilError RIL error
1941      * @param rilRequest RIL request
1942      * @param ret The returned RIL response
1943      */
writeOnRilSolicitedResponse(int phoneId, int rilSerial, int rilError, int rilRequest, Object ret)1944     public void writeOnRilSolicitedResponse(int phoneId, int rilSerial, int rilError,
1945                                             int rilRequest, Object ret) {
1946         switch (rilRequest) {
1947             case RIL_REQUEST_SETUP_DATA_CALL:
1948                 DataCallResponse response = (DataCallResponse) ret;
1949                 writeOnSetupDataCallResponse(phoneId, rilSerial, rilError, rilRequest, response);
1950                 break;
1951             case RIL_REQUEST_DEACTIVATE_DATA_CALL:
1952                 writeOnDeactivateDataCallResponse(phoneId, rilError);
1953                 break;
1954             case RIL_REQUEST_HANGUP:
1955             case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
1956             case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
1957             case RIL_REQUEST_DIAL:
1958             case RIL_REQUEST_ANSWER:
1959                 writeOnCallSolicitedResponse(phoneId, rilSerial, rilError, rilRequest);
1960                 break;
1961             case RIL_REQUEST_SEND_SMS:
1962             case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
1963             case RIL_REQUEST_CDMA_SEND_SMS:
1964             case RIL_REQUEST_IMS_SEND_SMS:
1965                 SmsResponse smsResponse = (SmsResponse) ret;
1966                 writeOnSmsSolicitedResponse(phoneId, rilSerial, rilError, smsResponse);
1967                 break;
1968         }
1969     }
1970 
1971     /**
1972      * Write network validation event.
1973      * @param networkValidationState the network validation state.
1974      */
writeNetworkValidate(int networkValidationState)1975     public void writeNetworkValidate(int networkValidationState) {
1976         addTelephonyEvent(
1977                 new TelephonyEventBuilder().setNetworkValidate(networkValidationState).build());
1978     }
1979 
1980     /**
1981      * Write data switch event.
1982      * @param subId data switch to the subscription with this id.
1983      * @param dataSwitch the reason and state of data switch.
1984      */
writeDataSwitch(int subId, DataSwitch dataSwitch)1985     public void writeDataSwitch(int subId, DataSwitch dataSwitch) {
1986         int phoneId = SubscriptionManager.getPhoneId(subId);
1987         addTelephonyEvent(new TelephonyEventBuilder(phoneId).setDataSwitch(dataSwitch).build());
1988     }
1989 
1990     /**
1991      * Write on demand data switch event.
1992      * @param onDemandDataSwitch the apn and state of on demand data switch.
1993      */
writeOnDemandDataSwitch(OnDemandDataSwitch onDemandDataSwitch)1994     public void writeOnDemandDataSwitch(OnDemandDataSwitch onDemandDataSwitch) {
1995         addTelephonyEvent(
1996                 new TelephonyEventBuilder().setOnDemandDataSwitch(onDemandDataSwitch).build());
1997     }
1998 
1999     /**
2000      * Write phone state changed event
2001      *
2002      * @param phoneId Phone id
2003      * @param phoneState Phone state. See PhoneConstants.State for the details.
2004      */
writePhoneState(int phoneId, PhoneConstants.State phoneState)2005     public void writePhoneState(int phoneId, PhoneConstants.State phoneState) {
2006         int state;
2007         switch (phoneState) {
2008             case IDLE:
2009                 state = TelephonyCallSession.Event.PhoneState.STATE_IDLE;
2010                 break;
2011             case RINGING:
2012                 state = TelephonyCallSession.Event.PhoneState.STATE_RINGING;
2013                 break;
2014             case OFFHOOK:
2015                 state = TelephonyCallSession.Event.PhoneState.STATE_OFFHOOK;
2016                 break;
2017             default:
2018                 state = TelephonyCallSession.Event.PhoneState.STATE_UNKNOWN;
2019                 break;
2020         }
2021 
2022         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
2023         if (callSession == null) {
2024             Rlog.e(TAG, "writePhoneState: Call session is missing");
2025         } else {
2026             // For CS Calls Finish the Call Session after Receiving the Last Call Fail Cause
2027             // For IMS calls we receive the Disconnect Cause along with Call End event.
2028             // So we can finish the call session here.
2029             callSession.setLastKnownPhoneState(state);
2030             if ((state == TelephonyCallSession.Event.PhoneState.STATE_IDLE)
2031                     && (!callSession.containsCsCalls())) {
2032                 finishCallSession(callSession);
2033             }
2034             callSession.addEvent(new CallSessionEventBuilder(
2035                     TelephonyCallSession.Event.Type.PHONE_STATE_CHANGED)
2036                     .setPhoneState(state));
2037         }
2038     }
2039 
2040     /**
2041      * Extracts the call ID from an ImsSession.
2042      *
2043      * @param session The session.
2044      * @return The call ID for the session, or -1 if none was found.
2045      */
getCallId(ImsCallSession session)2046     private int getCallId(ImsCallSession session) {
2047         if (session == null) {
2048             return -1;
2049         }
2050 
2051         try {
2052             return Integer.parseInt(session.getCallId());
2053         } catch (NumberFormatException nfe) {
2054             return -1;
2055         }
2056     }
2057 
2058     /**
2059      * Write IMS call state changed event
2060      *
2061      * @param phoneId Phone id
2062      * @param session IMS call session
2063      * @param callState IMS call state
2064      */
writeImsCallState(int phoneId, ImsCallSession session, ImsPhoneCall.State callState)2065     public void writeImsCallState(int phoneId, ImsCallSession session,
2066                                   ImsPhoneCall.State callState) {
2067         int state;
2068         switch (callState) {
2069             case IDLE:
2070                 state = TelephonyCallSession.Event.CallState.CALL_IDLE; break;
2071             case ACTIVE:
2072                 state = TelephonyCallSession.Event.CallState.CALL_ACTIVE; break;
2073             case HOLDING:
2074                 state = TelephonyCallSession.Event.CallState.CALL_HOLDING; break;
2075             case DIALING:
2076                 state = TelephonyCallSession.Event.CallState.CALL_DIALING; break;
2077             case ALERTING:
2078                 state = TelephonyCallSession.Event.CallState.CALL_ALERTING; break;
2079             case INCOMING:
2080                 state = TelephonyCallSession.Event.CallState.CALL_INCOMING; break;
2081             case WAITING:
2082                 state = TelephonyCallSession.Event.CallState.CALL_WAITING; break;
2083             case DISCONNECTED:
2084                 state = TelephonyCallSession.Event.CallState.CALL_DISCONNECTED; break;
2085             case DISCONNECTING:
2086                 state = TelephonyCallSession.Event.CallState.CALL_DISCONNECTING; break;
2087             default:
2088                 state = TelephonyCallSession.Event.CallState.CALL_UNKNOWN; break;
2089         }
2090 
2091         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
2092         if (callSession == null) {
2093             Rlog.e(TAG, "Call session is missing");
2094         } else {
2095             callSession.addEvent(new CallSessionEventBuilder(
2096                     TelephonyCallSession.Event.Type.IMS_CALL_STATE_CHANGED)
2097                     .setCallIndex(getCallId(session))
2098                     .setCallState(state));
2099         }
2100     }
2101 
2102     /**
2103      * Write IMS call start event
2104      *
2105      * @param phoneId Phone id
2106      * @param session IMS call session
2107      */
writeOnImsCallStart(int phoneId, ImsCallSession session)2108     public void writeOnImsCallStart(int phoneId, ImsCallSession session) {
2109         InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
2110 
2111         callSession.addEvent(
2112                 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_COMMAND)
2113                         .setCallIndex(getCallId(session))
2114                         .setImsCommand(TelephonyCallSession.Event.ImsCommand.IMS_CMD_START));
2115     }
2116 
2117     /**
2118      * Write IMS incoming call event
2119      *
2120      * @param phoneId Phone id
2121      * @param session IMS call session
2122      */
writeOnImsCallReceive(int phoneId, ImsCallSession session)2123     public void writeOnImsCallReceive(int phoneId, ImsCallSession session) {
2124         InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
2125 
2126         callSession.addEvent(
2127                 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_CALL_RECEIVE)
2128                         .setCallIndex(getCallId(session)));
2129     }
2130 
2131     /**
2132      * Write IMS command event
2133      *
2134      * @param phoneId Phone id
2135      * @param session IMS call session
2136      * @param command IMS command
2137      */
writeOnImsCommand(int phoneId, ImsCallSession session, int command)2138     public void writeOnImsCommand(int phoneId, ImsCallSession session, int command) {
2139 
2140         InProgressCallSession callSession =  mInProgressCallSessions.get(phoneId);
2141         if (callSession == null) {
2142             Rlog.e(TAG, "Call session is missing");
2143         } else {
2144             callSession.addEvent(
2145                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_COMMAND)
2146                             .setCallIndex(getCallId(session))
2147                             .setImsCommand(command));
2148         }
2149     }
2150 
2151     /**
2152      * Convert IMS reason info into proto
2153      *
2154      * @param reasonInfo IMS reason info
2155      * @return Converted proto
2156      */
toImsReasonInfoProto(ImsReasonInfo reasonInfo)2157     private TelephonyProto.ImsReasonInfo toImsReasonInfoProto(ImsReasonInfo reasonInfo) {
2158         TelephonyProto.ImsReasonInfo ri = new TelephonyProto.ImsReasonInfo();
2159         if (reasonInfo != null) {
2160             ri.reasonCode = reasonInfo.getCode();
2161             ri.extraCode = reasonInfo.getExtraCode();
2162             String extraMessage = reasonInfo.getExtraMessage();
2163             if (extraMessage != null) {
2164                 ri.extraMessage = extraMessage;
2165             }
2166         }
2167         return ri;
2168     }
2169 
2170     /**
2171      * Convert CallQuality to proto.
2172      *
2173      * @param callQuality call quality to convert
2174      * @return Coverted proto
2175      */
toCallQualityProto( CallQuality callQuality)2176     public static TelephonyCallSession.Event.CallQuality toCallQualityProto(
2177             CallQuality callQuality) {
2178         TelephonyCallSession.Event.CallQuality cq = new TelephonyCallSession.Event.CallQuality();
2179         if (callQuality != null) {
2180             cq.downlinkLevel = callQualityLevelToProtoEnum(callQuality
2181                     .getDownlinkCallQualityLevel());
2182             cq.uplinkLevel = callQualityLevelToProtoEnum(callQuality.getUplinkCallQualityLevel());
2183             // callDuration is reported in millis, so convert to seconds
2184             cq.durationInSeconds = callQuality.getCallDuration() / 1000;
2185             cq.rtpPacketsTransmitted = callQuality.getNumRtpPacketsTransmitted();
2186             cq.rtpPacketsReceived = callQuality.getNumRtpPacketsReceived();
2187             cq.rtpPacketsTransmittedLost = callQuality.getNumRtpPacketsTransmittedLost();
2188             cq.rtpPacketsNotReceived = callQuality.getNumRtpPacketsNotReceived();
2189             cq.averageRelativeJitterMillis = callQuality.getAverageRelativeJitter();
2190             cq.maxRelativeJitterMillis = callQuality.getMaxRelativeJitter();
2191             cq.codecType = convertImsCodec(callQuality.getCodecType());
2192             cq.rtpInactivityDetected = callQuality.isRtpInactivityDetected();
2193             cq.rxSilenceDetected = callQuality.isIncomingSilenceDetectedAtCallSetup();
2194             cq.txSilenceDetected = callQuality.isOutgoingSilenceDetectedAtCallSetup();
2195         }
2196         return cq;
2197     }
2198 
2199     /**
2200      * Convert Call quality level into proto defined value.
2201      */
callQualityLevelToProtoEnum(int level)2202     private static int callQualityLevelToProtoEnum(int level) {
2203         if (level == CallQuality.CALL_QUALITY_EXCELLENT) {
2204             return TelephonyCallSession.Event.CallQuality.CallQualityLevel.EXCELLENT;
2205         } else if (level == CallQuality.CALL_QUALITY_GOOD) {
2206             return TelephonyCallSession.Event.CallQuality.CallQualityLevel.GOOD;
2207         } else if (level == CallQuality.CALL_QUALITY_FAIR) {
2208             return TelephonyCallSession.Event.CallQuality.CallQualityLevel.FAIR;
2209         } else if (level == CallQuality.CALL_QUALITY_POOR) {
2210             return TelephonyCallSession.Event.CallQuality.CallQualityLevel.POOR;
2211         } else if (level == CallQuality.CALL_QUALITY_BAD) {
2212             return TelephonyCallSession.Event.CallQuality.CallQualityLevel.BAD;
2213         } else if (level == CallQuality.CALL_QUALITY_NOT_AVAILABLE) {
2214             return TelephonyCallSession.Event.CallQuality.CallQualityLevel.NOT_AVAILABLE;
2215         } else {
2216             return TelephonyCallSession.Event.CallQuality.CallQualityLevel.UNDEFINED;
2217         }
2218     }
2219 
2220     /**
2221      * Write IMS call end event
2222      *
2223      * @param phoneId Phone id
2224      * @param session IMS call session
2225      * @param reasonInfo Call end reason
2226      * @param cqm Call Quality Metrics
2227      * @param emergencyNumber Emergency Number Info
2228      * @param countryIso Network country iso
2229      * @param emergencyNumberDatabaseVersion Emergency Number Database Version
2230      */
writeOnImsCallTerminated(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo, CallQualityMetrics cqm, EmergencyNumber emergencyNumber, String countryIso, int emergencyNumberDatabaseVersion)2231     public void writeOnImsCallTerminated(int phoneId, ImsCallSession session,
2232                                          ImsReasonInfo reasonInfo, CallQualityMetrics cqm,
2233                                          EmergencyNumber emergencyNumber, String countryIso,
2234                                          int emergencyNumberDatabaseVersion) {
2235         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
2236         if (callSession == null) {
2237             Rlog.e(TAG, "Call session is missing");
2238         } else {
2239             CallSessionEventBuilder callSessionEvent = new CallSessionEventBuilder(
2240                     TelephonyCallSession.Event.Type.IMS_CALL_TERMINATED);
2241             callSessionEvent.setCallIndex(getCallId(session));
2242             callSessionEvent.setImsReasonInfo(toImsReasonInfoProto(reasonInfo));
2243 
2244             if (cqm != null) {
2245                 callSessionEvent.setCallQualitySummaryDl(cqm.getCallQualitySummaryDl())
2246                         .setCallQualitySummaryUl(cqm.getCallQualitySummaryUl());
2247             }
2248 
2249             if (emergencyNumber != null) {
2250                 /** Only collect this emergency number information per sample percentage */
2251                 if (ThreadLocalRandom.current().nextDouble(0, 100)
2252                         < getSamplePercentageForEmergencyCall(countryIso)) {
2253                     callSessionEvent.setIsImsEmergencyCall(true);
2254                     callSessionEvent.setImsEmergencyNumberInfo(
2255                             convertEmergencyNumberToEmergencyNumberInfo(emergencyNumber));
2256                     callSessionEvent.setEmergencyNumberDatabaseVersion(
2257                             emergencyNumberDatabaseVersion);
2258                 }
2259             }
2260             callSession.addEvent(callSessionEvent);
2261         }
2262     }
2263 
2264     /**
2265      * Write IMS call hangover event
2266      *
2267      * @param phoneId Phone id
2268      * @param eventType hangover type
2269      * @param session IMS call session
2270      * @param srcAccessTech Hangover starting RAT
2271      * @param targetAccessTech Hangover destination RAT
2272      * @param reasonInfo Hangover reason
2273      */
writeOnImsCallHandoverEvent(int phoneId, int eventType, ImsCallSession session, int srcAccessTech, int targetAccessTech, ImsReasonInfo reasonInfo)2274     public void writeOnImsCallHandoverEvent(int phoneId, int eventType, ImsCallSession session,
2275                                             int srcAccessTech, int targetAccessTech,
2276                                             ImsReasonInfo reasonInfo) {
2277         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
2278         if (callSession == null) {
2279             Rlog.e(TAG, "Call session is missing");
2280         } else {
2281             callSession.addEvent(
2282                     new CallSessionEventBuilder(eventType)
2283                             .setCallIndex(getCallId(session))
2284                             .setSrcAccessTech(srcAccessTech)
2285                             .setTargetAccessTech(targetAccessTech)
2286                             .setImsReasonInfo(toImsReasonInfoProto(reasonInfo)));
2287         }
2288     }
2289 
2290     /**
2291      * Write Send SMS event
2292      *
2293      * @param phoneId Phone id
2294      * @param rilSerial RIL request serial number
2295      * @param tech SMS RAT
2296      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
2297      *         {@link SmsMessage#FORMAT_3GPP2}.
2298      * @param messageId Unique id for this message.
2299      */
writeRilSendSms(int phoneId, int rilSerial, int tech, int format, long messageId)2300     public synchronized void writeRilSendSms(int phoneId, int rilSerial, int tech, int format,
2301             long messageId) {
2302         InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId);
2303 
2304         smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_SEND)
2305                 .setTech(tech)
2306                 .setRilRequestId(rilSerial)
2307                 .setFormat(format)
2308                 .setMessageId(messageId)
2309         );
2310 
2311         smsSession.increaseExpectedResponse();
2312     }
2313 
2314     /**
2315      * Write Send SMS event using ImsService. Expecting response from
2316      * {@link #writeOnSmsSolicitedResponse}.
2317      *
2318      * @param phoneId Phone id
2319      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
2320      *         {@link SmsMessage#FORMAT_3GPP2}.
2321      * @param resultCode The result of sending the new SMS to the vendor layer to be sent to the
2322      *         carrier network.
2323      * @param messageId Unique id for this message.
2324      */
writeImsServiceSendSms(int phoneId, String format, @ImsSmsImplBase.SendStatusResult int resultCode, long messageId)2325     public synchronized void writeImsServiceSendSms(int phoneId, String format,
2326             @ImsSmsImplBase.SendStatusResult int resultCode, long messageId) {
2327         InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId);
2328         smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_SEND)
2329                 .setTech(SmsSession.Event.Tech.SMS_IMS)
2330                 .setImsServiceErrno(resultCode)
2331                 .setFormat(convertSmsFormat(format))
2332                 .setMessageId(messageId)
2333         );
2334 
2335         smsSession.increaseExpectedResponse();
2336     }
2337 
2338     /**
2339      * Write incoming Broadcast SMS event
2340      *
2341      * @param phoneId Phone id
2342      * @param format CB msg format
2343      * @param priority CB msg priority
2344      * @param isCMAS true if msg is CMAS
2345      * @param isETWS true if msg is ETWS
2346      * @param serviceCategory Service category of CB msg
2347      * @param serialNumber Serial number of the message
2348      * @param deliveredTimestamp Message's delivered timestamp
2349      */
writeNewCBSms(int phoneId, int format, int priority, boolean isCMAS, boolean isETWS, int serviceCategory, int serialNumber, long deliveredTimestamp)2350     public synchronized void writeNewCBSms(int phoneId, int format, int priority, boolean isCMAS,
2351                                            boolean isETWS, int serviceCategory, int serialNumber,
2352                                            long deliveredTimestamp) {
2353         InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId);
2354 
2355         int type;
2356         if (isCMAS) {
2357             type = SmsSession.Event.CBMessageType.CMAS;
2358         } else if (isETWS) {
2359             type = SmsSession.Event.CBMessageType.ETWS;
2360         } else {
2361             type = SmsSession.Event.CBMessageType.OTHER;
2362         }
2363 
2364         SmsSession.Event.CBMessage cbm = new SmsSession.Event.CBMessage();
2365         cbm.msgFormat = format;
2366         cbm.msgPriority = priority + 1;
2367         cbm.msgType = type;
2368         cbm.serviceCategory = serviceCategory;
2369         cbm.serialNumber = serialNumber;
2370         cbm.deliveredTimestampMillis = deliveredTimestamp;
2371 
2372         smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.CB_SMS_RECEIVED)
2373                 .setCellBroadcastMessage(cbm)
2374         );
2375 
2376         finishSmsSessionIfNeeded(smsSession);
2377     }
2378 
2379     /**
2380      * Write an incoming multi-part SMS that was discarded because some parts were missing
2381      *
2382      * @param phoneId Phone id
2383      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
2384      *         {@link SmsMessage#FORMAT_3GPP2}.
2385      * @param receivedCount Number of received parts.
2386      * @param totalCount Total number of parts of the SMS.
2387      */
writeDroppedIncomingMultipartSms(int phoneId, String format, int receivedCount, int totalCount)2388     public void writeDroppedIncomingMultipartSms(int phoneId, String format,
2389             int receivedCount, int totalCount) {
2390         logv("Logged dropped multipart SMS: received " + receivedCount
2391                 + " out of " + totalCount);
2392 
2393         SmsSession.Event.IncompleteSms details = new SmsSession.Event.IncompleteSms();
2394         details.receivedParts = receivedCount;
2395         details.totalParts = totalCount;
2396 
2397         InProgressSmsSession smsSession = startNewSmsSession(phoneId);
2398         smsSession.addEvent(
2399                 new SmsSessionEventBuilder(SmsSession.Event.Type.INCOMPLETE_SMS_RECEIVED)
2400                     .setFormat(convertSmsFormat(format))
2401                     .setIncompleteSms(details));
2402 
2403         finishSmsSession(smsSession);
2404     }
2405 
2406     /**
2407      * Write a generic SMS of any type
2408      *
2409      * @param phoneId Phone id
2410      * @param type Type of the SMS.
2411      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
2412      *         {@link SmsMessage#FORMAT_3GPP2}.
2413      * @param success Indicates if the SMS-PP was successfully delivered to the USIM.
2414      */
writeIncomingSmsWithType(int phoneId, int type, String format, boolean success)2415     private void writeIncomingSmsWithType(int phoneId, int type, String format, boolean success) {
2416         InProgressSmsSession smsSession = startNewSmsSession(phoneId);
2417         smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_RECEIVED)
2418                 .setFormat(convertSmsFormat(format))
2419                 .setSmsType(type)
2420                 .setErrorCode(success ? SmsManager.RESULT_ERROR_NONE :
2421                     SmsManager.RESULT_ERROR_GENERIC_FAILURE));
2422         finishSmsSession(smsSession);
2423     }
2424 
2425     /**
2426      * Write an incoming SMS-PP for the USIM
2427      *
2428      * @param phoneId Phone id
2429      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
2430      *         {@link SmsMessage#FORMAT_3GPP2}.
2431      * @param success Indicates if the SMS-PP was successfully delivered to the USIM.
2432      */
writeIncomingSMSPP(int phoneId, String format, boolean success)2433     public void writeIncomingSMSPP(int phoneId, String format, boolean success) {
2434         logv("Logged SMS-PP session. Result = " + success);
2435         writeIncomingSmsWithType(phoneId,
2436                 SmsSession.Event.SmsType.SMS_TYPE_SMS_PP, format, success);
2437     }
2438 
2439     /**
2440      * Write an incoming SMS to update voicemail indicator
2441      *
2442      * @param phoneId Phone id
2443      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
2444      *         {@link SmsMessage#FORMAT_3GPP2}.
2445      */
writeIncomingVoiceMailSms(int phoneId, String format)2446     public void writeIncomingVoiceMailSms(int phoneId, String format) {
2447         logv("Logged VoiceMail message.");
2448         writeIncomingSmsWithType(phoneId,
2449                 SmsSession.Event.SmsType.SMS_TYPE_VOICEMAIL_INDICATION, format, true);
2450     }
2451 
2452     /**
2453      * Write an incoming SMS of type 0
2454      *
2455      * @param phoneId Phone id
2456      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
2457      *         {@link SmsMessage#FORMAT_3GPP2}.
2458      */
writeIncomingSmsTypeZero(int phoneId, String format)2459     public void writeIncomingSmsTypeZero(int phoneId, String format) {
2460         logv("Logged Type-0 SMS message.");
2461         writeIncomingSmsWithType(phoneId,
2462                 SmsSession.Event.SmsType.SMS_TYPE_ZERO, format, true);
2463     }
2464 
2465     /**
2466      * Write a successful incoming SMS session
2467      *
2468      * @param phoneId Phone id
2469      * @param type Type of the SMS.
2470      * @param smsSource the source of the SMS message
2471      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
2472      *         {@link SmsMessage#FORMAT_3GPP2}.
2473      * @param timestamps array with timestamps of each incoming SMS part. It contains a single
2474      * @param blocked indicates if the message was blocked or not.
2475      * @param success Indicates if the SMS-PP was successfully delivered to the USIM.
2476      * @param messageId Unique id for this message.
2477      */
writeIncomingSmsSessionWithType(int phoneId, int type, @InboundSmsHandler.SmsSource int smsSource, String format, long[] timestamps, boolean blocked, boolean success, long messageId)2478     private void writeIncomingSmsSessionWithType(int phoneId, int type,
2479             @InboundSmsHandler.SmsSource int smsSource, String format, long[] timestamps,
2480             boolean blocked, boolean success, long messageId) {
2481         logv("Logged SMS session consisting of " + timestamps.length
2482                 + " parts, source = " + smsSource
2483                 + " blocked = " + blocked
2484                 + " type = " + type
2485                 + " " + SmsController.formatCrossStackMessageId(messageId));
2486 
2487         int smsFormat = convertSmsFormat(format);
2488         int smsError =
2489                 success ? SmsManager.RESULT_ERROR_NONE : SmsManager.RESULT_ERROR_GENERIC_FAILURE;
2490         int smsTech = getSmsTech(smsSource, smsFormat == SmsSession.Event.Format.SMS_FORMAT_3GPP2);
2491 
2492         InProgressSmsSession smsSession = startNewSmsSession(phoneId);
2493 
2494         long startElapsedTimeMillis = SystemClock.elapsedRealtime();
2495         for (int i = 0; i < timestamps.length; i++) {
2496             SmsSessionEventBuilder eventBuilder =
2497                     new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_RECEIVED)
2498                         .setFormat(smsFormat)
2499                         .setTech(smsTech)
2500                         .setErrorCode(smsError)
2501                         .setSmsType(type)
2502                         .setBlocked(blocked)
2503                         .setMessageId(messageId);
2504             long interval = (i > 0) ? timestamps[i] - timestamps[i - 1] : 0;
2505             smsSession.addEvent(startElapsedTimeMillis + interval, eventBuilder);
2506         }
2507         finishSmsSession(smsSession);
2508     }
2509 
2510     /**
2511      * Write an incoming WAP-PUSH message.
2512      *
2513      * @param phoneId Phone id
2514      * @param smsSource the source of the SMS message
2515      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
2516      *         {@link SmsMessage#FORMAT_3GPP2}.
2517      * @param timestamps array with timestamps of each incoming SMS part. It contains a single
2518      * @param success Indicates if the SMS-PP was successfully delivered to the USIM.
2519      * @param messageId Unique id for this message.
2520      */
writeIncomingWapPush(int phoneId, @InboundSmsHandler.SmsSource int smsSource, String format, long[] timestamps, boolean success, long messageId)2521     public void writeIncomingWapPush(int phoneId, @InboundSmsHandler.SmsSource int smsSource,
2522             String format, long[] timestamps, boolean success, long messageId) {
2523         writeIncomingSmsSessionWithType(phoneId, SmsSession.Event.SmsType.SMS_TYPE_WAP_PUSH,
2524                 smsSource, format, timestamps, false, success, messageId);
2525     }
2526 
2527     /**
2528      * Write a successful incoming SMS session
2529      *
2530      * @param phoneId Phone id
2531      * @param smsSource the source of the SMS message
2532      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
2533      *         {@link SmsMessage#FORMAT_3GPP2}.
2534      * @param timestamps array with timestamps of each incoming SMS part. It contains a single
2535      * @param blocked indicates if the message was blocked or not.
2536      * @param messageId Unique id for this message.
2537      */
writeIncomingSmsSession(int phoneId, @InboundSmsHandler.SmsSource int smsSource, String format, long[] timestamps, boolean blocked, long messageId)2538     public void writeIncomingSmsSession(int phoneId, @InboundSmsHandler.SmsSource int smsSource,
2539             String format, long[] timestamps, boolean blocked, long messageId) {
2540         writeIncomingSmsSessionWithType(phoneId, SmsSession.Event.SmsType.SMS_TYPE_NORMAL,
2541                 smsSource, format, timestamps, blocked, true, messageId);
2542     }
2543 
2544     /**
2545      * Write an error incoming SMS
2546      *
2547      * @param phoneId Phone id
2548      * @param is3gpp2 true for 3GPP2 format, false for 3GPP format.
2549      * @param smsSource the source of the SMS message
2550      * @param result Indicates the reason of the failure.
2551      */
writeIncomingSmsError(int phoneId, boolean is3gpp2, @InboundSmsHandler.SmsSource int smsSource, int result)2552     public void writeIncomingSmsError(int phoneId, boolean is3gpp2,
2553             @InboundSmsHandler.SmsSource int smsSource, int result) {
2554         logv("Incoming SMS error = " + result);
2555 
2556         int smsError = SmsManager.RESULT_ERROR_GENERIC_FAILURE;
2557         switch (result) {
2558             case Intents.RESULT_SMS_HANDLED:
2559                 // This should not happen.
2560                 return;
2561             case Intents.RESULT_SMS_OUT_OF_MEMORY:
2562                 smsError = SmsManager.RESULT_NO_MEMORY;
2563                 break;
2564             case Intents.RESULT_SMS_UNSUPPORTED:
2565                 smsError = SmsManager.RESULT_REQUEST_NOT_SUPPORTED;
2566                 break;
2567             case Intents.RESULT_SMS_GENERIC_ERROR:
2568             default:
2569                 smsError = SmsManager.RESULT_ERROR_GENERIC_FAILURE;
2570                 break;
2571         }
2572 
2573         InProgressSmsSession smsSession = startNewSmsSession(phoneId);
2574 
2575         SmsSessionEventBuilder eventBuilder =
2576                 new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_RECEIVED)
2577                     .setFormat(is3gpp2
2578                                 ? SmsSession.Event.Format.SMS_FORMAT_3GPP2
2579                                 : SmsSession.Event.Format.SMS_FORMAT_3GPP)
2580                     .setTech(getSmsTech(smsSource, is3gpp2))
2581                     .setErrorCode(smsError);
2582         smsSession.addEvent(eventBuilder);
2583         finishSmsSession(smsSession);
2584     }
2585 
2586     /**
2587      * Write NITZ event
2588      *
2589      * @param phoneId Phone id
2590      * @param timestamp NITZ time in milliseconds
2591      */
writeNITZEvent(int phoneId, long timestamp)2592     public void writeNITZEvent(int phoneId, long timestamp) {
2593         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setNITZ(timestamp).build();
2594         addTelephonyEvent(event);
2595 
2596         annotateInProgressCallSession(event.timestampMillis, phoneId,
2597                 new CallSessionEventBuilder(
2598                         TelephonyCallSession.Event.Type.NITZ_TIME)
2599                         .setNITZ(timestamp));
2600     }
2601 
2602     /**
2603      * Write Modem Restart event
2604      *
2605      * @param phoneId Phone id
2606      * @param reason Reason for the modem reset.
2607      */
writeModemRestartEvent(int phoneId, String reason)2608     public void writeModemRestartEvent(int phoneId, String reason) {
2609         final ModemRestart modemRestart = new ModemRestart();
2610         String basebandVersion = Build.getRadioVersion();
2611         if (basebandVersion != null) modemRestart.basebandVersion = basebandVersion;
2612         if (reason != null) modemRestart.reason = reason;
2613         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setModemRestart(
2614                 modemRestart).build();
2615         addTelephonyEvent(event);
2616     }
2617 
2618     /**
2619      * Write carrier identification matching event
2620      *
2621      * @param phoneId Phone id
2622      * @param version Carrier table version
2623      * @param cid Unique Carrier Id
2624      * @param unknownMcmnc MCC and MNC that map to this carrier
2625      * @param unknownGid1 Group id level 1
2626      * @param simInfo Subscription info
2627      */
writeCarrierIdMatchingEvent(int phoneId, int version, int cid, String unknownMcmnc, String unknownGid1, CarrierResolver.CarrierMatchingRule simInfo)2628     public void writeCarrierIdMatchingEvent(int phoneId, int version, int cid,
2629                                             String unknownMcmnc, String unknownGid1,
2630                                             CarrierResolver.CarrierMatchingRule simInfo) {
2631         final CarrierIdMatching carrierIdMatching = new CarrierIdMatching();
2632         final CarrierIdMatchingResult carrierIdMatchingResult = new CarrierIdMatchingResult();
2633 
2634         // fill in information for unknown mccmnc and gid1 for unidentified carriers.
2635         if (cid != TelephonyManager.UNKNOWN_CARRIER_ID) {
2636             // Successful matching event if result only has carrierId
2637             carrierIdMatchingResult.carrierId = cid;
2638             // Unknown Gid1 event if result only has carrierId, gid1 and mccmnc
2639             if (unknownGid1 != null) {
2640                 carrierIdMatchingResult.unknownMccmnc = unknownMcmnc;
2641                 carrierIdMatchingResult.unknownGid1 = unknownGid1;
2642             }
2643         } else {
2644             // Unknown mccmnc event if result only has mccmnc
2645             if (unknownMcmnc != null) {
2646                 carrierIdMatchingResult.unknownMccmnc = unknownMcmnc;
2647             }
2648         }
2649 
2650         // fill in complete matching information from the SIM.
2651         carrierIdMatchingResult.mccmnc = TelephonyUtils.emptyIfNull(simInfo.mccMnc);
2652         carrierIdMatchingResult.spn = TelephonyUtils.emptyIfNull(simInfo.spn);
2653         carrierIdMatchingResult.pnn = TelephonyUtils.emptyIfNull(simInfo.plmn);
2654         carrierIdMatchingResult.gid1 = TelephonyUtils.emptyIfNull(simInfo.gid1);
2655         carrierIdMatchingResult.gid2 = TelephonyUtils.emptyIfNull(simInfo.gid2);
2656         carrierIdMatchingResult.imsiPrefix = TelephonyUtils.emptyIfNull(simInfo.imsiPrefixPattern);
2657         carrierIdMatchingResult.iccidPrefix = TelephonyUtils.emptyIfNull(simInfo.iccidPrefix);
2658         carrierIdMatchingResult.preferApn = TelephonyUtils.emptyIfNull(simInfo.apn);
2659         if (simInfo.privilegeAccessRule != null) {
2660             carrierIdMatchingResult.privilegeAccessRule =
2661                     simInfo.privilegeAccessRule.stream().toArray(String[]::new);
2662         }
2663 
2664         carrierIdMatching.cidTableVersion = version;
2665         carrierIdMatching.result = carrierIdMatchingResult;
2666 
2667         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setCarrierIdMatching(
2668                 carrierIdMatching).build();
2669         mLastCarrierId.put(phoneId, carrierIdMatching);
2670         addTelephonyEvent(event);
2671     }
2672 
2673     /**
2674      * Write emergency number update event
2675      *
2676      * @param emergencyNumber Updated emergency number
2677      */
writeEmergencyNumberUpdateEvent(int phoneId, EmergencyNumber emergencyNumber, int emergencyNumberDatabaseVersion)2678     public void writeEmergencyNumberUpdateEvent(int phoneId, EmergencyNumber emergencyNumber,
2679             int emergencyNumberDatabaseVersion) {
2680         if (emergencyNumber == null) {
2681             return;
2682         }
2683         final EmergencyNumberInfo emergencyNumberInfo =
2684                 convertEmergencyNumberToEmergencyNumberInfo(emergencyNumber);
2685 
2686         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setUpdatedEmergencyNumber(
2687                 emergencyNumberInfo, emergencyNumberDatabaseVersion).build();
2688         addTelephonyEvent(event);
2689     }
2690 
2691     /**
2692      * Write network capabilities changed event
2693      *
2694      * @param phoneId Phone id
2695      * @param networkCapabilities Network capabilities
2696      */
writeNetworkCapabilitiesChangedEvent(int phoneId, NetworkCapabilities networkCapabilities)2697     public void writeNetworkCapabilitiesChangedEvent(int phoneId,
2698             NetworkCapabilities networkCapabilities) {
2699         final NetworkCapabilitiesInfo caps = new NetworkCapabilitiesInfo();
2700         caps.isNetworkUnmetered = networkCapabilities.hasCapability(
2701                 NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED);
2702 
2703         TelephonyEvent event = new TelephonyEventBuilder(phoneId)
2704                 .setNetworkCapabilities(caps).build();
2705         mLastNetworkCapabilitiesInfos.put(phoneId, caps);
2706         addTelephonyEvent(event);
2707     }
2708 
2709     /** Write radio state changed event */
writeRadioState(int phoneId, @RadioPowerState int state)2710     public void writeRadioState(int phoneId, @RadioPowerState int state) {
2711         int radioState = convertRadioState(state);
2712         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setRadioState(radioState).build();
2713         mLastRadioState.put(phoneId, radioState);
2714         addTelephonyEvent(event);
2715     }
2716 
convertRadioState(@adioPowerState int state)2717     private static int convertRadioState(@RadioPowerState int state) {
2718         switch (state) {
2719             case TelephonyManager.RADIO_POWER_OFF:
2720                 return RadioState.RADIO_STATE_OFF;
2721             case TelephonyManager.RADIO_POWER_ON:
2722                 return RadioState.RADIO_STATE_ON;
2723             case TelephonyManager.RADIO_POWER_UNAVAILABLE:
2724                 return RadioState.RADIO_STATE_UNAVAILABLE;
2725             default:
2726                 return RadioState.RADIO_STATE_UNKNOWN;
2727         }
2728     }
2729 
2730     /**
2731      * Convert SMS format
2732      */
convertSmsFormat(String format)2733     private int convertSmsFormat(String format) {
2734         int formatCode = SmsSession.Event.Format.SMS_FORMAT_UNKNOWN;
2735         switch (format) {
2736             case SmsMessage.FORMAT_3GPP : {
2737                 formatCode = SmsSession.Event.Format.SMS_FORMAT_3GPP;
2738                 break;
2739             }
2740             case SmsMessage.FORMAT_3GPP2: {
2741                 formatCode = SmsSession.Event.Format.SMS_FORMAT_3GPP2;
2742                 break;
2743             }
2744         }
2745         return formatCode;
2746     }
2747 
2748     /**
2749      * Get SMS technology
2750      */
getSmsTech(@nboundSmsHandler.SmsSource int smsSource, boolean is3gpp2)2751     private int getSmsTech(@InboundSmsHandler.SmsSource int smsSource, boolean is3gpp2) {
2752         if (smsSource == SOURCE_INJECTED_FROM_IMS) {
2753             return SmsSession.Event.Tech.SMS_IMS;
2754         } else if (smsSource == SOURCE_NOT_INJECTED) {
2755             return is3gpp2 ? SmsSession.Event.Tech.SMS_CDMA : SmsSession.Event.Tech.SMS_GSM;
2756         } else { // SOURCE_INJECTED_FROM_UNKNOWN
2757             return SmsSession.Event.Tech.SMS_UNKNOWN;
2758         }
2759     }
2760 
2761     /**
2762      * Convert IMS audio codec into proto defined value
2763      *
2764      * @param c IMS codec value
2765      * @return Codec value defined in call session proto
2766      */
convertImsCodec(int c)2767     private static int convertImsCodec(int c) {
2768         switch (c) {
2769             case ImsStreamMediaProfile.AUDIO_QUALITY_AMR:
2770                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR;
2771             case ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB:
2772                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR_WB;
2773             case ImsStreamMediaProfile.AUDIO_QUALITY_QCELP13K:
2774                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_QCELP13K;
2775             case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC:
2776                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC;
2777             case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_B:
2778                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_B;
2779             case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_WB:
2780                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_WB;
2781             case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_NW:
2782                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_NW;
2783             case ImsStreamMediaProfile.AUDIO_QUALITY_GSM_EFR:
2784                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_EFR;
2785             case ImsStreamMediaProfile.AUDIO_QUALITY_GSM_FR:
2786                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_FR;
2787             case ImsStreamMediaProfile.AUDIO_QUALITY_GSM_HR:
2788                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_HR;
2789             case ImsStreamMediaProfile.AUDIO_QUALITY_G711U:
2790                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G711U;
2791             case ImsStreamMediaProfile.AUDIO_QUALITY_G723:
2792                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G723;
2793             case ImsStreamMediaProfile.AUDIO_QUALITY_G711A:
2794                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G711A;
2795             case ImsStreamMediaProfile.AUDIO_QUALITY_G722:
2796                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G722;
2797             case ImsStreamMediaProfile.AUDIO_QUALITY_G711AB:
2798                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G711AB;
2799             case ImsStreamMediaProfile.AUDIO_QUALITY_G729:
2800                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G729;
2801             case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_NB:
2802                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_NB;
2803             case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_WB:
2804                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_WB;
2805             case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_SWB:
2806                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_SWB;
2807             case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_FB:
2808                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_FB;
2809             default:
2810                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_UNKNOWN;
2811         }
2812     }
2813 
2814     /**
2815      * Convert GSM/CDMA audio codec into proto defined value
2816      *
2817      * @param c GSM/CDMA codec value
2818      * @return Codec value defined in call session proto
2819      */
convertGsmCdmaCodec(int c)2820     private int convertGsmCdmaCodec(int c) {
2821         switch (c) {
2822             case DriverCall.AUDIO_QUALITY_AMR:
2823                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR;
2824             case DriverCall.AUDIO_QUALITY_AMR_WB:
2825                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR_WB;
2826             case DriverCall.AUDIO_QUALITY_GSM_EFR:
2827                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_EFR;
2828             case DriverCall.AUDIO_QUALITY_GSM_FR:
2829                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_FR;
2830             case DriverCall.AUDIO_QUALITY_GSM_HR:
2831                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_HR;
2832             case DriverCall.AUDIO_QUALITY_EVRC:
2833                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC;
2834             case DriverCall.AUDIO_QUALITY_EVRC_B:
2835                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_B;
2836             case DriverCall.AUDIO_QUALITY_EVRC_WB:
2837                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_WB;
2838             case DriverCall.AUDIO_QUALITY_EVRC_NW:
2839                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_NW;
2840             default:
2841                 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_UNKNOWN;
2842         }
2843     }
2844 
2845     /**
2846      * Write audio codec event
2847      *
2848      * @param phoneId Phone id
2849      * @param session IMS call session
2850      */
writeAudioCodecIms(int phoneId, ImsCallSession session)2851     public void writeAudioCodecIms(int phoneId, ImsCallSession session) {
2852         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
2853         if (callSession == null) {
2854             Rlog.e(TAG, "Call session is missing");
2855             return;
2856         }
2857 
2858         ImsCallProfile localCallProfile = session.getLocalCallProfile();
2859         if (localCallProfile != null) {
2860             int codec = convertImsCodec(localCallProfile.mMediaProfile.mAudioQuality);
2861             callSession.addEvent(new CallSessionEventBuilder(
2862                     TelephonyCallSession.Event.Type.AUDIO_CODEC)
2863                     .setCallIndex(getCallId(session))
2864                     .setAudioCodec(codec));
2865 
2866             logv("Logged Audio Codec event. Value: " + codec);
2867         }
2868     }
2869 
2870     /**
2871      * Write audio codec event
2872      *
2873      * @param phoneId Phone id
2874      * @param audioQuality Audio quality value
2875      */
writeAudioCodecGsmCdma(int phoneId, int audioQuality)2876     public void writeAudioCodecGsmCdma(int phoneId, int audioQuality) {
2877         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
2878         if (callSession == null) {
2879             Rlog.e(TAG, "Call session is missing");
2880             return;
2881         }
2882 
2883         int codec = convertGsmCdmaCodec(audioQuality);
2884         callSession.addEvent(new CallSessionEventBuilder(
2885                 TelephonyCallSession.Event.Type.AUDIO_CODEC)
2886                 .setAudioCodec(codec));
2887 
2888         logv("Logged Audio Codec event. Value: " + codec);
2889     }
2890 
2891     //TODO: Expand the proto in the future
writeOnImsCallInitiating(int phoneId, ImsCallSession session)2892     public void writeOnImsCallInitiating(int phoneId, ImsCallSession session) {}
writeOnImsCallProgressing(int phoneId, ImsCallSession session)2893     public void writeOnImsCallProgressing(int phoneId, ImsCallSession session) {}
writeOnImsCallStarted(int phoneId, ImsCallSession session)2894     public void writeOnImsCallStarted(int phoneId, ImsCallSession session) {}
writeOnImsCallStartFailed(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo)2895     public void writeOnImsCallStartFailed(int phoneId, ImsCallSession session,
2896                                           ImsReasonInfo reasonInfo) {}
writeOnImsCallHeld(int phoneId, ImsCallSession session)2897     public void writeOnImsCallHeld(int phoneId, ImsCallSession session) {}
writeOnImsCallHoldReceived(int phoneId, ImsCallSession session)2898     public void writeOnImsCallHoldReceived(int phoneId, ImsCallSession session) {}
writeOnImsCallHoldFailed(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo)2899     public void writeOnImsCallHoldFailed(int phoneId, ImsCallSession session,
2900                                          ImsReasonInfo reasonInfo) {}
writeOnImsCallResumed(int phoneId, ImsCallSession session)2901     public void writeOnImsCallResumed(int phoneId, ImsCallSession session) {}
writeOnImsCallResumeReceived(int phoneId, ImsCallSession session)2902     public void writeOnImsCallResumeReceived(int phoneId, ImsCallSession session) {}
writeOnImsCallResumeFailed(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo)2903     public void writeOnImsCallResumeFailed(int phoneId, ImsCallSession session,
2904                                            ImsReasonInfo reasonInfo) {}
writeOnRilTimeoutResponse(int phoneId, int rilSerial, int rilRequest)2905     public void writeOnRilTimeoutResponse(int phoneId, int rilSerial, int rilRequest) {}
2906 
2907     /**
2908      * Get the sample percentage of collecting metrics based on countries' population.
2909      *
2910      * The larger population the country has, the lower percentage we use to collect this
2911      * metrics. Since the exact population changes frequently, buckets of the population are used
2912      * instead of its exact number. Seven different levels of sampling percentage are assigned
2913      * based on the scale of population for countries.
2914      */
getSamplePercentageForEmergencyCall(String countryIso)2915     private double getSamplePercentageForEmergencyCall(String countryIso) {
2916         String countriesFor1Percentage = "cn,in";
2917         String countriesFor5Percentage = "us,id,br,pk,ng,bd,ru,mx,jp,et,ph,eg,vn,cd,tr,ir,de";
2918         String countriesFor15Percentage = "th,gb,fr,tz,it,za,mm,ke,kr,co,es,ug,ar,ua,dz,sd,iq";
2919         String countriesFor25Percentage = "pl,ca,af,ma,sa,pe,uz,ve,my,ao,mz,gh,np,ye,mg,kp,cm";
2920         String countriesFor35Percentage = "au,tw,ne,lk,bf,mw,ml,ro,kz,sy,cl,zm,gt,zw,nl,ec,sn";
2921         String countriesFor45Percentage = "kh,td,so,gn,ss,rw,bj,tn,bi,be,cu,bo,ht,gr,do,cz,pt";
2922         if (countriesFor1Percentage.contains(countryIso)) {
2923             return 1;
2924         } else if (countriesFor5Percentage.contains(countryIso)) {
2925             return 5;
2926         } else if (countriesFor15Percentage.contains(countryIso)) {
2927             return 15;
2928         } else if (countriesFor25Percentage.contains(countryIso)) {
2929             return 25;
2930         } else if (countriesFor35Percentage.contains(countryIso)) {
2931             return 35;
2932         } else if (countriesFor45Percentage.contains(countryIso)) {
2933             return 45;
2934         } else {
2935             return 50;
2936         }
2937     }
2938 
mapSimStateToProto(int simState)2939     private static int mapSimStateToProto(int simState) {
2940         switch (simState) {
2941             case TelephonyManager.SIM_STATE_ABSENT:
2942                 return SimState.SIM_STATE_ABSENT;
2943             case TelephonyManager.SIM_STATE_LOADED:
2944                 return SimState.SIM_STATE_LOADED;
2945             default:
2946                 return SimState.SIM_STATE_UNKNOWN;
2947         }
2948     }
2949 
2950     /**
2951      * Write bandwidth estimator stats
2952      */
writeBandwidthStats(int link, int rat, int nrMode, int signalLevel, int bwEstExtErrPercent, int coldStartErrPercent, int bwKbps)2953     public synchronized void writeBandwidthStats(int link, int rat, int nrMode,
2954             int signalLevel, int bwEstExtErrPercent, int coldStartErrPercent, int bwKbps) {
2955         BwEstimationStats stats = lookupEstimationStats(link, rat, nrMode);
2956         stats.mBwEstErrorAcc[signalLevel] += Math.abs(bwEstExtErrPercent);
2957         stats.mStaticBwErrorAcc[signalLevel] += Math.abs(coldStartErrPercent);
2958         stats.mBwAccKbps[signalLevel] += bwKbps;
2959         stats.mCount[signalLevel]++;
2960     }
2961 
lookupEstimationStats(int linkIndex, int dataRat, int nrMode)2962     private BwEstimationStats lookupEstimationStats(int linkIndex, int dataRat, int nrMode) {
2963         String dataRatName = LinkBandwidthEstimator.getDataRatName(dataRat, nrMode);
2964         BwEstimationStats ans = mBwEstStatsMapList.get(linkIndex).get(dataRatName);
2965         if (ans == null) {
2966             ans = new BwEstimationStats(dataRat, nrMode);
2967             mBwEstStatsMapList.get(linkIndex).put(dataRatName, ans);
2968         }
2969         return ans;
2970     }
2971 
buildBandwidthEstimatorStats()2972     private BandwidthEstimatorStats buildBandwidthEstimatorStats() {
2973         BandwidthEstimatorStats stats = new BandwidthEstimatorStats();
2974         List<BandwidthEstimatorStats.PerRat> ratList;
2975         ratList = writeBandwidthEstimatorStatsRatList(mBwEstStatsMapList.get(0));
2976         stats.perRatTx = ratList.toArray(new BandwidthEstimatorStats.PerRat[0]);
2977         ratList = writeBandwidthEstimatorStatsRatList(mBwEstStatsMapList.get(1));
2978         stats.perRatRx = ratList.toArray(new BandwidthEstimatorStats.PerRat[0]);
2979         return stats;
2980     }
2981 
writeBandwidthEstimatorStatsRatList( Map<String, BwEstimationStats> bwEstStatsMap)2982     private List<BandwidthEstimatorStats.PerRat> writeBandwidthEstimatorStatsRatList(
2983             Map<String, BwEstimationStats> bwEstStatsMap) {
2984         List<BandwidthEstimatorStats.PerRat> ratList = new ArrayList<>();
2985         for (BwEstimationStats perRat : bwEstStatsMap.values()) {
2986             ratList.add(perRat.writeBandwidthStats());
2987         }
2988         return ratList;
2989     }
2990 
2991     private static class BwEstimationStats {
2992         final int mRadioTechnology;
2993         final int mNrMode;
2994         final long[] mBwEstErrorAcc = new long[NUM_SIGNAL_LEVEL];
2995         final long[] mStaticBwErrorAcc = new long[NUM_SIGNAL_LEVEL];
2996         final long[] mBwAccKbps = new long[NUM_SIGNAL_LEVEL];
2997         final int[] mCount = new int[NUM_SIGNAL_LEVEL];
2998 
BwEstimationStats(int radioTechnology, int nrMode)2999         BwEstimationStats(int radioTechnology, int nrMode) {
3000             mRadioTechnology = radioTechnology;
3001             mNrMode = nrMode;
3002         }
3003 
3004         @Override
toString()3005         public String toString() {
3006             StringBuilder sb = new StringBuilder();
3007             return sb.append(LinkBandwidthEstimator.getDataRatName(mRadioTechnology, mNrMode))
3008                     .append("\n Count\n").append(printValues(mCount))
3009                     .append("\n AvgKbps\n").append(printAvgValues(mBwAccKbps, mCount))
3010                     .append("\n BwEst Error\n").append(printAvgValues(mBwEstErrorAcc, mCount))
3011                     .append("\n StaticBw Error\n").append(printAvgValues(mStaticBwErrorAcc, mCount))
3012                     .toString();
3013         }
3014 
printValues(int[] values)3015         private String printValues(int[] values) {
3016             StringBuilder sb = new StringBuilder();
3017             for (int k = 0; k < NUM_SIGNAL_LEVEL; k++) {
3018                 sb.append(" " + values[k]);
3019             }
3020             return sb.toString();
3021         }
3022 
printAvgValues(long[] stats, int[] count)3023         private String printAvgValues(long[] stats, int[] count) {
3024             StringBuilder sb = new StringBuilder();
3025             for (int k = 0; k < NUM_SIGNAL_LEVEL; k++) {
3026                 int avgStat = calculateAvg(stats[k], count[k]);
3027                 sb.append(" " + avgStat);
3028             }
3029             return sb.toString();
3030         }
3031 
writeBandwidthStats()3032         private BandwidthEstimatorStats.PerRat writeBandwidthStats() {
3033             BandwidthEstimatorStats.PerRat stats = new BandwidthEstimatorStats.PerRat();
3034             List<BandwidthEstimatorStats.PerLevel> levelList = new ArrayList<>();
3035             for (int level = 0; level < NUM_SIGNAL_LEVEL; level++) {
3036                 BandwidthEstimatorStats.PerLevel currStats = writeBandwidthStatsPerLevel(level);
3037                 if (currStats != null) {
3038                     levelList.add(currStats);
3039                 }
3040             }
3041             stats.rat = mRadioTechnology;
3042             stats.perLevel = levelList.toArray(new BandwidthEstimatorStats.PerLevel[0]);
3043             stats.nrMode = mNrMode;
3044             return stats;
3045         }
3046 
writeBandwidthStatsPerLevel(int level)3047         private BandwidthEstimatorStats.PerLevel writeBandwidthStatsPerLevel(int level) {
3048             int count = mCount[level];
3049             if (count > 0) {
3050                 BandwidthEstimatorStats.PerLevel stats = new BandwidthEstimatorStats.PerLevel();
3051                 stats.signalLevel = level;
3052                 stats.count = count;
3053                 stats.avgBwKbps = calculateAvg(mBwAccKbps[level], count);
3054                 stats.staticBwErrorPercent = calculateAvg(mStaticBwErrorAcc[level], count);
3055                 stats.bwEstErrorPercent = calculateAvg(mBwEstErrorAcc[level], count);
3056                 return stats;
3057             }
3058             return null;
3059         }
3060 
calculateAvg(long acc, int count)3061         private int calculateAvg(long acc, int count) {
3062             return (count > 0) ? (int) (acc / count) : 0;
3063         }
3064     }
3065 
3066 }
3067