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