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