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