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