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