• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.metrics;
18 
19 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
20 
21 import static com.android.internal.telephony.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
27         .RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND;
28 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND;
29 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IMS_SEND_SMS;
30 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS;
31 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE;
32 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL;
33 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IP;
34 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;
35 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV6;
36 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_PPP;
37 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_UNKNOWN;
38 
39 import android.os.Build;
40 import android.os.SystemClock;
41 import android.telephony.Rlog;
42 import android.telephony.ServiceState;
43 import android.telephony.TelephonyHistogram;
44 import android.text.TextUtils;
45 import android.util.Base64;
46 import android.util.SparseArray;
47 
48 import com.android.ims.ImsConfig;
49 import com.android.ims.ImsReasonInfo;
50 import com.android.ims.internal.ImsCallSession;
51 import com.android.internal.telephony.GsmCdmaConnection;
52 import com.android.internal.telephony.PhoneConstants;
53 import com.android.internal.telephony.RIL;
54 import com.android.internal.telephony.RILConstants;
55 import com.android.internal.telephony.SmsResponse;
56 import com.android.internal.telephony.UUSInfo;
57 import com.android.internal.telephony.dataconnection.DataCallResponse;
58 import com.android.internal.telephony.imsphone.ImsPhoneCall;
59 import com.android.internal.telephony.nano.TelephonyProto;
60 import com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities;
61 import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
62 import com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
63 import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
64 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
65 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.CallState;
66 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.RilCall;
67 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.RilCall.Type;
68 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
69 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart;
70 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
71 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCall;
72 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse;
73 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse
74         .RilDataCallFailCause;
75 import com.android.internal.telephony.nano.TelephonyProto.TelephonyLog;
76 import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState;
77 import com.android.internal.telephony.nano.TelephonyProto.TelephonySettings;
78 import com.android.internal.telephony.nano.TelephonyProto.TimeInterval;
79 import com.android.internal.util.IndentingPrintWriter;
80 
81 import java.io.FileDescriptor;
82 import java.io.PrintWriter;
83 import java.util.ArrayDeque;
84 import java.util.ArrayList;
85 import java.util.Arrays;
86 import java.util.Deque;
87 import java.util.List;
88 
89 /**
90  * Telephony metrics holds all metrics events and convert it into telephony proto buf.
91  * @hide
92  */
93 public class TelephonyMetrics {
94 
95     private static final String TAG = TelephonyMetrics.class.getSimpleName();
96 
97     private static final boolean DBG = true;
98     private static final boolean VDBG = false; // STOPSHIP if true
99 
100     /** Maximum telephony events stored */
101     private static final int MAX_TELEPHONY_EVENTS = 1000;
102 
103     /** Maximum call sessions stored */
104     private static final int MAX_COMPLETED_CALL_SESSIONS = 50;
105 
106     /** Maximum sms sessions stored */
107     private static final int MAX_COMPLETED_SMS_SESSIONS = 500;
108 
109     /** For reducing the timing precision for privacy purposes */
110     private static final int SESSION_START_PRECISION_MINUTES = 5;
111 
112     /** The TelephonyMetrics singleton instance */
113     private static TelephonyMetrics sInstance;
114 
115     /** Telephony events */
116     private final Deque<TelephonyEvent> mTelephonyEvents = new ArrayDeque<>();
117 
118     /**
119      * In progress call sessions. Note that each phone can only have up to 1 in progress call
120      * session (might contains multiple calls). Having a sparse array in case we need to support
121      * DSDA in the future.
122      */
123     private final SparseArray<InProgressCallSession> mInProgressCallSessions = new SparseArray<>();
124 
125     /** The completed call sessions */
126     private final Deque<TelephonyCallSession> mCompletedCallSessions = new ArrayDeque<>();
127 
128     /** The in-progress SMS sessions. When finished, it will be moved into the completed sessions */
129     private final SparseArray<InProgressSmsSession> mInProgressSmsSessions = new SparseArray<>();
130 
131     /** The completed SMS sessions */
132     private final Deque<SmsSession> mCompletedSmsSessions = new ArrayDeque<>();
133 
134     /** Last service state. This is for injecting the base of a new log or a new call/sms session */
135     private final SparseArray<TelephonyServiceState> mLastServiceState = new SparseArray<>();
136 
137     /**
138      * Last ims capabilities. This is for injecting the base of a new log or a new call/sms
139      * session
140      */
141     private final SparseArray<ImsCapabilities> mLastImsCapabilities = new SparseArray<>();
142 
143     /**
144      * Last IMS connection state. This is for injecting the base of a new log or a new call/sms
145      * session
146      */
147     private final SparseArray<ImsConnectionState> mLastImsConnectionState = new SparseArray<>();
148 
149     /**
150      * Last settings state. This is for deduping same settings event logged.
151      */
152     private final SparseArray<TelephonySettings> mLastSettings = new SparseArray<>();
153 
154     /** The start system time of the TelephonyLog in milliseconds*/
155     private long mStartSystemTimeMs;
156 
157     /** The start elapsed time of the TelephonyLog in milliseconds*/
158     private long mStartElapsedTimeMs;
159 
160     /** Indicating if some of the telephony events are dropped in this log */
161     private boolean mTelephonyEventsDropped = false;
162 
TelephonyMetrics()163     public TelephonyMetrics() {
164         reset();
165     }
166 
167     /**
168      * Get the singleton instance of telephony metrics.
169      *
170      * @return The instance
171      */
getInstance()172     public synchronized static TelephonyMetrics getInstance() {
173         if (sInstance == null) {
174             sInstance = new TelephonyMetrics();
175         }
176 
177         return sInstance;
178     }
179 
180     /**
181      * Dump the state of various objects, add calls to other objects as desired.
182      *
183      * @param fd File descriptor
184      * @param pw Print writer
185      * @param args Arguments
186      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)187     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
188         if (args != null && args.length > 0) {
189             switch (args[0]) {
190                 case "--metrics":
191                     printAllMetrics(pw);
192                     break;
193                 case "--metricsproto":
194                     pw.println(convertProtoToBase64String(buildProto()));
195                     reset();
196                     break;
197             }
198         }
199     }
200 
201     /**
202      * Convert the telephony event to string
203      *
204      * @param event The event in integer
205      * @return The event in string
206      */
telephonyEventToString(int event)207     private static String telephonyEventToString(int event) {
208         switch (event) {
209             case TelephonyEvent.Type.UNKNOWN:
210                 return "UNKNOWN";
211             case TelephonyEvent.Type.SETTINGS_CHANGED:
212                 return "SETTINGS_CHANGED";
213             case TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED:
214                 return "RIL_SERVICE_STATE_CHANGED";
215             case TelephonyEvent.Type.IMS_CONNECTION_STATE_CHANGED:
216                 return "IMS_CONNECTION_STATE_CHANGED";
217             case TelephonyEvent.Type.IMS_CAPABILITIES_CHANGED:
218                 return "IMS_CAPABILITIES_CHANGED";
219             case TelephonyEvent.Type.DATA_CALL_SETUP:
220                 return "DATA_CALL_SETUP";
221             case TelephonyEvent.Type.DATA_CALL_SETUP_RESPONSE:
222                 return "DATA_CALL_SETUP_RESPONSE";
223             case TelephonyEvent.Type.DATA_CALL_LIST_CHANGED:
224                 return "DATA_CALL_LIST_CHANGED";
225             case TelephonyEvent.Type.DATA_CALL_DEACTIVATE:
226                 return "DATA_CALL_DEACTIVATE";
227             case TelephonyEvent.Type.DATA_CALL_DEACTIVATE_RESPONSE:
228                 return "DATA_CALL_DEACTIVATE_RESPONSE";
229             case TelephonyEvent.Type.DATA_STALL_ACTION:
230                 return "DATA_STALL_ACTION";
231             case TelephonyEvent.Type.MODEM_RESTART:
232                 return "MODEM_RESTART";
233             default:
234                 return Integer.toString(event);
235         }
236     }
237 
238     /**
239      * Convert the call session event into string
240      *
241      * @param event The event in integer
242      * @return The event in String
243      */
callSessionEventToString(int event)244     private static String callSessionEventToString(int event) {
245         switch (event) {
246             case TelephonyCallSession.Event.Type.EVENT_UNKNOWN:
247                 return "EVENT_UNKNOWN";
248             case TelephonyCallSession.Event.Type.SETTINGS_CHANGED:
249                 return "SETTINGS_CHANGED";
250             case TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED:
251                 return "RIL_SERVICE_STATE_CHANGED";
252             case TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED:
253                 return "IMS_CONNECTION_STATE_CHANGED";
254             case TelephonyCallSession.Event.Type.IMS_CAPABILITIES_CHANGED:
255                 return "IMS_CAPABILITIES_CHANGED";
256             case TelephonyCallSession.Event.Type.DATA_CALL_LIST_CHANGED:
257                 return "DATA_CALL_LIST_CHANGED";
258             case TelephonyCallSession.Event.Type.RIL_REQUEST:
259                 return "RIL_REQUEST";
260             case TelephonyCallSession.Event.Type.RIL_RESPONSE:
261                 return "RIL_RESPONSE";
262             case TelephonyCallSession.Event.Type.RIL_CALL_RING:
263                 return "RIL_CALL_RING";
264             case TelephonyCallSession.Event.Type.RIL_CALL_SRVCC:
265                 return "RIL_CALL_SRVCC";
266             case TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED:
267                 return "RIL_CALL_LIST_CHANGED";
268             case TelephonyCallSession.Event.Type.IMS_COMMAND:
269                 return "IMS_COMMAND";
270             case TelephonyCallSession.Event.Type.IMS_COMMAND_RECEIVED:
271                 return "IMS_COMMAND_RECEIVED";
272             case TelephonyCallSession.Event.Type.IMS_COMMAND_FAILED:
273                 return "IMS_COMMAND_FAILED";
274             case TelephonyCallSession.Event.Type.IMS_COMMAND_COMPLETE:
275                 return "IMS_COMMAND_COMPLETE";
276             case TelephonyCallSession.Event.Type.IMS_CALL_RECEIVE:
277                 return "IMS_CALL_RECEIVE";
278             case TelephonyCallSession.Event.Type.IMS_CALL_STATE_CHANGED:
279                 return "IMS_CALL_STATE_CHANGED";
280             case TelephonyCallSession.Event.Type.IMS_CALL_TERMINATED:
281                 return "IMS_CALL_TERMINATED";
282             case TelephonyCallSession.Event.Type.IMS_CALL_HANDOVER:
283                 return "IMS_CALL_HANDOVER";
284             case TelephonyCallSession.Event.Type.IMS_CALL_HANDOVER_FAILED:
285                 return "IMS_CALL_HANDOVER_FAILED";
286             case TelephonyCallSession.Event.Type.PHONE_STATE_CHANGED:
287                 return "PHONE_STATE_CHANGED";
288             case TelephonyCallSession.Event.Type.NITZ_TIME:
289                 return "NITZ_TIME";
290             default:
291                 return Integer.toString(event);
292         }
293     }
294 
295     /**
296      * Convert the SMS session event into string
297      * @param event The event in integer
298      * @return The event in String
299      */
smsSessionEventToString(int event)300     private static String smsSessionEventToString(int event) {
301         switch (event) {
302             case SmsSession.Event.Type.EVENT_UNKNOWN:
303                 return "EVENT_UNKNOWN";
304             case SmsSession.Event.Type.SETTINGS_CHANGED:
305                 return "SETTINGS_CHANGED";
306             case SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED:
307                 return "RIL_SERVICE_STATE_CHANGED";
308             case SmsSession.Event.Type.IMS_CONNECTION_STATE_CHANGED:
309                 return "IMS_CONNECTION_STATE_CHANGED";
310             case SmsSession.Event.Type.IMS_CAPABILITIES_CHANGED:
311                 return "IMS_CAPABILITIES_CHANGED";
312             case SmsSession.Event.Type.DATA_CALL_LIST_CHANGED:
313                 return "DATA_CALL_LIST_CHANGED";
314             case SmsSession.Event.Type.SMS_SEND:
315                 return "SMS_SEND";
316             case SmsSession.Event.Type.SMS_SEND_RESULT:
317                 return "SMS_SEND_RESULT";
318             case SmsSession.Event.Type.SMS_RECEIVED:
319                 return "SMS_RECEIVED";
320             default:
321                 return Integer.toString(event);
322         }
323     }
324 
325     /**
326      * Print all metrics data for debugging purposes
327      *
328      * @param rawWriter Print writer
329      */
printAllMetrics(PrintWriter rawWriter)330     private synchronized void printAllMetrics(PrintWriter rawWriter) {
331         final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, "  ");
332 
333         pw.println("Telephony metrics proto:");
334         pw.println("------------------------------------------");
335         pw.println("Telephony events:");
336         pw.increaseIndent();
337         for (TelephonyEvent event : mTelephonyEvents) {
338             pw.print(event.timestampMillis);
339             pw.print(" [");
340             pw.print(event.phoneId);
341             pw.print("] ");
342 
343             pw.print("T=");
344             if (event.type == TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED) {
345                 pw.print(telephonyEventToString(event.type)
346                         + "(" + event.serviceState.dataRat + ")");
347             } else {
348                 pw.print(telephonyEventToString(event.type));
349             }
350 
351             pw.println("");
352         }
353 
354         pw.decreaseIndent();
355         pw.println("Call sessions:");
356         pw.increaseIndent();
357 
358         for (TelephonyCallSession callSession : mCompletedCallSessions) {
359             pw.println("Start time in minutes: " + callSession.startTimeMinutes);
360             pw.println("Events dropped: " + callSession.eventsDropped);
361 
362             pw.println("Events: ");
363             pw.increaseIndent();
364             for (TelephonyCallSession.Event event : callSession.events) {
365                 pw.print(event.delay);
366                 pw.print(" T=");
367                 if (event.type == TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED) {
368                     pw.println(callSessionEventToString(event.type)
369                             + "(" + event.serviceState.dataRat + ")");
370                 } else if (event.type == TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED) {
371                     pw.println(callSessionEventToString(event.type));
372                     pw.increaseIndent();
373                     for (RilCall call : event.calls) {
374                         pw.println(call.index + ". Type = " + call.type + " State = "
375                                 + call.state + " End Reason " + call.callEndReason
376                                 + " isMultiparty = " + call.isMultiparty);
377                     }
378                     pw.decreaseIndent();
379                 } else {
380                     pw.println(callSessionEventToString(event.type));
381                 }
382             }
383             pw.decreaseIndent();
384         }
385 
386         pw.decreaseIndent();
387         pw.println("Sms sessions:");
388         pw.increaseIndent();
389 
390         int count = 0;
391         for (SmsSession smsSession : mCompletedSmsSessions) {
392             count++;
393             pw.print("[" + count + "] Start time in minutes: "
394                     + smsSession.startTimeMinutes);
395 
396             if (smsSession.eventsDropped) {
397                 pw.println(", events dropped: " + smsSession.eventsDropped);
398             }
399             pw.println("Events: ");
400             pw.increaseIndent();
401             for (SmsSession.Event event : smsSession.events) {
402                 pw.print(event.delay);
403                 pw.print(" T=");
404                 pw.println(smsSessionEventToString(event.type));
405             }
406             pw.decreaseIndent();
407         }
408 
409         pw.decreaseIndent();
410     }
411 
412     /**
413      * Convert the telephony proto into Base-64 encoded string
414      *
415      * @param proto Telephony proto
416      * @return Encoded string
417      */
convertProtoToBase64String(TelephonyLog proto)418     private static String convertProtoToBase64String(TelephonyLog proto) {
419         return Base64.encodeToString(
420                 TelephonyProto.TelephonyLog.toByteArray(proto), Base64.DEFAULT);
421     }
422 
423     /**
424      * Reset all events and sessions
425      */
reset()426     private synchronized void reset() {
427         mTelephonyEvents.clear();
428         mCompletedCallSessions.clear();
429         mCompletedSmsSessions.clear();
430 
431         mTelephonyEventsDropped = false;
432 
433         mStartSystemTimeMs = System.currentTimeMillis();
434         mStartElapsedTimeMs = SystemClock.elapsedRealtime();
435 
436         // Insert the last known service state, ims capabilities, and ims connection states as the
437         // base.
438         for (int i = 0; i < mLastServiceState.size(); i++) {
439             final int key = mLastServiceState.keyAt(i);
440 
441             TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
442                     .setServiceState(mLastServiceState.get(key)).build();
443             addTelephonyEvent(event);
444         }
445 
446         for (int i = 0; i < mLastImsCapabilities.size(); i++) {
447             final int key = mLastImsCapabilities.keyAt(i);
448 
449             TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
450                     .setImsCapabilities(mLastImsCapabilities.get(key)).build();
451             addTelephonyEvent(event);
452         }
453 
454         for (int i = 0; i < mLastImsConnectionState.size(); i++) {
455             final int key = mLastImsConnectionState.keyAt(i);
456 
457             TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
458                     .setImsConnectionState(mLastImsConnectionState.get(key)).build();
459             addTelephonyEvent(event);
460         }
461     }
462 
463     /**
464      * Build the telephony proto
465      *
466      * @return Telephony proto
467      */
buildProto()468     private synchronized TelephonyLog buildProto() {
469 
470         TelephonyLog log = new TelephonyLog();
471         // Build telephony events
472         log.events = new TelephonyEvent[mTelephonyEvents.size()];
473         mTelephonyEvents.toArray(log.events);
474         log.eventsDropped = mTelephonyEventsDropped;
475 
476         // Build call sessions
477         log.callSessions = new TelephonyCallSession[mCompletedCallSessions.size()];
478         mCompletedCallSessions.toArray(log.callSessions);
479 
480         // Build SMS sessions
481         log.smsSessions = new SmsSession[mCompletedSmsSessions.size()];
482         mCompletedSmsSessions.toArray(log.smsSessions);
483 
484         // Build histogram. Currently we only support RIL histograms.
485         List<TelephonyHistogram> rilHistograms = RIL.getTelephonyRILTimingHistograms();
486         log.histograms = new TelephonyProto.TelephonyHistogram[rilHistograms.size()];
487         for (int i = 0; i < rilHistograms.size(); i++) {
488             log.histograms[i] = new TelephonyProto.TelephonyHistogram();
489             TelephonyHistogram rilHistogram = rilHistograms.get(i);
490             TelephonyProto.TelephonyHistogram histogramProto = log.histograms[i];
491 
492             histogramProto.category = rilHistogram.getCategory();
493             histogramProto.id = rilHistogram.getId();
494             histogramProto.minTimeMillis = rilHistogram.getMinTime();
495             histogramProto.maxTimeMillis = rilHistogram.getMaxTime();
496             histogramProto.avgTimeMillis = rilHistogram.getAverageTime();
497             histogramProto.count = rilHistogram.getSampleCount();
498             histogramProto.bucketCount = rilHistogram.getBucketCount();
499             histogramProto.bucketEndPoints = rilHistogram.getBucketEndPoints();
500             histogramProto.bucketCounters = rilHistogram.getBucketCounters();
501         }
502 
503         // Log the starting system time
504         log.startTime = new TelephonyProto.Time();
505         log.startTime.systemTimestampMillis = mStartSystemTimeMs;
506         log.startTime.elapsedTimestampMillis = mStartElapsedTimeMs;
507 
508         log.endTime = new TelephonyProto.Time();
509         log.endTime.systemTimestampMillis = System.currentTimeMillis();
510         log.endTime.elapsedTimestampMillis = SystemClock.elapsedRealtime();
511 
512         return log;
513     }
514 
515     /**
516      * Reduce precision to meet privacy requirements.
517      *
518      * @param timestamp timestamp in milliseconds
519      * @return Precision reduced timestamp in minutes
520      */
roundSessionStart(long timestamp)521     static int roundSessionStart(long timestamp) {
522         return (int) ((timestamp) / (MINUTE_IN_MILLIS * SESSION_START_PRECISION_MINUTES)
523                 * (SESSION_START_PRECISION_MINUTES));
524     }
525 
526     /**
527      * Get the time interval with reduced prevision
528      *
529      * @param previousTimestamp Previous timestamp in milliseconds
530      * @param currentTimestamp Current timestamp in milliseconds
531      * @return The time interval
532      */
toPrivacyFuzzedTimeInterval(long previousTimestamp, long currentTimestamp)533     static int toPrivacyFuzzedTimeInterval(long previousTimestamp, long currentTimestamp) {
534         long diff = currentTimestamp - previousTimestamp;
535         if (diff < 0) {
536             return TimeInterval.TI_UNKNOWN;
537         } else if (diff <= 10) {
538             return TimeInterval.TI_10_MILLIS;
539         } else if (diff <= 20) {
540             return TimeInterval.TI_20_MILLIS;
541         } else if (diff <= 50) {
542             return TimeInterval.TI_50_MILLIS;
543         } else if (diff <= 100) {
544             return TimeInterval.TI_100_MILLIS;
545         } else if (diff <= 200) {
546             return TimeInterval.TI_200_MILLIS;
547         } else if (diff <= 500) {
548             return TimeInterval.TI_500_MILLIS;
549         } else if (diff <= 1000) {
550             return TimeInterval.TI_1_SEC;
551         } else if (diff <= 2000) {
552             return TimeInterval.TI_2_SEC;
553         } else if (diff <= 5000) {
554             return TimeInterval.TI_5_SEC;
555         } else if (diff <= 10000) {
556             return TimeInterval.TI_10_SEC;
557         } else if (diff <= 30000) {
558             return TimeInterval.TI_30_SEC;
559         } else if (diff <= 60000) {
560             return TimeInterval.TI_1_MINUTE;
561         } else if (diff <= 180000) {
562             return TimeInterval.TI_3_MINUTES;
563         } else if (diff <= 600000) {
564             return TimeInterval.TI_10_MINUTES;
565         } else if (diff <= 1800000) {
566             return TimeInterval.TI_30_MINUTES;
567         } else if (diff <= 3600000) {
568             return TimeInterval.TI_1_HOUR;
569         } else if (diff <= 7200000) {
570             return TimeInterval.TI_2_HOURS;
571         } else if (diff <= 14400000) {
572             return TimeInterval.TI_4_HOURS;
573         } else {
574             return TimeInterval.TI_MANY_HOURS;
575         }
576     }
577 
578     /**
579      * Convert the service state into service state proto
580      *
581      * @param serviceState Service state
582      * @return Service state proto
583      */
toServiceStateProto(ServiceState serviceState)584     private TelephonyServiceState toServiceStateProto(ServiceState serviceState) {
585         TelephonyServiceState ssProto = new TelephonyServiceState();
586 
587         ssProto.voiceRoamingType = serviceState.getVoiceRoamingType();
588         ssProto.dataRoamingType = serviceState.getDataRoamingType();
589 
590         ssProto.voiceOperator = new TelephonyServiceState.TelephonyOperator();
591 
592         if (serviceState.getVoiceOperatorAlphaLong() != null) {
593             ssProto.voiceOperator.alphaLong = serviceState.getVoiceOperatorAlphaLong();
594         }
595 
596         if (serviceState.getVoiceOperatorAlphaShort() != null) {
597             ssProto.voiceOperator.alphaShort = serviceState.getVoiceOperatorAlphaShort();
598         }
599 
600         if (serviceState.getVoiceOperatorNumeric() != null) {
601             ssProto.voiceOperator.numeric = serviceState.getVoiceOperatorNumeric();
602         }
603 
604         ssProto.dataOperator = new TelephonyServiceState.TelephonyOperator();
605 
606         if (serviceState.getDataOperatorAlphaLong() != null) {
607             ssProto.dataOperator.alphaLong = serviceState.getDataOperatorAlphaLong();
608         }
609 
610         if (serviceState.getDataOperatorAlphaShort() != null) {
611             ssProto.dataOperator.alphaShort = serviceState.getDataOperatorAlphaShort();
612         }
613 
614         if (serviceState.getDataOperatorNumeric() != null) {
615             ssProto.dataOperator.numeric = serviceState.getDataOperatorNumeric();
616         }
617 
618         ssProto.voiceRat = serviceState.getRilVoiceRadioTechnology();
619         ssProto.dataRat = serviceState.getRilDataRadioTechnology();
620         return ssProto;
621     }
622 
623     /**
624      * Annotate the call session with events
625      *
626      * @param timestamp Event timestamp
627      * @param phoneId Phone id
628      * @param eventBuilder Call session event builder
629      */
annotateInProgressCallSession(long timestamp, int phoneId, CallSessionEventBuilder eventBuilder)630     private synchronized void annotateInProgressCallSession(long timestamp, int phoneId,
631                                                             CallSessionEventBuilder eventBuilder) {
632         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
633         if (callSession != null) {
634             callSession.addEvent(timestamp, eventBuilder);
635         }
636     }
637 
638     /**
639      * Annotate the SMS session with events
640      *
641      * @param timestamp Event timestamp
642      * @param phoneId Phone id
643      * @param eventBuilder SMS session event builder
644      */
annotateInProgressSmsSession(long timestamp, int phoneId, SmsSessionEventBuilder eventBuilder)645     private synchronized void annotateInProgressSmsSession(long timestamp, int phoneId,
646                                                            SmsSessionEventBuilder eventBuilder) {
647         InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId);
648         if (smsSession != null) {
649             smsSession.addEvent(timestamp, eventBuilder);
650         }
651     }
652 
653     /**
654      * Create the call session if there isn't any existing one
655      *
656      * @param phoneId Phone id
657      * @return The call session
658      */
startNewCallSessionIfNeeded(int phoneId)659     private synchronized InProgressCallSession startNewCallSessionIfNeeded(int phoneId) {
660         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
661         if (callSession == null) {
662             if (VDBG) Rlog.v(TAG, "Starting a new call session on phone " + phoneId);
663             callSession = new InProgressCallSession(phoneId);
664             mInProgressCallSessions.append(phoneId, callSession);
665 
666             // Insert the latest service state, ims capabilities, and ims connection states as the
667             // base.
668             TelephonyServiceState serviceState = mLastServiceState.get(phoneId);
669             if (serviceState != null) {
670                 callSession.addEvent(callSession.startElapsedTimeMs, new CallSessionEventBuilder(
671                         TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
672                         .setServiceState(serviceState));
673             }
674 
675             ImsCapabilities imsCapabilities = mLastImsCapabilities.get(phoneId);
676             if (imsCapabilities != null) {
677                 callSession.addEvent(callSession.startElapsedTimeMs, new CallSessionEventBuilder(
678                         TelephonyCallSession.Event.Type.IMS_CAPABILITIES_CHANGED)
679                         .setImsCapabilities(imsCapabilities));
680             }
681 
682             ImsConnectionState imsConnectionState = mLastImsConnectionState.get(phoneId);
683             if (imsConnectionState != null) {
684                 callSession.addEvent(callSession.startElapsedTimeMs, new CallSessionEventBuilder(
685                         TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED)
686                         .setImsConnectionState(imsConnectionState));
687             }
688         }
689         return callSession;
690     }
691 
692     /**
693      * Create the SMS session if there isn't any existing one
694      *
695      * @param phoneId Phone id
696      * @return The SMS session
697      */
startNewSmsSessionIfNeeded(int phoneId)698     private synchronized InProgressSmsSession startNewSmsSessionIfNeeded(int phoneId) {
699         InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId);
700         if (smsSession == null) {
701             if (VDBG) Rlog.v(TAG, "Starting a new sms session on phone " + phoneId);
702             smsSession = new InProgressSmsSession(phoneId);
703             mInProgressSmsSessions.append(phoneId, smsSession);
704 
705             // Insert the latest service state, ims capabilities, and ims connection state as the
706             // base.
707             TelephonyServiceState serviceState = mLastServiceState.get(phoneId);
708             if (serviceState != null) {
709                 smsSession.addEvent(smsSession.startElapsedTimeMs, new SmsSessionEventBuilder(
710                         TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
711                         .setServiceState(serviceState));
712             }
713 
714             ImsCapabilities imsCapabilities = mLastImsCapabilities.get(phoneId);
715             if (imsCapabilities != null) {
716                 smsSession.addEvent(smsSession.startElapsedTimeMs, new SmsSessionEventBuilder(
717                         SmsSession.Event.Type.IMS_CAPABILITIES_CHANGED)
718                         .setImsCapabilities(imsCapabilities));
719             }
720 
721             ImsConnectionState imsConnectionState = mLastImsConnectionState.get(phoneId);
722             if (imsConnectionState != null) {
723                 smsSession.addEvent(smsSession.startElapsedTimeMs, new SmsSessionEventBuilder(
724                         SmsSession.Event.Type.IMS_CONNECTION_STATE_CHANGED)
725                         .setImsConnectionState(imsConnectionState));
726             }
727         }
728         return smsSession;
729     }
730 
731     /**
732      * Finish the call session and move it into the completed session
733      *
734      * @param inProgressCallSession The in progress call session
735      */
finishCallSession(InProgressCallSession inProgressCallSession)736     private synchronized void finishCallSession(InProgressCallSession inProgressCallSession) {
737         TelephonyCallSession callSession = new TelephonyCallSession();
738         callSession.events = new TelephonyCallSession.Event[inProgressCallSession.events.size()];
739         inProgressCallSession.events.toArray(callSession.events);
740         callSession.startTimeMinutes = inProgressCallSession.startSystemTimeMin;
741         callSession.phoneId = inProgressCallSession.phoneId;
742         callSession.eventsDropped = inProgressCallSession.isEventsDropped();
743         if (mCompletedCallSessions.size() >= MAX_COMPLETED_CALL_SESSIONS) {
744             mCompletedCallSessions.removeFirst();
745         }
746         mCompletedCallSessions.add(callSession);
747         mInProgressCallSessions.remove(inProgressCallSession.phoneId);
748         if (VDBG) Rlog.v(TAG, "Call session finished");
749     }
750 
751     /**
752      * Finish the SMS session and move it into the completed session
753      *
754      * @param inProgressSmsSession The in progress SMS session
755      */
finishSmsSessionIfNeeded(InProgressSmsSession inProgressSmsSession)756     private synchronized void finishSmsSessionIfNeeded(InProgressSmsSession inProgressSmsSession) {
757         if (inProgressSmsSession.getNumExpectedResponses() == 0) {
758             SmsSession smsSession = new SmsSession();
759             smsSession.events = new SmsSession.Event[inProgressSmsSession.events.size()];
760             inProgressSmsSession.events.toArray(smsSession.events);
761             smsSession.startTimeMinutes = inProgressSmsSession.startSystemTimeMin;
762             smsSession.phoneId = inProgressSmsSession.phoneId;
763             smsSession.eventsDropped = inProgressSmsSession.isEventsDropped();
764             if (mCompletedSmsSessions.size() >= MAX_COMPLETED_SMS_SESSIONS) {
765                 mCompletedSmsSessions.removeFirst();
766             }
767             mCompletedSmsSessions.add(smsSession);
768             mInProgressSmsSessions.remove(inProgressSmsSession.phoneId);
769             if (VDBG) Rlog.v(TAG, "SMS session finished");
770         }
771     }
772 
773     /**
774      * Add telephony event into the queue
775      *
776      * @param event Telephony event
777      */
addTelephonyEvent(TelephonyEvent event)778     private synchronized void addTelephonyEvent(TelephonyEvent event) {
779         if (mTelephonyEvents.size() >= MAX_TELEPHONY_EVENTS) {
780             mTelephonyEvents.removeFirst();
781             mTelephonyEventsDropped = true;
782         }
783         mTelephonyEvents.add(event);
784     }
785 
786     /**
787      * Write service changed event
788      *
789      * @param phoneId Phone id
790      * @param serviceState Service state
791      */
writeServiceStateChanged(int phoneId, ServiceState serviceState)792     public synchronized void writeServiceStateChanged(int phoneId, ServiceState serviceState) {
793 
794         TelephonyEvent event = new TelephonyEventBuilder(phoneId)
795                 .setServiceState(toServiceStateProto(serviceState)).build();
796 
797         // If service state doesn't change, we don't log the event.
798         if (mLastServiceState.get(phoneId) != null &&
799                 Arrays.equals(TelephonyServiceState.toByteArray(mLastServiceState.get(phoneId)),
800                         TelephonyServiceState.toByteArray(event.serviceState))) {
801             return;
802         }
803 
804         mLastServiceState.put(phoneId, event.serviceState);
805         addTelephonyEvent(event);
806 
807         annotateInProgressCallSession(event.timestampMillis, phoneId,
808                 new CallSessionEventBuilder(
809                         TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
810                         .setServiceState(event.serviceState));
811         annotateInProgressSmsSession(event.timestampMillis, phoneId,
812                 new SmsSessionEventBuilder(
813                         SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
814                         .setServiceState(event.serviceState));
815     }
816 
817     /**
818      * Write data stall event
819      *
820      * @param phoneId Phone id
821      * @param recoveryAction Data stall recovery action
822      */
writeDataStallEvent(int phoneId, int recoveryAction)823     public void writeDataStallEvent(int phoneId, int recoveryAction) {
824         addTelephonyEvent(new TelephonyEventBuilder(phoneId)
825                 .setDataStallRecoveryAction(recoveryAction).build());
826     }
827 
828     /**
829      * Write IMS feature settings changed event
830      *
831      * @param phoneId Phone id
832      * @param feature IMS feature
833      * @param network The IMS network type
834      * @param value The settings. 0 indicates disabled, otherwise enabled.
835      * @param status IMS operation status. See OperationStatusConstants for details.
836      */
writeImsSetFeatureValue(int phoneId, int feature, int network, int value, int status)837     public void writeImsSetFeatureValue(int phoneId, int feature, int network, int value,
838                                         int status) {
839         TelephonySettings s = new TelephonySettings();
840         switch (feature) {
841             case ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE:
842                 s.isEnhanced4GLteModeEnabled = (value != 0);
843                 break;
844             case ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI:
845                 s.isWifiCallingEnabled = (value != 0);
846                 break;
847             case ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE:
848                 s.isVtOverLteEnabled = (value != 0);
849                 break;
850             case ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_WIFI:
851                 s.isVtOverWifiEnabled = (value != 0);
852                 break;
853         }
854 
855         // If the settings don't change, we don't log the event.
856         if (mLastSettings.get(phoneId) != null &&
857                 Arrays.equals(TelephonySettings.toByteArray(mLastSettings.get(phoneId)),
858                         TelephonySettings.toByteArray(s))) {
859             return;
860         }
861 
862         mLastSettings.put(phoneId, s);
863 
864         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setSettings(s).build();
865         addTelephonyEvent(event);
866 
867         annotateInProgressCallSession(event.timestampMillis, phoneId,
868                 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.SETTINGS_CHANGED)
869                         .setSettings(s));
870         annotateInProgressSmsSession(event.timestampMillis, phoneId,
871                 new SmsSessionEventBuilder(SmsSession.Event.Type.SETTINGS_CHANGED)
872                         .setSettings(s));
873     }
874 
875     /**
876      * Write the preferred network settings changed event
877      *
878      * @param phoneId Phone id
879      * @param networkType The preferred network
880      */
writeSetPreferredNetworkType(int phoneId, int networkType)881     public void writeSetPreferredNetworkType(int phoneId, int networkType) {
882         TelephonySettings s = new TelephonySettings();
883         s.preferredNetworkMode = networkType + 1;
884 
885         // If the settings don't change, we don't log the event.
886         if (mLastSettings.get(phoneId) != null &&
887                 Arrays.equals(TelephonySettings.toByteArray(mLastSettings.get(phoneId)),
888                         TelephonySettings.toByteArray(s))) {
889             return;
890         }
891 
892         mLastSettings.put(phoneId, s);
893 
894         addTelephonyEvent(new TelephonyEventBuilder(phoneId).setSettings(s).build());
895     }
896 
897     /**
898      * Write the IMS connection state changed event
899      *
900      * @param phoneId Phone id
901      * @param state IMS connection state
902      * @param reasonInfo The reason info. Only used for disconnected state.
903      */
writeOnImsConnectionState(int phoneId, int state, ImsReasonInfo reasonInfo)904     public synchronized void writeOnImsConnectionState(int phoneId, int state,
905                                                        ImsReasonInfo reasonInfo) {
906         ImsConnectionState imsState = new ImsConnectionState();
907         imsState.state = state;
908 
909         if (reasonInfo != null) {
910             TelephonyProto.ImsReasonInfo ri = new TelephonyProto.ImsReasonInfo();
911 
912             ri.reasonCode = reasonInfo.getCode();
913             ri.extraCode = reasonInfo.getExtraCode();
914             String extraMessage = reasonInfo.getExtraMessage();
915             if (extraMessage != null) {
916                 ri.extraMessage = extraMessage;
917             }
918 
919             imsState.reasonInfo = ri;
920         }
921 
922         // If the connection state does not change, do not log it.
923         if (mLastImsConnectionState.get(phoneId) != null &&
924                 Arrays.equals(ImsConnectionState.toByteArray(mLastImsConnectionState.get(phoneId)),
925                         ImsConnectionState.toByteArray(imsState))) {
926             return;
927         }
928 
929         mLastImsConnectionState.put(phoneId, imsState);
930 
931         TelephonyEvent event = new TelephonyEventBuilder(phoneId)
932                 .setImsConnectionState(imsState).build();
933         addTelephonyEvent(event);
934 
935         annotateInProgressCallSession(event.timestampMillis, phoneId,
936                 new CallSessionEventBuilder(
937                         TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED)
938                         .setImsConnectionState(event.imsConnectionState));
939         annotateInProgressSmsSession(event.timestampMillis, phoneId,
940                 new SmsSessionEventBuilder(
941                         SmsSession.Event.Type.IMS_CONNECTION_STATE_CHANGED)
942                         .setImsConnectionState(event.imsConnectionState));
943     }
944 
945     /**
946      * Write the IMS capabilities changed event
947      *
948      * @param phoneId Phone id
949      * @param capabilities IMS capabilities array
950      */
writeOnImsCapabilities(int phoneId, boolean[] capabilities)951     public synchronized void writeOnImsCapabilities(int phoneId, boolean[] capabilities) {
952         ImsCapabilities cap = new ImsCapabilities();
953 
954         cap.voiceOverLte = capabilities[0];
955         cap.videoOverLte = capabilities[1];
956         cap.voiceOverWifi = capabilities[2];
957         cap.videoOverWifi = capabilities[3];
958         cap.utOverLte = capabilities[4];
959         cap.utOverWifi = capabilities[5];
960 
961         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setImsCapabilities(cap).build();
962 
963         // If the capabilities don't change, we don't log the event.
964         if (mLastImsCapabilities.get(phoneId) != null &&
965                 Arrays.equals(ImsCapabilities.toByteArray(mLastImsCapabilities.get(phoneId)),
966                 ImsCapabilities.toByteArray(cap))) {
967             return;
968         }
969 
970         mLastImsCapabilities.put(phoneId, cap);
971         addTelephonyEvent(event);
972 
973         annotateInProgressCallSession(event.timestampMillis, phoneId,
974                 new CallSessionEventBuilder(
975                         TelephonyCallSession.Event.Type.IMS_CAPABILITIES_CHANGED)
976                         .setImsCapabilities(event.imsCapabilities));
977         annotateInProgressSmsSession(event.timestampMillis, phoneId,
978                 new SmsSessionEventBuilder(
979                         SmsSession.Event.Type.IMS_CAPABILITIES_CHANGED)
980                         .setImsCapabilities(event.imsCapabilities));
981     }
982 
983     /**
984      * Convert PDP type into the enumeration
985      *
986      * @param type PDP type
987      * @return The proto defined enumeration
988      */
toPdpType(String type)989     private int toPdpType(String type) {
990         switch (type) {
991             case "IP":
992                 return PDP_TYPE_IP;
993             case "IPV6":
994                 return PDP_TYPE_IPV6;
995             case "IPV4V6":
996                 return PDP_TYPE_IPV4V6;
997             case "PPP":
998                 return PDP_TYPE_PPP;
999         }
1000         Rlog.e(TAG, "Unknown type: " + type);
1001         return PDP_UNKNOWN;
1002     }
1003 
1004     /**
1005      * Write setup data call event
1006      *
1007      * @param phoneId Phone id
1008      * @param rilSerial RIL request serial number
1009      * @param radioTechnology The data call RAT
1010      * @param profile Data profile
1011      * @param apn APN in string
1012      * @param authType Authentication type
1013      * @param protocol Data connection protocol
1014      */
writeRilSetupDataCall(int phoneId, int rilSerial, int radioTechnology, int profile, String apn, int authType, String protocol)1015     public void writeRilSetupDataCall(int phoneId, int rilSerial, int radioTechnology, int profile,
1016                                       String apn, int authType, String protocol) {
1017 
1018         RilSetupDataCall setupDataCall = new RilSetupDataCall();
1019         setupDataCall.rat = radioTechnology;
1020         setupDataCall.dataProfile = profile + 1;  // off by 1 between proto and RIL constants.
1021         if (apn != null) {
1022             setupDataCall.apn = apn;
1023         }
1024         if (protocol != null) {
1025             setupDataCall.type = toPdpType(protocol);
1026         }
1027 
1028         addTelephonyEvent(new TelephonyEventBuilder(phoneId).setSetupDataCall(
1029                 setupDataCall).build());
1030     }
1031 
1032     /**
1033      * Write data call deactivate event
1034      *
1035      * @param phoneId Phone id
1036      * @param rilSerial RIL request serial number
1037      * @param cid call id
1038      * @param reason Deactivate reason
1039      */
writeRilDeactivateDataCall(int phoneId, int rilSerial, int cid, int reason)1040     public void writeRilDeactivateDataCall(int phoneId, int rilSerial, int cid, int reason) {
1041 
1042         RilDeactivateDataCall deactivateDataCall = new RilDeactivateDataCall();
1043         deactivateDataCall.cid = cid;
1044         deactivateDataCall.reason = reason + 1;
1045 
1046         addTelephonyEvent(new TelephonyEventBuilder(phoneId).setDeactivateDataCall(
1047                 deactivateDataCall).build());
1048     }
1049 
1050     /**
1051      * Write get data call list event
1052      *
1053      * @param phoneId Phone id
1054      * @param dcsList Data call list
1055      */
writeRilDataCallList(int phoneId, ArrayList<DataCallResponse> dcsList)1056     public void writeRilDataCallList(int phoneId, ArrayList<DataCallResponse> dcsList) {
1057 
1058         RilDataCall[] dataCalls = new RilDataCall[dcsList.size()];
1059 
1060         for (int i = 0; i < dcsList.size(); i++) {
1061             dataCalls[i] = new RilDataCall();
1062             dataCalls[i].cid = dcsList.get(i).cid;
1063             if (!TextUtils.isEmpty(dcsList.get(i).ifname)) {
1064                 dataCalls[i].iframe = dcsList.get(i).ifname;
1065             }
1066             if (!TextUtils.isEmpty(dcsList.get(i).type)) {
1067                 dataCalls[i].type = toPdpType(dcsList.get(i).type);
1068             }
1069         }
1070 
1071         addTelephonyEvent(new TelephonyEventBuilder(phoneId).setDataCalls(dataCalls).build());
1072     }
1073 
1074     /**
1075      * Write CS call list event
1076      *
1077      * @param phoneId    Phone id
1078      * @param connections Array of GsmCdmaConnection objects
1079      */
writeRilCallList(int phoneId, ArrayList<GsmCdmaConnection> connections)1080     public void writeRilCallList(int phoneId, ArrayList<GsmCdmaConnection> connections) {
1081         if (VDBG) {
1082             Rlog.v(TAG, "Logging CallList Changed Connections Size = " + connections.size());
1083         }
1084         InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
1085         if (callSession == null) {
1086             Rlog.e(TAG, "writeRilCallList: Call session is missing");
1087         } else {
1088             RilCall[] calls = convertConnectionsToRilCalls(connections);
1089             callSession.addEvent(
1090                     new CallSessionEventBuilder(
1091                             TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED)
1092                             .setRilCalls(calls)
1093             );
1094             if (VDBG) Rlog.v(TAG, "Logged Call list changed");
1095             if (callSession.isPhoneIdle() && disconnectReasonsKnown(calls)) {
1096                 finishCallSession(callSession);
1097             }
1098         }
1099     }
1100 
disconnectReasonsKnown(RilCall[] calls)1101     private boolean disconnectReasonsKnown(RilCall[] calls) {
1102         for (RilCall call : calls) {
1103             if (call.callEndReason == 0) return false;
1104         }
1105         return true;
1106     }
1107 
convertConnectionsToRilCalls(ArrayList<GsmCdmaConnection> mConnections)1108     private RilCall[] convertConnectionsToRilCalls(ArrayList<GsmCdmaConnection> mConnections) {
1109         RilCall[] calls = new RilCall[mConnections.size()];
1110         for (int i = 0; i < mConnections.size(); i++) {
1111             calls[i] = new RilCall();
1112             calls[i].index = i;
1113             convertConnectionToRilCall(mConnections.get(i), calls[i]);
1114         }
1115         return calls;
1116     }
1117 
convertConnectionToRilCall(GsmCdmaConnection conn, RilCall call)1118     private void convertConnectionToRilCall(GsmCdmaConnection conn, RilCall call) {
1119         if (conn.isIncoming()) {
1120             call.type = Type.MT;
1121         } else {
1122             call.type = Type.MO;
1123         }
1124         switch (conn.getState()) {
1125             case IDLE:
1126                 call.state = CallState.CALL_IDLE;
1127                 break;
1128             case ACTIVE:
1129                 call.state = CallState.CALL_ACTIVE;
1130                 break;
1131             case HOLDING:
1132                 call.state = CallState.CALL_HOLDING;
1133                 break;
1134             case DIALING:
1135                 call.state = CallState.CALL_DIALING;
1136                 break;
1137             case ALERTING:
1138                 call.state = CallState.CALL_ALERTING;
1139                 break;
1140             case INCOMING:
1141                 call.state = CallState.CALL_INCOMING;
1142                 break;
1143             case WAITING:
1144                 call.state = CallState.CALL_WAITING;
1145                 break;
1146             case DISCONNECTED:
1147                 call.state = CallState.CALL_DISCONNECTED;
1148                 break;
1149             case DISCONNECTING:
1150                 call.state = CallState.CALL_DISCONNECTING;
1151                 break;
1152             default:
1153                 call.state = CallState.CALL_UNKNOWN;
1154                 break;
1155         }
1156         call.callEndReason = conn.getDisconnectCause();
1157         call.isMultiparty = conn.isMultiparty();
1158     }
1159 
1160     /**
1161      * Write dial event
1162      *
1163      * @param phoneId Phone id
1164      * @param conn Connection object created to track this call
1165      * @param clirMode CLIR (Calling Line Identification Restriction) mode
1166      * @param uusInfo User-to-User signaling Info
1167      */
writeRilDial(int phoneId, GsmCdmaConnection conn, int clirMode, UUSInfo uusInfo)1168     public void writeRilDial(int phoneId, GsmCdmaConnection conn, int clirMode, UUSInfo uusInfo) {
1169 
1170         InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
1171         if (VDBG) Rlog.v(TAG, "Logging Dial Connection = " + conn);
1172         if (callSession == null) {
1173             Rlog.e(TAG, "writeRilDial: Call session is missing");
1174         } else {
1175             RilCall[] calls = new RilCall[1];
1176             calls[0] = new RilCall();
1177             calls[0].index = -1;
1178             convertConnectionToRilCall(conn, calls[0]);
1179             callSession.addEvent(callSession.startElapsedTimeMs,
1180                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST)
1181                             .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL)
1182                             .setRilCalls(calls));
1183             if (VDBG) Rlog.v(TAG, "Logged Dial event");
1184         }
1185     }
1186 
1187     /**
1188      * Write incoming call event
1189      *
1190      * @param phoneId Phone id
1191      * @param response Unused today
1192      */
writeRilCallRing(int phoneId, char[] response)1193     public void writeRilCallRing(int phoneId, char[] response) {
1194         InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
1195 
1196         callSession.addEvent(callSession.startElapsedTimeMs,
1197                 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_CALL_RING));
1198     }
1199 
1200     /**
1201      * Write call hangup event
1202      *
1203      * @param phoneId Phone id
1204      * @param conn Connection object associated with the call that is being hung-up
1205      * @param callId Call id
1206      */
writeRilHangup(int phoneId, GsmCdmaConnection conn, int callId)1207     public void writeRilHangup(int phoneId, GsmCdmaConnection conn, int callId) {
1208         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1209         if (callSession == null) {
1210             Rlog.e(TAG, "writeRilHangup: Call session is missing");
1211         } else {
1212             RilCall[] calls = new RilCall[1];
1213             calls[0] = new RilCall();
1214             calls[0].index = callId;
1215             convertConnectionToRilCall(conn, calls[0]);
1216             callSession.addEvent(
1217                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST)
1218                             .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_HANGUP)
1219                             .setRilCalls(calls));
1220             if (VDBG) Rlog.v(TAG, "Logged Hangup event");
1221         }
1222     }
1223 
1224     /**
1225      * Write call answer event
1226      *
1227      * @param phoneId Phone id
1228      * @param rilSerial RIL request serial number
1229      */
writeRilAnswer(int phoneId, int rilSerial)1230     public void writeRilAnswer(int phoneId, int rilSerial) {
1231         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1232         if (callSession == null) {
1233             Rlog.e(TAG, "writeRilAnswer: Call session is missing");
1234         } else {
1235             callSession.addEvent(
1236                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST)
1237                             .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_ANSWER)
1238                             .setRilRequestId(rilSerial));
1239         }
1240     }
1241 
1242     /**
1243      * Write IMS call SRVCC event
1244      *
1245      * @param phoneId Phone id
1246      * @param rilSrvccState SRVCC state
1247      */
writeRilSrvcc(int phoneId, int rilSrvccState)1248     public void writeRilSrvcc(int phoneId, int rilSrvccState) {
1249         InProgressCallSession callSession =  mInProgressCallSessions.get(phoneId);
1250         if (callSession == null) {
1251             Rlog.e(TAG, "writeRilSrvcc: Call session is missing");
1252         } else {
1253             callSession.addEvent(
1254                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_CALL_SRVCC)
1255                             .setSrvccState(rilSrvccState + 1));
1256         }
1257     }
1258 
1259     /**
1260      * Convert RIL request into proto defined RIL request
1261      *
1262      * @param r RIL request
1263      * @return RIL request defined in call session proto
1264      */
toCallSessionRilRequest(int r)1265     private int toCallSessionRilRequest(int r) {
1266         switch (r) {
1267             case RILConstants.RIL_REQUEST_DIAL:
1268                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL;
1269 
1270             case RILConstants.RIL_REQUEST_ANSWER:
1271                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_ANSWER;
1272 
1273             case RILConstants.RIL_REQUEST_HANGUP:
1274             case RILConstants.RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
1275             case RILConstants.RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
1276                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_HANGUP;
1277 
1278             case RILConstants.RIL_REQUEST_SET_CALL_WAITING:
1279                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_SET_CALL_WAITING;
1280 
1281             case RILConstants.RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
1282                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE;
1283 
1284             case RILConstants.RIL_REQUEST_CDMA_FLASH:
1285                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_CDMA_FLASH;
1286 
1287             case RILConstants.RIL_REQUEST_CONFERENCE:
1288                 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_CONFERENCE;
1289         }
1290         Rlog.e(TAG, "Unknown RIL request: " + r);
1291         return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_UNKNOWN;
1292     }
1293 
1294     /**
1295      * Write setup data call response event
1296      *
1297      * @param phoneId Phone id
1298      * @param rilSerial RIL request serial number
1299      * @param rilError RIL error
1300      * @param rilRequest RIL request
1301      * @param response Data call response
1302      */
writeOnSetupDataCallResponse(int phoneId, int rilSerial, int rilError, int rilRequest, DataCallResponse response)1303     private void writeOnSetupDataCallResponse(int phoneId, int rilSerial, int rilError,
1304                                               int rilRequest, DataCallResponse response) {
1305 
1306         RilSetupDataCallResponse setupDataCallResponse = new RilSetupDataCallResponse();
1307         RilDataCall dataCall = new RilDataCall();
1308 
1309         if (response != null) {
1310             setupDataCallResponse.status =
1311                     (response.status == 0 ? RilDataCallFailCause.PDP_FAIL_NONE : response.status);
1312             setupDataCallResponse.suggestedRetryTimeMillis = response.suggestedRetryTime;
1313 
1314             dataCall.cid = response.cid;
1315             if (!TextUtils.isEmpty(response.type)) {
1316                 dataCall.type = toPdpType(response.type);
1317             }
1318 
1319             if (!TextUtils.isEmpty(response.ifname)) {
1320                 dataCall.iframe = response.ifname;
1321             }
1322         }
1323         setupDataCallResponse.call = dataCall;
1324 
1325         addTelephonyEvent(new TelephonyEventBuilder(phoneId)
1326                 .setSetupDataCallResponse(setupDataCallResponse).build());
1327     }
1328 
1329     /**
1330      * Write call related solicited response event
1331      *
1332      * @param phoneId Phone id
1333      * @param rilSerial RIL request serial number
1334      * @param rilError RIL error
1335      * @param rilRequest RIL request
1336      */
writeOnCallSolicitedResponse(int phoneId, int rilSerial, int rilError, int rilRequest)1337     private void writeOnCallSolicitedResponse(int phoneId, int rilSerial, int rilError,
1338                                               int rilRequest) {
1339         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1340         if (callSession == null) {
1341             Rlog.e(TAG, "writeOnCallSolicitedResponse: Call session is missing");
1342         } else {
1343             callSession.addEvent(new CallSessionEventBuilder(
1344                     TelephonyCallSession.Event.Type.RIL_RESPONSE)
1345                     .setRilRequest(toCallSessionRilRequest(rilRequest))
1346                     .setRilRequestId(rilSerial)
1347                     .setRilError(rilError + 1));
1348         }
1349     }
1350 
1351     /**
1352      * Write SMS related solicited response event
1353      *
1354      * @param phoneId Phone id
1355      * @param rilSerial RIL request serial number
1356      * @param rilError RIL error
1357      * @param response SMS response
1358      */
writeOnSmsSolicitedResponse(int phoneId, int rilSerial, int rilError, SmsResponse response)1359     private synchronized void writeOnSmsSolicitedResponse(int phoneId, int rilSerial, int rilError,
1360                                                           SmsResponse response) {
1361 
1362         InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId);
1363         if (smsSession == null) {
1364             Rlog.e(TAG, "SMS session is missing");
1365         } else {
1366 
1367             int errorCode = 0;
1368             if (response != null) {
1369                 errorCode = response.mErrorCode;
1370             }
1371 
1372             smsSession.addEvent(new SmsSessionEventBuilder(
1373                     SmsSession.Event.Type.SMS_SEND_RESULT)
1374                     .setErrorCode(errorCode)
1375                     .setRilErrno(rilError + 1)
1376                     .setRilRequestId(rilSerial)
1377             );
1378 
1379             smsSession.decreaseExpectedResponse();
1380             finishSmsSessionIfNeeded(smsSession);
1381         }
1382     }
1383 
1384     /**
1385      * Write deactivate data call response event
1386      *
1387      * @param phoneId Phone id
1388      * @param rilError RIL error
1389      */
writeOnDeactivateDataCallResponse(int phoneId, int rilError)1390     private void writeOnDeactivateDataCallResponse(int phoneId, int rilError) {
1391         addTelephonyEvent(new TelephonyEventBuilder(phoneId)
1392                 .setDeactivateDataCallResponse(rilError + 1).build());
1393     }
1394 
1395     /**
1396      * Write RIL solicited response event
1397      *
1398      * @param phoneId Phone id
1399      * @param rilSerial RIL request serial number
1400      * @param rilError RIL error
1401      * @param rilRequest RIL request
1402      * @param ret The returned RIL response
1403      */
writeOnRilSolicitedResponse(int phoneId, int rilSerial, int rilError, int rilRequest, Object ret)1404     public void writeOnRilSolicitedResponse(int phoneId, int rilSerial, int rilError,
1405                                             int rilRequest, Object ret) {
1406         switch (rilRequest) {
1407             case RIL_REQUEST_SETUP_DATA_CALL:
1408                 DataCallResponse dataCall = (DataCallResponse) ret;
1409                 writeOnSetupDataCallResponse(phoneId, rilSerial, rilError, rilRequest, dataCall);
1410                 break;
1411             case RIL_REQUEST_DEACTIVATE_DATA_CALL:
1412                 writeOnDeactivateDataCallResponse(phoneId, rilError);
1413                 break;
1414             case RIL_REQUEST_HANGUP:
1415             case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
1416             case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
1417             case RIL_REQUEST_DIAL:
1418             case RIL_REQUEST_ANSWER:
1419                 writeOnCallSolicitedResponse(phoneId, rilSerial, rilError, rilRequest);
1420                 break;
1421             case RIL_REQUEST_SEND_SMS:
1422             case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
1423             case RIL_REQUEST_CDMA_SEND_SMS:
1424             case RIL_REQUEST_IMS_SEND_SMS:
1425                 SmsResponse smsResponse = (SmsResponse) ret;
1426                 writeOnSmsSolicitedResponse(phoneId, rilSerial, rilError, smsResponse);
1427                 break;
1428         }
1429     }
1430 
1431     /**
1432      * Write phone state changed event
1433      *
1434      * @param phoneId Phone id
1435      * @param phoneState Phone state. See PhoneConstants.State for the details.
1436      */
writePhoneState(int phoneId, PhoneConstants.State phoneState)1437     public void writePhoneState(int phoneId, PhoneConstants.State phoneState) {
1438         int state;
1439         switch (phoneState) {
1440             case IDLE:
1441                 state = TelephonyCallSession.Event.PhoneState.STATE_IDLE;
1442                 break;
1443             case RINGING:
1444                 state = TelephonyCallSession.Event.PhoneState.STATE_RINGING;
1445                 break;
1446             case OFFHOOK:
1447                 state = TelephonyCallSession.Event.PhoneState.STATE_OFFHOOK;
1448                 break;
1449             default:
1450                 state = TelephonyCallSession.Event.PhoneState.STATE_UNKNOWN;
1451                 break;
1452         }
1453 
1454         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1455         if (callSession == null) {
1456             Rlog.e(TAG, "writePhoneState: Call session is missing");
1457         } else {
1458             // For CS Calls Finish the Call Session after Receiving the Last Call Fail Cause
1459             // For IMS calls we receive the Disconnect Cause along with Call End event.
1460             // So we can finish the call session here.
1461             callSession.setLastKnownPhoneState(state);
1462             if ((state == TelephonyCallSession.Event.PhoneState.STATE_IDLE)
1463                     && (!callSession.containsCsCalls())) {
1464                 finishCallSession(callSession);
1465             }
1466             callSession.addEvent(new CallSessionEventBuilder(
1467                     TelephonyCallSession.Event.Type.PHONE_STATE_CHANGED)
1468                     .setPhoneState(state));
1469         }
1470     }
1471 
1472     /**
1473      * Extracts the call ID from an ImsSession.
1474      *
1475      * @param session The session.
1476      * @return The call ID for the session, or -1 if none was found.
1477      */
getCallId(ImsCallSession session)1478     private int getCallId(ImsCallSession session) {
1479         if (session == null) {
1480             return -1;
1481         }
1482 
1483         try {
1484             return Integer.parseInt(session.getCallId());
1485         } catch (NumberFormatException nfe) {
1486             return -1;
1487         }
1488     }
1489 
1490     /**
1491      * Write IMS call state changed event
1492      *
1493      * @param phoneId Phone id
1494      * @param session IMS call session
1495      * @param callState IMS call state
1496      */
writeImsCallState(int phoneId, ImsCallSession session, ImsPhoneCall.State callState)1497     public void writeImsCallState(int phoneId, ImsCallSession session,
1498                                   ImsPhoneCall.State callState) {
1499         int state;
1500         switch (callState) {
1501             case IDLE:
1502                 state = TelephonyCallSession.Event.CallState.CALL_IDLE; break;
1503             case ACTIVE:
1504                 state = TelephonyCallSession.Event.CallState.CALL_ACTIVE; break;
1505             case HOLDING:
1506                 state = TelephonyCallSession.Event.CallState.CALL_HOLDING; break;
1507             case DIALING:
1508                 state = TelephonyCallSession.Event.CallState.CALL_DIALING; break;
1509             case ALERTING:
1510                 state = TelephonyCallSession.Event.CallState.CALL_ALERTING; break;
1511             case INCOMING:
1512                 state = TelephonyCallSession.Event.CallState.CALL_INCOMING; break;
1513             case WAITING:
1514                 state = TelephonyCallSession.Event.CallState.CALL_WAITING; break;
1515             case DISCONNECTED:
1516                 state = TelephonyCallSession.Event.CallState.CALL_DISCONNECTED; break;
1517             case DISCONNECTING:
1518                 state = TelephonyCallSession.Event.CallState.CALL_DISCONNECTING; break;
1519             default:
1520                 state = TelephonyCallSession.Event.CallState.CALL_UNKNOWN; break;
1521         }
1522 
1523         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1524         if (callSession == null) {
1525             Rlog.e(TAG, "Call session is missing");
1526         } else {
1527             callSession.addEvent(new CallSessionEventBuilder(
1528                     TelephonyCallSession.Event.Type.IMS_CALL_STATE_CHANGED)
1529                     .setCallIndex(getCallId(session))
1530                     .setCallState(state));
1531         }
1532     }
1533 
1534     /**
1535      * Write IMS call start event
1536      *
1537      * @param phoneId Phone id
1538      * @param session IMS call session
1539      */
writeOnImsCallStart(int phoneId, ImsCallSession session)1540     public void writeOnImsCallStart(int phoneId, ImsCallSession session) {
1541         InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
1542 
1543         callSession.addEvent(
1544                 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_COMMAND)
1545                         .setCallIndex(getCallId(session))
1546                         .setImsCommand(TelephonyCallSession.Event.ImsCommand.IMS_CMD_START));
1547     }
1548 
1549     /**
1550      * Write IMS incoming call event
1551      *
1552      * @param phoneId Phone id
1553      * @param session IMS call session
1554      */
writeOnImsCallReceive(int phoneId, ImsCallSession session)1555     public void writeOnImsCallReceive(int phoneId, ImsCallSession session) {
1556         InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
1557 
1558         callSession.addEvent(
1559                 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_CALL_RECEIVE)
1560                         .setCallIndex(getCallId(session)));
1561     }
1562 
1563     /**
1564      * Write IMS command event
1565      *
1566      * @param phoneId Phone id
1567      * @param session IMS call session
1568      * @param command IMS command
1569      */
writeOnImsCommand(int phoneId, ImsCallSession session, int command)1570     public void writeOnImsCommand(int phoneId, ImsCallSession session, int command) {
1571 
1572         InProgressCallSession callSession =  mInProgressCallSessions.get(phoneId);
1573         if (callSession == null) {
1574             Rlog.e(TAG, "Call session is missing");
1575         } else {
1576             callSession.addEvent(
1577                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_COMMAND)
1578                             .setCallIndex(getCallId(session))
1579                             .setImsCommand(command));
1580         }
1581     }
1582 
1583     /**
1584      * Convert IMS reason info into proto
1585      *
1586      * @param reasonInfo IMS reason info
1587      * @return Converted proto
1588      */
toImsReasonInfoProto(ImsReasonInfo reasonInfo)1589     private TelephonyProto.ImsReasonInfo toImsReasonInfoProto(ImsReasonInfo reasonInfo) {
1590         TelephonyProto.ImsReasonInfo ri = new TelephonyProto.ImsReasonInfo();
1591         if (reasonInfo != null) {
1592             ri.reasonCode = reasonInfo.getCode();
1593             ri.extraCode = reasonInfo.getExtraCode();
1594             String extraMessage = reasonInfo.getExtraMessage();
1595             if (extraMessage != null) {
1596                 ri.extraMessage = extraMessage;
1597             }
1598         }
1599         return ri;
1600     }
1601 
1602     /**
1603      * Write IMS call end event
1604      *
1605      * @param phoneId Phone id
1606      * @param session IMS call session
1607      * @param reasonInfo Call end reason
1608      */
writeOnImsCallTerminated(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo)1609     public void writeOnImsCallTerminated(int phoneId, ImsCallSession session,
1610                                          ImsReasonInfo reasonInfo) {
1611         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1612         if (callSession == null) {
1613             Rlog.e(TAG, "Call session is missing");
1614         } else {
1615             callSession.addEvent(
1616                     new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_CALL_TERMINATED)
1617                             .setCallIndex(getCallId(session))
1618                             .setImsReasonInfo(toImsReasonInfoProto(reasonInfo)));
1619         }
1620     }
1621 
1622     /**
1623      * Write IMS call hangover event
1624      *
1625      * @param phoneId Phone id
1626      * @param eventType hangover type
1627      * @param session IMS call session
1628      * @param srcAccessTech Hangover starting RAT
1629      * @param targetAccessTech Hangover destination RAT
1630      * @param reasonInfo Hangover reason
1631      */
writeOnImsCallHandoverEvent(int phoneId, int eventType, ImsCallSession session, int srcAccessTech, int targetAccessTech, ImsReasonInfo reasonInfo)1632     public void writeOnImsCallHandoverEvent(int phoneId, int eventType, ImsCallSession session,
1633                                             int srcAccessTech, int targetAccessTech,
1634                                             ImsReasonInfo reasonInfo) {
1635         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
1636         if (callSession == null) {
1637             Rlog.e(TAG, "Call session is missing");
1638         } else {
1639             callSession.addEvent(
1640                     new CallSessionEventBuilder(eventType)
1641                             .setCallIndex(getCallId(session))
1642                             .setSrcAccessTech(srcAccessTech)
1643                             .setTargetAccessTech(targetAccessTech)
1644                             .setImsReasonInfo(toImsReasonInfoProto(reasonInfo)));
1645         }
1646     }
1647 
1648     /**
1649      * Write Send SMS event
1650      *
1651      * @param phoneId Phone id
1652      * @param rilSerial RIL request serial number
1653      * @param tech SMS RAT
1654      * @param format SMS format. Either 3GPP or 3GPP2.
1655      */
writeRilSendSms(int phoneId, int rilSerial, int tech, int format)1656     public void writeRilSendSms(int phoneId, int rilSerial, int tech, int format) {
1657         InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId);
1658 
1659         smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_SEND)
1660                 .setTech(tech)
1661                 .setRilRequestId(rilSerial)
1662                 .setFormat(format)
1663         );
1664 
1665         smsSession.increaseExpectedResponse();
1666     }
1667 
1668     /**
1669      * Write incoming SMS event
1670      *
1671      * @param phoneId Phone id
1672      * @param tech SMS RAT
1673      * @param format SMS format. Either 3GPP or 3GPP2.
1674      */
writeRilNewSms(int phoneId, int tech, int format)1675     public void writeRilNewSms(int phoneId, int tech, int format) {
1676         InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId);
1677 
1678         smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_RECEIVED)
1679                 .setTech(tech)
1680                 .setFormat(format)
1681         );
1682 
1683         finishSmsSessionIfNeeded(smsSession);
1684     }
1685 
1686     /**
1687      * Write NITZ event
1688      *
1689      * @param phoneId Phone id
1690      * @param timestamp NITZ time in milliseconds
1691      */
writeNITZEvent(int phoneId, long timestamp)1692     public void writeNITZEvent(int phoneId, long timestamp) {
1693         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setNITZ(timestamp).build();
1694         addTelephonyEvent(event);
1695 
1696         annotateInProgressCallSession(event.timestampMillis, phoneId,
1697                 new CallSessionEventBuilder(
1698                         TelephonyCallSession.Event.Type.NITZ_TIME)
1699                         .setNITZ(timestamp));
1700     }
1701 
1702     /**
1703      * Write Modem Restart event
1704      *
1705      * @param phoneId Phone id
1706      * @param reason Reason for the modem reset.
1707      */
writeModemRestartEvent(int phoneId, String reason)1708     public void writeModemRestartEvent(int phoneId, String reason) {
1709         final ModemRestart modemRestart = new ModemRestart();
1710         String basebandVersion = Build.getRadioVersion();
1711         if (basebandVersion != null) modemRestart.basebandVersion = basebandVersion;
1712         if (reason != null) modemRestart.reason = reason;
1713         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setModemRestart(
1714                 modemRestart).build();
1715         addTelephonyEvent(event);
1716     }
1717 
1718     //TODO: Expand the proto in the future
writeOnImsCallProgressing(int phoneId, ImsCallSession session)1719     public void writeOnImsCallProgressing(int phoneId, ImsCallSession session) {}
writeOnImsCallStarted(int phoneId, ImsCallSession session)1720     public void writeOnImsCallStarted(int phoneId, ImsCallSession session) {}
writeOnImsCallStartFailed(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo)1721     public void writeOnImsCallStartFailed(int phoneId, ImsCallSession session,
1722                                           ImsReasonInfo reasonInfo) {}
writeOnImsCallHeld(int phoneId, ImsCallSession session)1723     public void writeOnImsCallHeld(int phoneId, ImsCallSession session) {}
writeOnImsCallHoldReceived(int phoneId, ImsCallSession session)1724     public void writeOnImsCallHoldReceived(int phoneId, ImsCallSession session) {}
writeOnImsCallHoldFailed(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo)1725     public void writeOnImsCallHoldFailed(int phoneId, ImsCallSession session,
1726                                          ImsReasonInfo reasonInfo) {}
writeOnImsCallResumed(int phoneId, ImsCallSession session)1727     public void writeOnImsCallResumed(int phoneId, ImsCallSession session) {}
writeOnImsCallResumeReceived(int phoneId, ImsCallSession session)1728     public void writeOnImsCallResumeReceived(int phoneId, ImsCallSession session) {}
writeOnImsCallResumeFailed(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo)1729     public void writeOnImsCallResumeFailed(int phoneId, ImsCallSession session,
1730                                            ImsReasonInfo reasonInfo) {}
writeOnRilTimeoutResponse(int phoneId, int rilSerial, int rilRequest)1731     public void writeOnRilTimeoutResponse(int phoneId, int rilSerial, int rilRequest) {}
1732 }
1733