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