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