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