1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.metrics; 18 19 import static android.text.format.DateUtils.MINUTE_IN_MILLIS; 20 21 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ANSWER; 22 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CDMA_SEND_SMS; 23 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE_DATA_CALL; 24 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DIAL; 25 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP; 26 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND; 27 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND; 28 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IMS_SEND_SMS; 29 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS; 30 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE; 31 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL; 32 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IP; 33 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6; 34 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV6; 35 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_NON_IP; 36 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_PPP; 37 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_UNSTRUCTURED; 38 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_UNKNOWN; 39 40 import android.os.Build; 41 import android.os.SystemClock; 42 import android.os.SystemProperties; 43 import android.provider.Telephony.Sms.Intents; 44 import android.telephony.CallQuality; 45 import android.telephony.DisconnectCause; 46 import android.telephony.Rlog; 47 import android.telephony.ServiceState; 48 import android.telephony.SmsManager; 49 import android.telephony.SmsMessage; 50 import android.telephony.SubscriptionInfo; 51 import android.telephony.SubscriptionManager; 52 import android.telephony.TelephonyHistogram; 53 import android.telephony.TelephonyManager; 54 import android.telephony.data.DataCallResponse; 55 import android.telephony.data.DataService; 56 import android.telephony.emergency.EmergencyNumber; 57 import android.telephony.ims.ImsCallProfile; 58 import android.telephony.ims.ImsCallSession; 59 import android.telephony.ims.ImsReasonInfo; 60 import android.telephony.ims.ImsStreamMediaProfile; 61 import android.telephony.ims.feature.MmTelFeature; 62 import android.telephony.ims.stub.ImsRegistrationImplBase; 63 import android.telephony.ims.stub.ImsSmsImplBase; 64 import android.text.TextUtils; 65 import android.util.Base64; 66 import android.util.SparseArray; 67 68 import com.android.internal.telephony.CarrierResolver; 69 import com.android.internal.telephony.DriverCall; 70 import com.android.internal.telephony.GsmCdmaConnection; 71 import com.android.internal.telephony.PhoneConstants; 72 import com.android.internal.telephony.RIL; 73 import com.android.internal.telephony.RILConstants; 74 import com.android.internal.telephony.SmsResponse; 75 import com.android.internal.telephony.UUSInfo; 76 import com.android.internal.telephony.imsphone.ImsPhoneCall; 77 import com.android.internal.telephony.nano.TelephonyProto; 78 import com.android.internal.telephony.nano.TelephonyProto.ActiveSubscriptionInfo; 79 import com.android.internal.telephony.nano.TelephonyProto.EmergencyNumberInfo; 80 import com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities; 81 import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState; 82 import com.android.internal.telephony.nano.TelephonyProto.ModemPowerStats; 83 import com.android.internal.telephony.nano.TelephonyProto.RilDataCall; 84 import com.android.internal.telephony.nano.TelephonyProto.SimState; 85 import com.android.internal.telephony.nano.TelephonyProto.SmsSession; 86 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession; 87 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.CallState; 88 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.RilCall; 89 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.RilCall.Type; 90 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; 91 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatching; 92 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatchingResult; 93 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierKeyChange; 94 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch; 95 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart; 96 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch; 97 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall; 98 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall.DeactivateReason; 99 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCall; 100 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse; 101 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse.RilDataCallFailCause; 102 import com.android.internal.telephony.nano.TelephonyProto.TelephonyLog; 103 import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState; 104 import com.android.internal.telephony.nano.TelephonyProto.TelephonySettings; 105 import com.android.internal.telephony.nano.TelephonyProto.TimeInterval; 106 import com.android.internal.telephony.protobuf.nano.MessageNano; 107 import com.android.internal.util.IndentingPrintWriter; 108 109 import java.io.FileDescriptor; 110 import java.io.PrintWriter; 111 import java.text.DecimalFormat; 112 import java.util.ArrayDeque; 113 import java.util.ArrayList; 114 import java.util.Arrays; 115 import java.util.Deque; 116 import java.util.List; 117 import java.util.concurrent.ThreadLocalRandom; 118 119 /** 120 * Telephony metrics holds all metrics events and convert it into telephony proto buf. 121 * @hide 122 */ 123 public class TelephonyMetrics { 124 125 private static final String TAG = TelephonyMetrics.class.getSimpleName(); 126 127 private static final boolean DBG = true; 128 private static final boolean VDBG = false; // STOPSHIP if true 129 130 /** Maximum telephony events stored */ 131 private static final int MAX_TELEPHONY_EVENTS = 1000; 132 133 /** Maximum call sessions stored */ 134 private static final int MAX_COMPLETED_CALL_SESSIONS = 50; 135 136 /** Maximum sms sessions stored */ 137 private static final int MAX_COMPLETED_SMS_SESSIONS = 500; 138 139 /** For reducing the timing precision for privacy purposes */ 140 private static final int SESSION_START_PRECISION_MINUTES = 5; 141 142 /** The TelephonyMetrics singleton instance */ 143 private static TelephonyMetrics sInstance; 144 145 /** Telephony events */ 146 private final Deque<TelephonyEvent> mTelephonyEvents = new ArrayDeque<>(); 147 148 /** 149 * In progress call sessions. Note that each phone can only have up to 1 in progress call 150 * session (might contains multiple calls). Having a sparse array in case we need to support 151 * DSDA in the future. 152 */ 153 private final SparseArray<InProgressCallSession> mInProgressCallSessions = new SparseArray<>(); 154 155 /** The completed call sessions */ 156 private final Deque<TelephonyCallSession> mCompletedCallSessions = new ArrayDeque<>(); 157 158 /** The in-progress SMS sessions. When finished, it will be moved into the completed sessions */ 159 private final SparseArray<InProgressSmsSession> mInProgressSmsSessions = new SparseArray<>(); 160 161 /** The completed SMS sessions */ 162 private final Deque<SmsSession> mCompletedSmsSessions = new ArrayDeque<>(); 163 164 /** Last service state. This is for injecting the base of a new log or a new call/sms session */ 165 private final SparseArray<TelephonyServiceState> mLastServiceState = new SparseArray<>(); 166 167 /** 168 * Last ims capabilities. This is for injecting the base of a new log or a new call/sms 169 * session 170 */ 171 private final SparseArray<ImsCapabilities> mLastImsCapabilities = new SparseArray<>(); 172 173 /** 174 * Last IMS connection state. This is for injecting the base of a new log or a new call/sms 175 * session 176 */ 177 private final SparseArray<ImsConnectionState> mLastImsConnectionState = new SparseArray<>(); 178 179 /** 180 * Last settings state. This is for deduping same settings event logged. 181 */ 182 private final SparseArray<TelephonySettings> mLastSettings = new SparseArray<>(); 183 184 /** 185 * Last sim state, indexed by phone id. 186 */ 187 private final SparseArray<Integer> mLastSimState = new SparseArray<>(); 188 189 /** 190 * Last active subscription information, indexed by phone id. 191 */ 192 private final SparseArray<ActiveSubscriptionInfo> mLastActiveSubscriptionInfos = 193 new SparseArray<>(); 194 195 /** 196 * The last modem state represent by a bitmap, the i-th bit(LSB) indicates the i-th modem 197 * state(0 - disabled, 1 - enabled). 198 * 199 * TODO: initialize the enabled modem bitmap when it's possible to get the modem state. 200 */ 201 private int mLastEnabledModemBitmap = (1 << TelephonyManager.getDefault().getPhoneCount()) - 1; 202 203 /** 204 * Last carrier id matching. 205 */ 206 private final SparseArray<CarrierIdMatching> mLastCarrierId = new SparseArray<>(); 207 208 /** 209 * Last RilDataCall Events (indexed by cid), indexed by phone id 210 */ 211 private final SparseArray<SparseArray<RilDataCall>> mLastRilDataCallEvents = 212 new SparseArray<>(); 213 214 /** The start system time of the TelephonyLog in milliseconds*/ 215 private long mStartSystemTimeMs; 216 217 /** The start elapsed time of the TelephonyLog in milliseconds*/ 218 private long mStartElapsedTimeMs; 219 220 /** Indicating if some of the telephony events are dropped in this log */ 221 private boolean mTelephonyEventsDropped = false; 222 TelephonyMetrics()223 public TelephonyMetrics() { 224 mStartSystemTimeMs = System.currentTimeMillis(); 225 mStartElapsedTimeMs = SystemClock.elapsedRealtime(); 226 } 227 228 /** 229 * Get the singleton instance of telephony metrics. 230 * 231 * @return The instance 232 */ getInstance()233 public synchronized static TelephonyMetrics getInstance() { 234 if (sInstance == null) { 235 sInstance = new TelephonyMetrics(); 236 } 237 238 return sInstance; 239 } 240 241 /** 242 * Dump the state of various objects, add calls to other objects as desired. 243 * 244 * @param fd File descriptor 245 * @param pw Print writer 246 * @param args Arguments 247 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)248 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 249 if (args != null && args.length > 0) { 250 boolean reset = true; 251 if (args.length > 1 && "--keep".equals(args[1])) { 252 reset = false; 253 } 254 255 switch (args[0]) { 256 case "--metrics": 257 printAllMetrics(pw); 258 break; 259 case "--metricsproto": 260 pw.println(convertProtoToBase64String(buildProto())); 261 if (reset) { 262 reset(); 263 } 264 break; 265 case "--metricsprototext": 266 pw.println(buildProto().toString()); 267 break; 268 } 269 } 270 } 271 logv(String log)272 private void logv(String log) { 273 if (VDBG) { 274 Rlog.v(TAG, log); 275 } 276 } 277 278 /** 279 * Convert the telephony event to string 280 * 281 * @param event The event in integer 282 * @return The event in string 283 */ telephonyEventToString(int event)284 private static String telephonyEventToString(int event) { 285 switch (event) { 286 case TelephonyEvent.Type.UNKNOWN: 287 return "UNKNOWN"; 288 case TelephonyEvent.Type.SETTINGS_CHANGED: 289 return "SETTINGS_CHANGED"; 290 case TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED: 291 return "RIL_SERVICE_STATE_CHANGED"; 292 case TelephonyEvent.Type.IMS_CONNECTION_STATE_CHANGED: 293 return "IMS_CONNECTION_STATE_CHANGED"; 294 case TelephonyEvent.Type.IMS_CAPABILITIES_CHANGED: 295 return "IMS_CAPABILITIES_CHANGED"; 296 case TelephonyEvent.Type.DATA_CALL_SETUP: 297 return "DATA_CALL_SETUP"; 298 case TelephonyEvent.Type.DATA_CALL_SETUP_RESPONSE: 299 return "DATA_CALL_SETUP_RESPONSE"; 300 case TelephonyEvent.Type.DATA_CALL_LIST_CHANGED: 301 return "DATA_CALL_LIST_CHANGED"; 302 case TelephonyEvent.Type.DATA_CALL_DEACTIVATE: 303 return "DATA_CALL_DEACTIVATE"; 304 case TelephonyEvent.Type.DATA_CALL_DEACTIVATE_RESPONSE: 305 return "DATA_CALL_DEACTIVATE_RESPONSE"; 306 case TelephonyEvent.Type.DATA_STALL_ACTION: 307 return "DATA_STALL_ACTION"; 308 case TelephonyEvent.Type.MODEM_RESTART: 309 return "MODEM_RESTART"; 310 case TelephonyEvent.Type.CARRIER_ID_MATCHING: 311 return "CARRIER_ID_MATCHING"; 312 case TelephonyEvent.Type.NITZ_TIME: 313 return "NITZ_TIME"; 314 case TelephonyEvent.Type.EMERGENCY_NUMBER_REPORT: 315 return "EMERGENCY_NUMBER_REPORT"; 316 default: 317 return Integer.toString(event); 318 } 319 } 320 321 /** 322 * Convert the call session event into string 323 * 324 * @param event The event in integer 325 * @return The event in String 326 */ callSessionEventToString(int event)327 private static String callSessionEventToString(int event) { 328 switch (event) { 329 case TelephonyCallSession.Event.Type.EVENT_UNKNOWN: 330 return "EVENT_UNKNOWN"; 331 case TelephonyCallSession.Event.Type.SETTINGS_CHANGED: 332 return "SETTINGS_CHANGED"; 333 case TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED: 334 return "RIL_SERVICE_STATE_CHANGED"; 335 case TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED: 336 return "IMS_CONNECTION_STATE_CHANGED"; 337 case TelephonyCallSession.Event.Type.IMS_CAPABILITIES_CHANGED: 338 return "IMS_CAPABILITIES_CHANGED"; 339 case TelephonyCallSession.Event.Type.DATA_CALL_LIST_CHANGED: 340 return "DATA_CALL_LIST_CHANGED"; 341 case TelephonyCallSession.Event.Type.RIL_REQUEST: 342 return "RIL_REQUEST"; 343 case TelephonyCallSession.Event.Type.RIL_RESPONSE: 344 return "RIL_RESPONSE"; 345 case TelephonyCallSession.Event.Type.RIL_CALL_RING: 346 return "RIL_CALL_RING"; 347 case TelephonyCallSession.Event.Type.RIL_CALL_SRVCC: 348 return "RIL_CALL_SRVCC"; 349 case TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED: 350 return "RIL_CALL_LIST_CHANGED"; 351 case TelephonyCallSession.Event.Type.IMS_COMMAND: 352 return "IMS_COMMAND"; 353 case TelephonyCallSession.Event.Type.IMS_COMMAND_RECEIVED: 354 return "IMS_COMMAND_RECEIVED"; 355 case TelephonyCallSession.Event.Type.IMS_COMMAND_FAILED: 356 return "IMS_COMMAND_FAILED"; 357 case TelephonyCallSession.Event.Type.IMS_COMMAND_COMPLETE: 358 return "IMS_COMMAND_COMPLETE"; 359 case TelephonyCallSession.Event.Type.IMS_CALL_RECEIVE: 360 return "IMS_CALL_RECEIVE"; 361 case TelephonyCallSession.Event.Type.IMS_CALL_STATE_CHANGED: 362 return "IMS_CALL_STATE_CHANGED"; 363 case TelephonyCallSession.Event.Type.IMS_CALL_TERMINATED: 364 return "IMS_CALL_TERMINATED"; 365 case TelephonyCallSession.Event.Type.IMS_CALL_HANDOVER: 366 return "IMS_CALL_HANDOVER"; 367 case TelephonyCallSession.Event.Type.IMS_CALL_HANDOVER_FAILED: 368 return "IMS_CALL_HANDOVER_FAILED"; 369 case TelephonyCallSession.Event.Type.PHONE_STATE_CHANGED: 370 return "PHONE_STATE_CHANGED"; 371 case TelephonyCallSession.Event.Type.NITZ_TIME: 372 return "NITZ_TIME"; 373 case TelephonyCallSession.Event.Type.AUDIO_CODEC: 374 return "AUDIO_CODEC"; 375 default: 376 return Integer.toString(event); 377 } 378 } 379 380 /** 381 * Convert the SMS session event into string 382 * @param event The event in integer 383 * @return The event in String 384 */ smsSessionEventToString(int event)385 private static String smsSessionEventToString(int event) { 386 switch (event) { 387 case SmsSession.Event.Type.EVENT_UNKNOWN: 388 return "EVENT_UNKNOWN"; 389 case SmsSession.Event.Type.SETTINGS_CHANGED: 390 return "SETTINGS_CHANGED"; 391 case SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED: 392 return "RIL_SERVICE_STATE_CHANGED"; 393 case SmsSession.Event.Type.IMS_CONNECTION_STATE_CHANGED: 394 return "IMS_CONNECTION_STATE_CHANGED"; 395 case SmsSession.Event.Type.IMS_CAPABILITIES_CHANGED: 396 return "IMS_CAPABILITIES_CHANGED"; 397 case SmsSession.Event.Type.DATA_CALL_LIST_CHANGED: 398 return "DATA_CALL_LIST_CHANGED"; 399 case SmsSession.Event.Type.SMS_SEND: 400 return "SMS_SEND"; 401 case SmsSession.Event.Type.SMS_SEND_RESULT: 402 return "SMS_SEND_RESULT"; 403 case SmsSession.Event.Type.SMS_RECEIVED: 404 return "SMS_RECEIVED"; 405 case SmsSession.Event.Type.INCOMPLETE_SMS_RECEIVED: 406 return "INCOMPLETE_SMS_RECEIVED"; 407 default: 408 return Integer.toString(event); 409 } 410 } 411 412 /** 413 * Print all metrics data for debugging purposes 414 * 415 * @param rawWriter Print writer 416 */ printAllMetrics(PrintWriter rawWriter)417 private synchronized void printAllMetrics(PrintWriter rawWriter) { 418 final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " "); 419 420 pw.println("Telephony metrics proto:"); 421 pw.println("------------------------------------------"); 422 pw.println("Telephony events:"); 423 pw.increaseIndent(); 424 for (TelephonyEvent event : mTelephonyEvents) { 425 pw.print(event.timestampMillis); 426 pw.print(" ["); 427 pw.print(event.phoneId); 428 pw.print("] "); 429 430 pw.print("T="); 431 if (event.type == TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED) { 432 pw.print(telephonyEventToString(event.type) 433 + "(" + "Data RAT " + event.serviceState.dataRat 434 + " Voice RAT " + event.serviceState.voiceRat 435 + " Channel Number " + event.serviceState.channelNumber 436 + ")"); 437 } else { 438 pw.print(telephonyEventToString(event.type)); 439 } 440 441 pw.println(""); 442 } 443 444 pw.decreaseIndent(); 445 pw.println("Call sessions:"); 446 pw.increaseIndent(); 447 448 for (TelephonyCallSession callSession : mCompletedCallSessions) { 449 pw.print("Start time in minutes: " + callSession.startTimeMinutes); 450 pw.print(", phone: " + callSession.phoneId); 451 if (callSession.eventsDropped) { 452 pw.println(" Events dropped: " + callSession.eventsDropped); 453 } 454 455 pw.println(" Events: "); 456 pw.increaseIndent(); 457 for (TelephonyCallSession.Event event : callSession.events) { 458 pw.print(event.delay); 459 pw.print(" T="); 460 if (event.type == TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED) { 461 pw.println(callSessionEventToString(event.type) 462 + "(" + "Data RAT " + event.serviceState.dataRat 463 + " Voice RAT " + event.serviceState.voiceRat 464 + " Channel Number " + event.serviceState.channelNumber 465 + ")"); 466 } else if (event.type == TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED) { 467 pw.println(callSessionEventToString(event.type)); 468 pw.increaseIndent(); 469 for (RilCall call : event.calls) { 470 pw.println(call.index + ". Type = " + call.type + " State = " 471 + call.state + " End Reason " + call.callEndReason 472 + " Precise Disconnect Cause " + call.preciseDisconnectCause 473 + " isMultiparty = " + call.isMultiparty); 474 } 475 pw.decreaseIndent(); 476 } else if (event.type == TelephonyCallSession.Event.Type.AUDIO_CODEC) { 477 pw.println(callSessionEventToString(event.type) 478 + "(" + event.audioCodec + ")"); 479 } else { 480 pw.println(callSessionEventToString(event.type)); 481 } 482 } 483 pw.decreaseIndent(); 484 } 485 486 pw.decreaseIndent(); 487 pw.println("Sms sessions:"); 488 pw.increaseIndent(); 489 490 int count = 0; 491 for (SmsSession smsSession : mCompletedSmsSessions) { 492 count++; 493 pw.print("[" + count + "] Start time in minutes: " 494 + smsSession.startTimeMinutes); 495 pw.print(", phone: " + smsSession.phoneId); 496 if (smsSession.eventsDropped) { 497 pw.println(", events dropped: " + smsSession.eventsDropped); 498 } else { 499 pw.println(""); 500 } 501 pw.println("Events: "); 502 pw.increaseIndent(); 503 for (SmsSession.Event event : smsSession.events) { 504 pw.print(event.delay); 505 pw.print(" T="); 506 pw.println(smsSessionEventToString(event.type)); 507 // Only show more info for tx/rx sms 508 if (event.type == SmsSession.Event.Type.SMS_RECEIVED) { 509 pw.increaseIndent(); 510 switch (event.smsType) { 511 case SmsSession.Event.SmsType.SMS_TYPE_SMS_PP: 512 pw.println("Type: SMS-PP"); 513 break; 514 case SmsSession.Event.SmsType.SMS_TYPE_VOICEMAIL_INDICATION: 515 pw.println("Type: Voicemail indication"); 516 break; 517 case SmsSession.Event.SmsType.SMS_TYPE_ZERO: 518 pw.println("Type: zero"); 519 break; 520 case SmsSession.Event.SmsType.SMS_TYPE_WAP_PUSH: 521 pw.println("Type: WAP PUSH"); 522 break; 523 default: 524 break; 525 } 526 if (event.errorCode != SmsManager.RESULT_ERROR_NONE) { 527 pw.println("E=" + event.errorCode); 528 } 529 pw.decreaseIndent(); 530 } else if (event.type == SmsSession.Event.Type.SMS_SEND 531 || event.type == SmsSession.Event.Type.SMS_SEND_RESULT) { 532 pw.increaseIndent(); 533 pw.println("ReqId=" + event.rilRequestId); 534 pw.println("E=" + event.errorCode); 535 pw.println("RilE=" + event.error); 536 pw.println("ImsE=" + event.imsError); 537 pw.decreaseIndent(); 538 } else if (event.type == SmsSession.Event.Type.INCOMPLETE_SMS_RECEIVED) { 539 pw.increaseIndent(); 540 pw.println("Received: " + event.incompleteSms.receivedParts + "/" 541 + event.incompleteSms.totalParts); 542 pw.decreaseIndent(); 543 } 544 } 545 pw.decreaseIndent(); 546 } 547 548 pw.decreaseIndent(); 549 pw.println("Modem power stats:"); 550 pw.increaseIndent(); 551 ModemPowerStats s = new ModemPowerMetrics().buildProto(); 552 pw.println("Power log duration (battery time) (ms): " + s.loggingDurationMs); 553 pw.println("Energy consumed by modem (mAh): " + s.energyConsumedMah); 554 pw.println("Number of packets sent (tx): " + s.numPacketsTx); 555 pw.println("Number of bytes sent (tx): " + s.numBytesTx); 556 pw.println("Number of packets received (rx): " + s.numPacketsRx); 557 pw.println("Number of bytes received (rx): " + s.numBytesRx); 558 pw.println("Amount of time kernel is active because of cellular data (ms): " 559 + s.cellularKernelActiveTimeMs); 560 pw.println("Amount of time spent in very poor rx signal level (ms): " 561 + s.timeInVeryPoorRxSignalLevelMs); 562 pw.println("Amount of time modem is in sleep (ms): " + s.sleepTimeMs); 563 pw.println("Amount of time modem is in idle (ms): " + s.idleTimeMs); 564 pw.println("Amount of time modem is in rx (ms): " + s.rxTimeMs); 565 pw.println("Amount of time modem is in tx (ms): " + Arrays.toString(s.txTimeMs)); 566 pw.println("Amount of time phone spent in various Radio Access Technologies (ms): " 567 + Arrays.toString(s.timeInRatMs)); 568 pw.println("Amount of time phone spent in various cellular " 569 + "rx signal strength levels (ms): " 570 + Arrays.toString(s.timeInRxSignalStrengthLevelMs)); 571 pw.println("Energy consumed across measured modem rails (mAh): " 572 + new DecimalFormat("#.##").format(s.monitoredRailEnergyConsumedMah)); 573 pw.decreaseIndent(); 574 pw.println("Hardware Version: " + SystemProperties.get("ro.boot.revision", "")); 575 } 576 577 /** 578 * Convert the telephony proto into Base-64 encoded string 579 * 580 * @param proto Telephony proto 581 * @return Encoded string 582 */ convertProtoToBase64String(TelephonyLog proto)583 private static String convertProtoToBase64String(TelephonyLog proto) { 584 return Base64.encodeToString( 585 TelephonyProto.TelephonyLog.toByteArray(proto), Base64.DEFAULT); 586 } 587 588 /** 589 * Reset all events and sessions 590 */ reset()591 private synchronized void reset() { 592 mTelephonyEvents.clear(); 593 mCompletedCallSessions.clear(); 594 mCompletedSmsSessions.clear(); 595 596 mTelephonyEventsDropped = false; 597 598 mStartSystemTimeMs = System.currentTimeMillis(); 599 mStartElapsedTimeMs = SystemClock.elapsedRealtime(); 600 601 // Insert the last known sim state, enabled modem bitmap, active subscription info, 602 // service state, ims capabilities, ims connection states, carrier id and Data call 603 // events as the base. 604 // Sim state, modem bitmap and active subscription info events are logged before 605 // other events. 606 addTelephonyEvent(new TelephonyEventBuilder(mStartElapsedTimeMs, -1 /* phoneId */) 607 .setSimStateChange(mLastSimState).build()); 608 609 addTelephonyEvent(new TelephonyEventBuilder(mStartElapsedTimeMs, -1 /* phoneId */) 610 .setEnabledModemBitmap(mLastEnabledModemBitmap).build()); 611 612 for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) { 613 final int key = mLastActiveSubscriptionInfos.keyAt(i); 614 TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key) 615 .setActiveSubscriptionInfoChange(mLastActiveSubscriptionInfos.get(key)).build(); 616 addTelephonyEvent(event); 617 } 618 619 for (int i = 0; i < mLastServiceState.size(); i++) { 620 final int key = mLastServiceState.keyAt(i); 621 622 TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key) 623 .setServiceState(mLastServiceState.get(key)).build(); 624 addTelephonyEvent(event); 625 } 626 627 for (int i = 0; i < mLastImsCapabilities.size(); i++) { 628 final int key = mLastImsCapabilities.keyAt(i); 629 630 TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key) 631 .setImsCapabilities(mLastImsCapabilities.get(key)).build(); 632 addTelephonyEvent(event); 633 } 634 635 for (int i = 0; i < mLastImsConnectionState.size(); i++) { 636 final int key = mLastImsConnectionState.keyAt(i); 637 638 TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key) 639 .setImsConnectionState(mLastImsConnectionState.get(key)).build(); 640 addTelephonyEvent(event); 641 } 642 643 for (int i = 0; i < mLastCarrierId.size(); i++) { 644 final int key = mLastCarrierId.keyAt(i); 645 TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key) 646 .setCarrierIdMatching(mLastCarrierId.get(key)).build(); 647 addTelephonyEvent(event); 648 } 649 650 for (int i = 0; i < mLastRilDataCallEvents.size(); i++) { 651 final int key = mLastRilDataCallEvents.keyAt(i); 652 for (int j = 0; j < mLastRilDataCallEvents.get(key).size(); j++) { 653 final int cidKey = mLastRilDataCallEvents.get(key).keyAt(j); 654 RilDataCall[] dataCalls = new RilDataCall[1]; 655 dataCalls[0] = mLastRilDataCallEvents.get(key).get(cidKey); 656 addTelephonyEvent(new TelephonyEventBuilder(mStartElapsedTimeMs, key) 657 .setDataCalls(dataCalls).build()); 658 } 659 } 660 } 661 662 /** 663 * Build the telephony proto 664 * 665 * @return Telephony proto 666 */ buildProto()667 private synchronized TelephonyLog buildProto() { 668 669 TelephonyLog log = new TelephonyLog(); 670 // Build telephony events 671 log.events = new TelephonyEvent[mTelephonyEvents.size()]; 672 mTelephonyEvents.toArray(log.events); 673 log.eventsDropped = mTelephonyEventsDropped; 674 675 // Build call sessions 676 log.callSessions = new TelephonyCallSession[mCompletedCallSessions.size()]; 677 mCompletedCallSessions.toArray(log.callSessions); 678 679 // Build SMS sessions 680 log.smsSessions = new SmsSession[mCompletedSmsSessions.size()]; 681 mCompletedSmsSessions.toArray(log.smsSessions); 682 683 // Build histogram. Currently we only support RIL histograms. 684 List<TelephonyHistogram> rilHistograms = RIL.getTelephonyRILTimingHistograms(); 685 log.histograms = new TelephonyProto.TelephonyHistogram[rilHistograms.size()]; 686 for (int i = 0; i < rilHistograms.size(); i++) { 687 log.histograms[i] = new TelephonyProto.TelephonyHistogram(); 688 TelephonyHistogram rilHistogram = rilHistograms.get(i); 689 TelephonyProto.TelephonyHistogram histogramProto = log.histograms[i]; 690 691 histogramProto.category = rilHistogram.getCategory(); 692 histogramProto.id = rilHistogram.getId(); 693 histogramProto.minTimeMillis = rilHistogram.getMinTime(); 694 histogramProto.maxTimeMillis = rilHistogram.getMaxTime(); 695 histogramProto.avgTimeMillis = rilHistogram.getAverageTime(); 696 histogramProto.count = rilHistogram.getSampleCount(); 697 histogramProto.bucketCount = rilHistogram.getBucketCount(); 698 histogramProto.bucketEndPoints = rilHistogram.getBucketEndPoints(); 699 histogramProto.bucketCounters = rilHistogram.getBucketCounters(); 700 } 701 702 // Build modem power metrics 703 log.modemPowerStats = new ModemPowerMetrics().buildProto(); 704 705 // Log the hardware revision 706 log.hardwareRevision = SystemProperties.get("ro.boot.revision", ""); 707 708 // Log the starting system time 709 log.startTime = new TelephonyProto.Time(); 710 log.startTime.systemTimestampMillis = mStartSystemTimeMs; 711 log.startTime.elapsedTimestampMillis = mStartElapsedTimeMs; 712 713 log.endTime = new TelephonyProto.Time(); 714 log.endTime.systemTimestampMillis = System.currentTimeMillis(); 715 log.endTime.elapsedTimestampMillis = SystemClock.elapsedRealtime(); 716 717 // Log the last active subscription information. 718 int phoneCount = TelephonyManager.getDefault().getPhoneCount(); 719 ActiveSubscriptionInfo[] activeSubscriptionInfo = 720 new ActiveSubscriptionInfo[phoneCount]; 721 for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) { 722 int key = mLastActiveSubscriptionInfos.keyAt(i); 723 activeSubscriptionInfo[key] = mLastActiveSubscriptionInfos.get(key); 724 } 725 for (int i = 0; i < phoneCount; i++) { 726 if (activeSubscriptionInfo[i] == null) { 727 activeSubscriptionInfo[i] = makeInvalidSubscriptionInfo(i); 728 } 729 } 730 log.lastActiveSubscriptionInfo = activeSubscriptionInfo; 731 732 return log; 733 } 734 735 /** Update the sim state. */ updateSimState(int phoneId, int simState)736 public void updateSimState(int phoneId, int simState) { 737 int state = mapSimStateToProto(simState); 738 Integer lastSimState = mLastSimState.get(phoneId); 739 if (lastSimState == null || !lastSimState.equals(state)) { 740 mLastSimState.put(phoneId, state); 741 addTelephonyEvent(new TelephonyEventBuilder().setSimStateChange(mLastSimState).build()); 742 } 743 } 744 745 /** Update active subscription info list. */ updateActiveSubscriptionInfoList(List<SubscriptionInfo> subInfos)746 public synchronized void updateActiveSubscriptionInfoList(List<SubscriptionInfo> subInfos) { 747 List<Integer> inActivePhoneList = new ArrayList<>(); 748 for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) { 749 inActivePhoneList.add(mLastActiveSubscriptionInfos.keyAt(i)); 750 } 751 752 for (SubscriptionInfo info : subInfos) { 753 int phoneId = info.getSimSlotIndex(); 754 inActivePhoneList.removeIf(value -> value.equals(phoneId)); 755 ActiveSubscriptionInfo activeSubscriptionInfo = new ActiveSubscriptionInfo(); 756 activeSubscriptionInfo.slotIndex = phoneId; 757 activeSubscriptionInfo.isOpportunistic = info.isOpportunistic() ? 1 : 0; 758 activeSubscriptionInfo.carrierId = info.getCarrierId(); 759 if (!MessageNano.messageNanoEquals( 760 mLastActiveSubscriptionInfos.get(phoneId), activeSubscriptionInfo)) { 761 addTelephonyEvent(new TelephonyEventBuilder(phoneId) 762 .setActiveSubscriptionInfoChange(activeSubscriptionInfo).build()); 763 764 mLastActiveSubscriptionInfos.put(phoneId, activeSubscriptionInfo); 765 } 766 } 767 768 for (int phoneId : inActivePhoneList) { 769 mLastActiveSubscriptionInfos.remove(phoneId); 770 addTelephonyEvent(new TelephonyEventBuilder(phoneId) 771 .setActiveSubscriptionInfoChange(makeInvalidSubscriptionInfo(phoneId)).build()); 772 } 773 } 774 775 /** Update the enabled modem bitmap. */ updateEnabledModemBitmap(int enabledModemBitmap)776 public void updateEnabledModemBitmap(int enabledModemBitmap) { 777 if (mLastEnabledModemBitmap == enabledModemBitmap) return; 778 mLastEnabledModemBitmap = enabledModemBitmap; 779 addTelephonyEvent(new TelephonyEventBuilder() 780 .setEnabledModemBitmap(mLastEnabledModemBitmap).build()); 781 } 782 makeInvalidSubscriptionInfo(int phoneId)783 private static ActiveSubscriptionInfo makeInvalidSubscriptionInfo(int phoneId) { 784 ActiveSubscriptionInfo invalidSubscriptionInfo = new ActiveSubscriptionInfo(); 785 invalidSubscriptionInfo.slotIndex = phoneId; 786 invalidSubscriptionInfo.carrierId = -1; 787 invalidSubscriptionInfo.isOpportunistic = -1; 788 return invalidSubscriptionInfo; 789 } 790 791 /** 792 * Reduce precision to meet privacy requirements. 793 * 794 * @param timestamp timestamp in milliseconds 795 * @return Precision reduced timestamp in minutes 796 */ roundSessionStart(long timestamp)797 static int roundSessionStart(long timestamp) { 798 return (int) ((timestamp) / (MINUTE_IN_MILLIS * SESSION_START_PRECISION_MINUTES) 799 * (SESSION_START_PRECISION_MINUTES)); 800 } 801 802 /** 803 * Write the Carrier Key change event 804 * 805 * @param phoneId Phone id 806 * @param keyType type of key 807 * @param isDownloadSuccessful true if the key was successfully downloaded 808 */ writeCarrierKeyEvent(int phoneId, int keyType, boolean isDownloadSuccessful)809 public void writeCarrierKeyEvent(int phoneId, int keyType, boolean isDownloadSuccessful) { 810 final CarrierKeyChange carrierKeyChange = new CarrierKeyChange(); 811 carrierKeyChange.keyType = keyType; 812 carrierKeyChange.isDownloadSuccessful = isDownloadSuccessful; 813 TelephonyEvent event = new TelephonyEventBuilder(phoneId).setCarrierKeyChange( 814 carrierKeyChange).build(); 815 addTelephonyEvent(event); 816 } 817 818 819 /** 820 * Get the time interval with reduced prevision 821 * 822 * @param previousTimestamp Previous timestamp in milliseconds 823 * @param currentTimestamp Current timestamp in milliseconds 824 * @return The time interval 825 */ toPrivacyFuzzedTimeInterval(long previousTimestamp, long currentTimestamp)826 static int toPrivacyFuzzedTimeInterval(long previousTimestamp, long currentTimestamp) { 827 long diff = currentTimestamp - previousTimestamp; 828 if (diff < 0) { 829 return TimeInterval.TI_UNKNOWN; 830 } else if (diff <= 10) { 831 return TimeInterval.TI_10_MILLIS; 832 } else if (diff <= 20) { 833 return TimeInterval.TI_20_MILLIS; 834 } else if (diff <= 50) { 835 return TimeInterval.TI_50_MILLIS; 836 } else if (diff <= 100) { 837 return TimeInterval.TI_100_MILLIS; 838 } else if (diff <= 200) { 839 return TimeInterval.TI_200_MILLIS; 840 } else if (diff <= 500) { 841 return TimeInterval.TI_500_MILLIS; 842 } else if (diff <= 1000) { 843 return TimeInterval.TI_1_SEC; 844 } else if (diff <= 2000) { 845 return TimeInterval.TI_2_SEC; 846 } else if (diff <= 5000) { 847 return TimeInterval.TI_5_SEC; 848 } else if (diff <= 10000) { 849 return TimeInterval.TI_10_SEC; 850 } else if (diff <= 30000) { 851 return TimeInterval.TI_30_SEC; 852 } else if (diff <= 60000) { 853 return TimeInterval.TI_1_MINUTE; 854 } else if (diff <= 180000) { 855 return TimeInterval.TI_3_MINUTES; 856 } else if (diff <= 600000) { 857 return TimeInterval.TI_10_MINUTES; 858 } else if (diff <= 1800000) { 859 return TimeInterval.TI_30_MINUTES; 860 } else if (diff <= 3600000) { 861 return TimeInterval.TI_1_HOUR; 862 } else if (diff <= 7200000) { 863 return TimeInterval.TI_2_HOURS; 864 } else if (diff <= 14400000) { 865 return TimeInterval.TI_4_HOURS; 866 } else { 867 return TimeInterval.TI_MANY_HOURS; 868 } 869 } 870 871 /** 872 * Convert the service state into service state proto 873 * 874 * @param serviceState Service state 875 * @return Service state proto 876 */ toServiceStateProto(ServiceState serviceState)877 private TelephonyServiceState toServiceStateProto(ServiceState serviceState) { 878 TelephonyServiceState ssProto = new TelephonyServiceState(); 879 880 ssProto.voiceRoamingType = serviceState.getVoiceRoamingType(); 881 ssProto.dataRoamingType = serviceState.getDataRoamingType(); 882 883 ssProto.voiceOperator = new TelephonyServiceState.TelephonyOperator(); 884 885 if (serviceState.getVoiceOperatorAlphaLong() != null) { 886 ssProto.voiceOperator.alphaLong = serviceState.getVoiceOperatorAlphaLong(); 887 } 888 889 if (serviceState.getVoiceOperatorAlphaShort() != null) { 890 ssProto.voiceOperator.alphaShort = serviceState.getVoiceOperatorAlphaShort(); 891 } 892 893 if (serviceState.getVoiceOperatorNumeric() != null) { 894 ssProto.voiceOperator.numeric = serviceState.getVoiceOperatorNumeric(); 895 } 896 897 ssProto.dataOperator = new TelephonyServiceState.TelephonyOperator(); 898 899 if (serviceState.getDataOperatorAlphaLong() != null) { 900 ssProto.dataOperator.alphaLong = serviceState.getDataOperatorAlphaLong(); 901 } 902 903 if (serviceState.getDataOperatorAlphaShort() != null) { 904 ssProto.dataOperator.alphaShort = serviceState.getDataOperatorAlphaShort(); 905 } 906 907 if (serviceState.getDataOperatorNumeric() != null) { 908 ssProto.dataOperator.numeric = serviceState.getDataOperatorNumeric(); 909 } 910 911 ssProto.voiceRat = serviceState.getRilVoiceRadioTechnology(); 912 ssProto.dataRat = serviceState.getRilDataRadioTechnology(); 913 ssProto.channelNumber = serviceState.getChannelNumber(); 914 return ssProto; 915 } 916 917 /** 918 * Annotate the call session with events 919 * 920 * @param timestamp Event timestamp 921 * @param phoneId Phone id 922 * @param eventBuilder Call session event builder 923 */ annotateInProgressCallSession(long timestamp, int phoneId, CallSessionEventBuilder eventBuilder)924 private synchronized void annotateInProgressCallSession(long timestamp, int phoneId, 925 CallSessionEventBuilder eventBuilder) { 926 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 927 if (callSession != null) { 928 callSession.addEvent(timestamp, eventBuilder); 929 } 930 } 931 932 /** 933 * Annotate the SMS session with events 934 * 935 * @param timestamp Event timestamp 936 * @param phoneId Phone id 937 * @param eventBuilder SMS session event builder 938 */ annotateInProgressSmsSession(long timestamp, int phoneId, SmsSessionEventBuilder eventBuilder)939 private synchronized void annotateInProgressSmsSession(long timestamp, int phoneId, 940 SmsSessionEventBuilder eventBuilder) { 941 InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId); 942 if (smsSession != null) { 943 smsSession.addEvent(timestamp, eventBuilder); 944 } 945 } 946 947 /** 948 * Create the call session if there isn't any existing one 949 * 950 * @param phoneId Phone id 951 * @return The call session 952 */ startNewCallSessionIfNeeded(int phoneId)953 private synchronized InProgressCallSession startNewCallSessionIfNeeded(int phoneId) { 954 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 955 if (callSession == null) { 956 logv("Starting a new call session on phone " + phoneId); 957 callSession = new InProgressCallSession(phoneId); 958 mInProgressCallSessions.append(phoneId, callSession); 959 960 // Insert the latest service state, ims capabilities, and ims connection states as the 961 // base. 962 TelephonyServiceState serviceState = mLastServiceState.get(phoneId); 963 if (serviceState != null) { 964 callSession.addEvent(callSession.startElapsedTimeMs, new CallSessionEventBuilder( 965 TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED) 966 .setServiceState(serviceState)); 967 } 968 969 ImsCapabilities imsCapabilities = mLastImsCapabilities.get(phoneId); 970 if (imsCapabilities != null) { 971 callSession.addEvent(callSession.startElapsedTimeMs, new CallSessionEventBuilder( 972 TelephonyCallSession.Event.Type.IMS_CAPABILITIES_CHANGED) 973 .setImsCapabilities(imsCapabilities)); 974 } 975 976 ImsConnectionState imsConnectionState = mLastImsConnectionState.get(phoneId); 977 if (imsConnectionState != null) { 978 callSession.addEvent(callSession.startElapsedTimeMs, new CallSessionEventBuilder( 979 TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED) 980 .setImsConnectionState(imsConnectionState)); 981 } 982 } 983 return callSession; 984 } 985 986 /** 987 * Create the SMS session if there isn't any existing one 988 * 989 * @param phoneId Phone id 990 * @return The SMS session 991 */ startNewSmsSessionIfNeeded(int phoneId)992 private synchronized InProgressSmsSession startNewSmsSessionIfNeeded(int phoneId) { 993 InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId); 994 if (smsSession == null) { 995 logv("Starting a new sms session on phone " + phoneId); 996 smsSession = startNewSmsSession(phoneId); 997 mInProgressSmsSessions.append(phoneId, smsSession); 998 } 999 return smsSession; 1000 } 1001 1002 /** 1003 * Create a new SMS session 1004 * 1005 * @param phoneId Phone id 1006 * @return The SMS session 1007 */ startNewSmsSession(int phoneId)1008 private InProgressSmsSession startNewSmsSession(int phoneId) { 1009 InProgressSmsSession smsSession = new InProgressSmsSession(phoneId); 1010 1011 // Insert the latest service state, ims capabilities, and ims connection state as the 1012 // base. 1013 TelephonyServiceState serviceState = mLastServiceState.get(phoneId); 1014 if (serviceState != null) { 1015 smsSession.addEvent(smsSession.startElapsedTimeMs, new SmsSessionEventBuilder( 1016 TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED) 1017 .setServiceState(serviceState)); 1018 } 1019 1020 ImsCapabilities imsCapabilities = mLastImsCapabilities.get(phoneId); 1021 if (imsCapabilities != null) { 1022 smsSession.addEvent(smsSession.startElapsedTimeMs, new SmsSessionEventBuilder( 1023 SmsSession.Event.Type.IMS_CAPABILITIES_CHANGED) 1024 .setImsCapabilities(imsCapabilities)); 1025 } 1026 1027 ImsConnectionState imsConnectionState = mLastImsConnectionState.get(phoneId); 1028 if (imsConnectionState != null) { 1029 smsSession.addEvent(smsSession.startElapsedTimeMs, new SmsSessionEventBuilder( 1030 SmsSession.Event.Type.IMS_CONNECTION_STATE_CHANGED) 1031 .setImsConnectionState(imsConnectionState)); 1032 } 1033 return smsSession; 1034 } 1035 1036 /** 1037 * Finish the call session and move it into the completed session 1038 * 1039 * @param inProgressCallSession The in progress call session 1040 */ finishCallSession(InProgressCallSession inProgressCallSession)1041 private synchronized void finishCallSession(InProgressCallSession inProgressCallSession) { 1042 TelephonyCallSession callSession = new TelephonyCallSession(); 1043 callSession.events = new TelephonyCallSession.Event[inProgressCallSession.events.size()]; 1044 inProgressCallSession.events.toArray(callSession.events); 1045 callSession.startTimeMinutes = inProgressCallSession.startSystemTimeMin; 1046 callSession.phoneId = inProgressCallSession.phoneId; 1047 callSession.eventsDropped = inProgressCallSession.isEventsDropped(); 1048 if (mCompletedCallSessions.size() >= MAX_COMPLETED_CALL_SESSIONS) { 1049 mCompletedCallSessions.removeFirst(); 1050 } 1051 mCompletedCallSessions.add(callSession); 1052 mInProgressCallSessions.remove(inProgressCallSession.phoneId); 1053 logv("Call session finished"); 1054 } 1055 1056 /** 1057 * Finish the SMS session and move it into the completed session 1058 * 1059 * @param inProgressSmsSession The in progress SMS session 1060 */ finishSmsSessionIfNeeded(InProgressSmsSession inProgressSmsSession)1061 private synchronized void finishSmsSessionIfNeeded(InProgressSmsSession inProgressSmsSession) { 1062 if (inProgressSmsSession.getNumExpectedResponses() == 0) { 1063 SmsSession smsSession = finishSmsSession(inProgressSmsSession); 1064 1065 mInProgressSmsSessions.remove(inProgressSmsSession.phoneId); 1066 logv("SMS session finished"); 1067 } 1068 } 1069 finishSmsSession(InProgressSmsSession inProgressSmsSession)1070 private SmsSession finishSmsSession(InProgressSmsSession inProgressSmsSession) { 1071 SmsSession smsSession = new SmsSession(); 1072 smsSession.events = new SmsSession.Event[inProgressSmsSession.events.size()]; 1073 inProgressSmsSession.events.toArray(smsSession.events); 1074 smsSession.startTimeMinutes = inProgressSmsSession.startSystemTimeMin; 1075 smsSession.phoneId = inProgressSmsSession.phoneId; 1076 smsSession.eventsDropped = inProgressSmsSession.isEventsDropped(); 1077 1078 if (mCompletedSmsSessions.size() >= MAX_COMPLETED_SMS_SESSIONS) { 1079 mCompletedSmsSessions.removeFirst(); 1080 } 1081 mCompletedSmsSessions.add(smsSession); 1082 return smsSession; 1083 } 1084 1085 /** 1086 * Add telephony event into the queue 1087 * 1088 * @param event Telephony event 1089 */ addTelephonyEvent(TelephonyEvent event)1090 private synchronized void addTelephonyEvent(TelephonyEvent event) { 1091 if (mTelephonyEvents.size() >= MAX_TELEPHONY_EVENTS) { 1092 mTelephonyEvents.removeFirst(); 1093 mTelephonyEventsDropped = true; 1094 } 1095 mTelephonyEvents.add(event); 1096 } 1097 1098 /** 1099 * Write service changed event 1100 * 1101 * @param phoneId Phone id 1102 * @param serviceState Service state 1103 */ writeServiceStateChanged(int phoneId, ServiceState serviceState)1104 public synchronized void writeServiceStateChanged(int phoneId, ServiceState serviceState) { 1105 1106 TelephonyEvent event = new TelephonyEventBuilder(phoneId) 1107 .setServiceState(toServiceStateProto(serviceState)).build(); 1108 1109 // If service state doesn't change, we don't log the event. 1110 if (mLastServiceState.get(phoneId) != null && 1111 Arrays.equals(TelephonyServiceState.toByteArray(mLastServiceState.get(phoneId)), 1112 TelephonyServiceState.toByteArray(event.serviceState))) { 1113 return; 1114 } 1115 1116 mLastServiceState.put(phoneId, event.serviceState); 1117 addTelephonyEvent(event); 1118 1119 annotateInProgressCallSession(event.timestampMillis, phoneId, 1120 new CallSessionEventBuilder( 1121 TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED) 1122 .setServiceState(event.serviceState)); 1123 annotateInProgressSmsSession(event.timestampMillis, phoneId, 1124 new SmsSessionEventBuilder( 1125 SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED) 1126 .setServiceState(event.serviceState)); 1127 } 1128 1129 /** 1130 * Write data stall event 1131 * 1132 * @param phoneId Phone id 1133 * @param recoveryAction Data stall recovery action 1134 */ writeDataStallEvent(int phoneId, int recoveryAction)1135 public void writeDataStallEvent(int phoneId, int recoveryAction) { 1136 addTelephonyEvent(new TelephonyEventBuilder(phoneId) 1137 .setDataStallRecoveryAction(recoveryAction).build()); 1138 } 1139 1140 /** 1141 * Write IMS feature settings changed event 1142 * 1143 * @param phoneId Phone id 1144 * @param feature IMS feature 1145 * @param network The IMS network type 1146 * @param value The settings. 0 indicates disabled, otherwise enabled. 1147 */ writeImsSetFeatureValue(int phoneId, int feature, int network, int value)1148 public void writeImsSetFeatureValue(int phoneId, int feature, int network, int value) { 1149 TelephonySettings s = new TelephonySettings(); 1150 if (network == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) { 1151 switch (feature) { 1152 case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE: 1153 s.isEnhanced4GLteModeEnabled = (value != 0); 1154 break; 1155 case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO: 1156 s.isVtOverLteEnabled = (value != 0); 1157 break; 1158 } 1159 } else if (network == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) { 1160 switch (feature) { 1161 case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE: 1162 s.isWifiCallingEnabled = (value != 0); 1163 break; 1164 case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO: 1165 s.isVtOverWifiEnabled = (value != 0); 1166 break; 1167 } 1168 } 1169 1170 1171 // If the settings don't change, we don't log the event. 1172 if (mLastSettings.get(phoneId) != null && 1173 Arrays.equals(TelephonySettings.toByteArray(mLastSettings.get(phoneId)), 1174 TelephonySettings.toByteArray(s))) { 1175 return; 1176 } 1177 1178 mLastSettings.put(phoneId, s); 1179 1180 TelephonyEvent event = new TelephonyEventBuilder(phoneId).setSettings(s).build(); 1181 addTelephonyEvent(event); 1182 1183 annotateInProgressCallSession(event.timestampMillis, phoneId, 1184 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.SETTINGS_CHANGED) 1185 .setSettings(s)); 1186 annotateInProgressSmsSession(event.timestampMillis, phoneId, 1187 new SmsSessionEventBuilder(SmsSession.Event.Type.SETTINGS_CHANGED) 1188 .setSettings(s)); 1189 } 1190 1191 /** 1192 * Write the preferred network settings changed event 1193 * 1194 * @param phoneId Phone id 1195 * @param networkType The preferred network 1196 */ writeSetPreferredNetworkType(int phoneId, int networkType)1197 public void writeSetPreferredNetworkType(int phoneId, int networkType) { 1198 TelephonySettings s = new TelephonySettings(); 1199 s.preferredNetworkMode = networkType + 1; 1200 1201 // If the settings don't change, we don't log the event. 1202 if (mLastSettings.get(phoneId) != null && 1203 Arrays.equals(TelephonySettings.toByteArray(mLastSettings.get(phoneId)), 1204 TelephonySettings.toByteArray(s))) { 1205 return; 1206 } 1207 1208 mLastSettings.put(phoneId, s); 1209 1210 addTelephonyEvent(new TelephonyEventBuilder(phoneId).setSettings(s).build()); 1211 } 1212 1213 /** 1214 * Write the IMS connection state changed event 1215 * 1216 * @param phoneId Phone id 1217 * @param state IMS connection state 1218 * @param reasonInfo The reason info. Only used for disconnected state. 1219 */ writeOnImsConnectionState(int phoneId, int state, ImsReasonInfo reasonInfo)1220 public synchronized void writeOnImsConnectionState(int phoneId, int state, 1221 ImsReasonInfo reasonInfo) { 1222 ImsConnectionState imsState = new ImsConnectionState(); 1223 imsState.state = state; 1224 1225 if (reasonInfo != null) { 1226 TelephonyProto.ImsReasonInfo ri = new TelephonyProto.ImsReasonInfo(); 1227 1228 ri.reasonCode = reasonInfo.getCode(); 1229 ri.extraCode = reasonInfo.getExtraCode(); 1230 String extraMessage = reasonInfo.getExtraMessage(); 1231 if (extraMessage != null) { 1232 ri.extraMessage = extraMessage; 1233 } 1234 1235 imsState.reasonInfo = ri; 1236 } 1237 1238 // If the connection state does not change, do not log it. 1239 if (mLastImsConnectionState.get(phoneId) != null && 1240 Arrays.equals(ImsConnectionState.toByteArray(mLastImsConnectionState.get(phoneId)), 1241 ImsConnectionState.toByteArray(imsState))) { 1242 return; 1243 } 1244 1245 mLastImsConnectionState.put(phoneId, imsState); 1246 1247 TelephonyEvent event = new TelephonyEventBuilder(phoneId) 1248 .setImsConnectionState(imsState).build(); 1249 addTelephonyEvent(event); 1250 1251 annotateInProgressCallSession(event.timestampMillis, phoneId, 1252 new CallSessionEventBuilder( 1253 TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED) 1254 .setImsConnectionState(event.imsConnectionState)); 1255 annotateInProgressSmsSession(event.timestampMillis, phoneId, 1256 new SmsSessionEventBuilder( 1257 SmsSession.Event.Type.IMS_CONNECTION_STATE_CHANGED) 1258 .setImsConnectionState(event.imsConnectionState)); 1259 } 1260 1261 /** 1262 * Write the IMS capabilities changed event 1263 * 1264 * @param phoneId Phone id 1265 * @param capabilities IMS capabilities array 1266 */ writeOnImsCapabilities(int phoneId, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech, MmTelFeature.MmTelCapabilities capabilities)1267 public synchronized void writeOnImsCapabilities(int phoneId, 1268 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech, 1269 MmTelFeature.MmTelCapabilities capabilities) { 1270 ImsCapabilities cap = new ImsCapabilities(); 1271 1272 if (radioTech == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) { 1273 cap.voiceOverLte = capabilities.isCapable( 1274 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE); 1275 cap.videoOverLte = capabilities.isCapable( 1276 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO); 1277 cap.utOverLte = capabilities.isCapable( 1278 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT); 1279 1280 } else if (radioTech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) { 1281 cap.voiceOverWifi = capabilities.isCapable( 1282 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE); 1283 cap.videoOverWifi = capabilities.isCapable( 1284 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO); 1285 cap.utOverWifi = capabilities.isCapable( 1286 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT); 1287 } 1288 1289 TelephonyEvent event = new TelephonyEventBuilder(phoneId).setImsCapabilities(cap).build(); 1290 1291 // If the capabilities don't change, we don't log the event. 1292 if (mLastImsCapabilities.get(phoneId) != null && 1293 Arrays.equals(ImsCapabilities.toByteArray(mLastImsCapabilities.get(phoneId)), 1294 ImsCapabilities.toByteArray(cap))) { 1295 return; 1296 } 1297 1298 mLastImsCapabilities.put(phoneId, cap); 1299 addTelephonyEvent(event); 1300 1301 annotateInProgressCallSession(event.timestampMillis, phoneId, 1302 new CallSessionEventBuilder( 1303 TelephonyCallSession.Event.Type.IMS_CAPABILITIES_CHANGED) 1304 .setImsCapabilities(event.imsCapabilities)); 1305 annotateInProgressSmsSession(event.timestampMillis, phoneId, 1306 new SmsSessionEventBuilder( 1307 SmsSession.Event.Type.IMS_CAPABILITIES_CHANGED) 1308 .setImsCapabilities(event.imsCapabilities)); 1309 } 1310 1311 /** 1312 * Convert PDP type into the enumeration 1313 * 1314 * @param type PDP type 1315 * @return The proto defined enumeration 1316 */ toPdpType(String type)1317 private int toPdpType(String type) { 1318 switch (type) { 1319 case "IP": 1320 return PDP_TYPE_IP; 1321 case "IPV6": 1322 return PDP_TYPE_IPV6; 1323 case "IPV4V6": 1324 return PDP_TYPE_IPV4V6; 1325 case "PPP": 1326 return PDP_TYPE_PPP; 1327 case "NON-IP": 1328 return PDP_TYPE_NON_IP; 1329 case "UNSTRUCTURED": 1330 return PDP_TYPE_UNSTRUCTURED; 1331 } 1332 Rlog.e(TAG, "Unknown type: " + type); 1333 return PDP_UNKNOWN; 1334 } 1335 1336 /** 1337 * Write setup data call event 1338 * 1339 * @param phoneId Phone id 1340 * @param radioTechnology The data call RAT 1341 * @param profileId Data profile id 1342 * @param apn APN in string 1343 * @param protocol Data connection protocol 1344 */ writeSetupDataCall(int phoneId, int radioTechnology, int profileId, String apn, int protocol)1345 public void writeSetupDataCall(int phoneId, int radioTechnology, int profileId, String apn, 1346 int protocol) { 1347 1348 RilSetupDataCall setupDataCall = new RilSetupDataCall(); 1349 setupDataCall.rat = radioTechnology; 1350 setupDataCall.dataProfile = profileId + 1; // off by 1 between proto and RIL constants. 1351 if (apn != null) { 1352 setupDataCall.apn = apn; 1353 } 1354 1355 setupDataCall.type = protocol + 1; 1356 1357 addTelephonyEvent(new TelephonyEventBuilder(phoneId).setSetupDataCall( 1358 setupDataCall).build()); 1359 } 1360 1361 /** 1362 * Write data call deactivate event 1363 * 1364 * @param phoneId Phone id 1365 * @param rilSerial RIL request serial number 1366 * @param cid call id 1367 * @param reason Deactivate reason 1368 */ writeRilDeactivateDataCall(int phoneId, int rilSerial, int cid, int reason)1369 public void writeRilDeactivateDataCall(int phoneId, int rilSerial, int cid, int reason) { 1370 1371 RilDeactivateDataCall deactivateDataCall = new RilDeactivateDataCall(); 1372 deactivateDataCall.cid = cid; 1373 switch (reason) { 1374 case DataService.REQUEST_REASON_NORMAL: 1375 deactivateDataCall.reason = DeactivateReason.DEACTIVATE_REASON_NONE; 1376 break; 1377 case DataService.REQUEST_REASON_SHUTDOWN: 1378 deactivateDataCall.reason = DeactivateReason.DEACTIVATE_REASON_RADIO_OFF; 1379 break; 1380 case DataService.REQUEST_REASON_HANDOVER: 1381 deactivateDataCall.reason = DeactivateReason.DEACTIVATE_REASON_HANDOVER; 1382 break; 1383 default: 1384 deactivateDataCall.reason = DeactivateReason.DEACTIVATE_REASON_UNKNOWN; 1385 } 1386 1387 addTelephonyEvent(new TelephonyEventBuilder(phoneId).setDeactivateDataCall( 1388 deactivateDataCall).build()); 1389 } 1390 1391 /** 1392 * Write data call list event when connected 1393 * @param phoneId Phone id 1394 * @param cid Context Id, uniquely identifies the call 1395 * @param apnTypeBitmask Bitmask of supported APN types 1396 * @param state State of the data call event 1397 */ writeRilDataCallEvent(int phoneId, int cid, int apnTypeBitmask, int state)1398 public void writeRilDataCallEvent(int phoneId, int cid, 1399 int apnTypeBitmask, int state) { 1400 RilDataCall[] dataCalls = new RilDataCall[1]; 1401 dataCalls[0] = new RilDataCall(); 1402 dataCalls[0].cid = cid; 1403 dataCalls[0].apnTypeBitmask = apnTypeBitmask; 1404 dataCalls[0].state = state; 1405 1406 SparseArray<RilDataCall> dataCallList; 1407 if (mLastRilDataCallEvents.get(phoneId) != null) { 1408 // If the Data call event does not change, do not log it. 1409 if (mLastRilDataCallEvents.get(phoneId).get(cid) != null 1410 && Arrays.equals( 1411 RilDataCall.toByteArray(mLastRilDataCallEvents.get(phoneId).get(cid)), 1412 RilDataCall.toByteArray(dataCalls[0]))) { 1413 return; 1414 } 1415 dataCallList = mLastRilDataCallEvents.get(phoneId); 1416 } else { 1417 dataCallList = new SparseArray<>(); 1418 } 1419 1420 dataCallList.put(cid, dataCalls[0]); 1421 mLastRilDataCallEvents.put(phoneId, dataCallList); 1422 addTelephonyEvent(new TelephonyEventBuilder(phoneId).setDataCalls(dataCalls).build()); 1423 } 1424 1425 /** 1426 * Write CS call list event 1427 * 1428 * @param phoneId Phone id 1429 * @param connections Array of GsmCdmaConnection objects 1430 */ writeRilCallList(int phoneId, ArrayList<GsmCdmaConnection> connections, String countryIso)1431 public void writeRilCallList(int phoneId, ArrayList<GsmCdmaConnection> connections, 1432 String countryIso) { 1433 logv("Logging CallList Changed Connections Size = " + connections.size()); 1434 InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId); 1435 if (callSession == null) { 1436 Rlog.e(TAG, "writeRilCallList: Call session is missing"); 1437 } else { 1438 RilCall[] calls = convertConnectionsToRilCalls(connections, countryIso); 1439 callSession.addEvent( 1440 new CallSessionEventBuilder( 1441 TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED) 1442 .setRilCalls(calls) 1443 ); 1444 logv("Logged Call list changed"); 1445 if (callSession.isPhoneIdle() && disconnectReasonsKnown(calls)) { 1446 finishCallSession(callSession); 1447 } 1448 } 1449 } 1450 disconnectReasonsKnown(RilCall[] calls)1451 private boolean disconnectReasonsKnown(RilCall[] calls) { 1452 for (RilCall call : calls) { 1453 if (call.callEndReason == 0) return false; 1454 } 1455 return true; 1456 } 1457 convertConnectionsToRilCalls(ArrayList<GsmCdmaConnection> mConnections, String countryIso)1458 private RilCall[] convertConnectionsToRilCalls(ArrayList<GsmCdmaConnection> mConnections, 1459 String countryIso) { 1460 RilCall[] calls = new RilCall[mConnections.size()]; 1461 for (int i = 0; i < mConnections.size(); i++) { 1462 calls[i] = new RilCall(); 1463 calls[i].index = i; 1464 convertConnectionToRilCall(mConnections.get(i), calls[i], countryIso); 1465 } 1466 return calls; 1467 } 1468 convertEmergencyNumberToEmergencyNumberInfo(EmergencyNumber num)1469 private EmergencyNumberInfo convertEmergencyNumberToEmergencyNumberInfo(EmergencyNumber num) { 1470 EmergencyNumberInfo emergencyNumberInfo = new EmergencyNumberInfo(); 1471 emergencyNumberInfo.address = num.getNumber(); 1472 emergencyNumberInfo.countryIso = num.getCountryIso(); 1473 emergencyNumberInfo.mnc = num.getMnc(); 1474 emergencyNumberInfo.serviceCategoriesBitmask = num.getEmergencyServiceCategoryBitmask(); 1475 emergencyNumberInfo.urns = num.getEmergencyUrns().stream().toArray(String[]::new); 1476 emergencyNumberInfo.numberSourcesBitmask = num.getEmergencyNumberSourceBitmask(); 1477 emergencyNumberInfo.routing = num.getEmergencyCallRouting(); 1478 return emergencyNumberInfo; 1479 } 1480 convertConnectionToRilCall(GsmCdmaConnection conn, RilCall call, String countryIso)1481 private void convertConnectionToRilCall(GsmCdmaConnection conn, RilCall call, 1482 String countryIso) { 1483 if (conn.isIncoming()) { 1484 call.type = Type.MT; 1485 } else { 1486 call.type = Type.MO; 1487 } 1488 switch (conn.getState()) { 1489 case IDLE: 1490 call.state = CallState.CALL_IDLE; 1491 break; 1492 case ACTIVE: 1493 call.state = CallState.CALL_ACTIVE; 1494 break; 1495 case HOLDING: 1496 call.state = CallState.CALL_HOLDING; 1497 break; 1498 case DIALING: 1499 call.state = CallState.CALL_DIALING; 1500 break; 1501 case ALERTING: 1502 call.state = CallState.CALL_ALERTING; 1503 break; 1504 case INCOMING: 1505 call.state = CallState.CALL_INCOMING; 1506 break; 1507 case WAITING: 1508 call.state = CallState.CALL_WAITING; 1509 break; 1510 case DISCONNECTED: 1511 call.state = CallState.CALL_DISCONNECTED; 1512 break; 1513 case DISCONNECTING: 1514 call.state = CallState.CALL_DISCONNECTING; 1515 break; 1516 default: 1517 call.state = CallState.CALL_UNKNOWN; 1518 break; 1519 } 1520 call.callEndReason = conn.getDisconnectCause(); 1521 call.isMultiparty = conn.isMultiparty(); 1522 call.preciseDisconnectCause = conn.getPreciseDisconnectCause(); 1523 1524 // Emergency call metrics when call ends 1525 if (conn.getDisconnectCause() != DisconnectCause.NOT_DISCONNECTED 1526 && conn.isEmergencyCall() && conn.getEmergencyNumberInfo() != null) { 1527 /** Only collect this emergency number information per sample percentage */ 1528 if (ThreadLocalRandom.current().nextDouble(0, 100) 1529 < getSamplePercentageForEmergencyCall(countryIso)) { 1530 call.isEmergencyCall = conn.isEmergencyCall(); 1531 call.emergencyNumberInfo = convertEmergencyNumberToEmergencyNumberInfo( 1532 conn.getEmergencyNumberInfo()); 1533 } 1534 } 1535 } 1536 1537 /** 1538 * Write dial event 1539 * 1540 * @param phoneId Phone id 1541 * @param conn Connection object created to track this call 1542 * @param clirMode CLIR (Calling Line Identification Restriction) mode 1543 * @param uusInfo User-to-User signaling Info 1544 */ writeRilDial(int phoneId, GsmCdmaConnection conn, int clirMode, UUSInfo uusInfo)1545 public void writeRilDial(int phoneId, GsmCdmaConnection conn, int clirMode, UUSInfo uusInfo) { 1546 1547 InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId); 1548 logv("Logging Dial Connection = " + conn); 1549 if (callSession == null) { 1550 Rlog.e(TAG, "writeRilDial: Call session is missing"); 1551 } else { 1552 RilCall[] calls = new RilCall[1]; 1553 calls[0] = new RilCall(); 1554 calls[0].index = -1; 1555 convertConnectionToRilCall(conn, calls[0], ""); 1556 callSession.addEvent(callSession.startElapsedTimeMs, 1557 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST) 1558 .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL) 1559 .setRilCalls(calls)); 1560 logv("Logged Dial event"); 1561 } 1562 } 1563 1564 /** 1565 * Write incoming call event 1566 * 1567 * @param phoneId Phone id 1568 * @param response Unused today 1569 */ writeRilCallRing(int phoneId, char[] response)1570 public void writeRilCallRing(int phoneId, char[] response) { 1571 InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId); 1572 1573 callSession.addEvent(callSession.startElapsedTimeMs, 1574 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_CALL_RING)); 1575 } 1576 1577 /** 1578 * Write call hangup event 1579 * 1580 * @param phoneId Phone id 1581 * @param conn Connection object associated with the call that is being hung-up 1582 * @param callId Call id 1583 */ writeRilHangup(int phoneId, GsmCdmaConnection conn, int callId, String countryIso)1584 public void writeRilHangup(int phoneId, GsmCdmaConnection conn, int callId, 1585 String countryIso) { 1586 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 1587 if (callSession == null) { 1588 Rlog.e(TAG, "writeRilHangup: Call session is missing"); 1589 } else { 1590 RilCall[] calls = new RilCall[1]; 1591 calls[0] = new RilCall(); 1592 calls[0].index = callId; 1593 convertConnectionToRilCall(conn, calls[0], countryIso); 1594 callSession.addEvent( 1595 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST) 1596 .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_HANGUP) 1597 .setRilCalls(calls)); 1598 logv("Logged Hangup event"); 1599 } 1600 } 1601 1602 /** 1603 * Write call answer event 1604 * 1605 * @param phoneId Phone id 1606 * @param rilSerial RIL request serial number 1607 */ writeRilAnswer(int phoneId, int rilSerial)1608 public void writeRilAnswer(int phoneId, int rilSerial) { 1609 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 1610 if (callSession == null) { 1611 Rlog.e(TAG, "writeRilAnswer: Call session is missing"); 1612 } else { 1613 callSession.addEvent( 1614 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST) 1615 .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_ANSWER) 1616 .setRilRequestId(rilSerial)); 1617 } 1618 } 1619 1620 /** 1621 * Write IMS call SRVCC event 1622 * 1623 * @param phoneId Phone id 1624 * @param rilSrvccState SRVCC state 1625 */ writeRilSrvcc(int phoneId, int rilSrvccState)1626 public void writeRilSrvcc(int phoneId, int rilSrvccState) { 1627 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 1628 if (callSession == null) { 1629 Rlog.e(TAG, "writeRilSrvcc: Call session is missing"); 1630 } else { 1631 callSession.addEvent( 1632 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_CALL_SRVCC) 1633 .setSrvccState(rilSrvccState + 1)); 1634 } 1635 } 1636 1637 /** 1638 * Convert RIL request into proto defined RIL request 1639 * 1640 * @param r RIL request 1641 * @return RIL request defined in call session proto 1642 */ toCallSessionRilRequest(int r)1643 private int toCallSessionRilRequest(int r) { 1644 switch (r) { 1645 case RILConstants.RIL_REQUEST_DIAL: 1646 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL; 1647 1648 case RILConstants.RIL_REQUEST_ANSWER: 1649 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_ANSWER; 1650 1651 case RILConstants.RIL_REQUEST_HANGUP: 1652 case RILConstants.RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: 1653 case RILConstants.RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: 1654 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_HANGUP; 1655 1656 case RILConstants.RIL_REQUEST_SET_CALL_WAITING: 1657 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_SET_CALL_WAITING; 1658 1659 case RILConstants.RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: 1660 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE; 1661 1662 case RILConstants.RIL_REQUEST_CDMA_FLASH: 1663 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_CDMA_FLASH; 1664 1665 case RILConstants.RIL_REQUEST_CONFERENCE: 1666 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_CONFERENCE; 1667 } 1668 Rlog.e(TAG, "Unknown RIL request: " + r); 1669 return TelephonyCallSession.Event.RilRequest.RIL_REQUEST_UNKNOWN; 1670 } 1671 1672 /** 1673 * Write setup data call response event 1674 * 1675 * @param phoneId Phone id 1676 * @param rilSerial RIL request serial number 1677 * @param rilError RIL error 1678 * @param rilRequest RIL request 1679 * @param result Data call result 1680 */ writeOnSetupDataCallResponse(int phoneId, int rilSerial, int rilError, int rilRequest, DataCallResponse response)1681 private void writeOnSetupDataCallResponse(int phoneId, int rilSerial, int rilError, 1682 int rilRequest, DataCallResponse response) { 1683 1684 RilSetupDataCallResponse setupDataCallResponse = new RilSetupDataCallResponse(); 1685 RilDataCall dataCall = new RilDataCall(); 1686 1687 if (response != null) { 1688 setupDataCallResponse.status = (response.getCause() == 0 1689 ? RilDataCallFailCause.PDP_FAIL_NONE : response.getCause()); 1690 setupDataCallResponse.suggestedRetryTimeMillis = response.getSuggestedRetryTime(); 1691 1692 dataCall.cid = response.getId(); 1693 dataCall.type = response.getProtocolType() + 1; 1694 1695 if (!TextUtils.isEmpty(response.getInterfaceName())) { 1696 dataCall.iframe = response.getInterfaceName(); 1697 } 1698 } 1699 setupDataCallResponse.call = dataCall; 1700 1701 addTelephonyEvent(new TelephonyEventBuilder(phoneId) 1702 .setSetupDataCallResponse(setupDataCallResponse).build()); 1703 } 1704 1705 /** 1706 * Write call related solicited response event 1707 * 1708 * @param phoneId Phone id 1709 * @param rilSerial RIL request serial number 1710 * @param rilError RIL error 1711 * @param rilRequest RIL request 1712 */ writeOnCallSolicitedResponse(int phoneId, int rilSerial, int rilError, int rilRequest)1713 private void writeOnCallSolicitedResponse(int phoneId, int rilSerial, int rilError, 1714 int rilRequest) { 1715 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 1716 if (callSession == null) { 1717 Rlog.e(TAG, "writeOnCallSolicitedResponse: Call session is missing"); 1718 } else { 1719 callSession.addEvent(new CallSessionEventBuilder( 1720 TelephonyCallSession.Event.Type.RIL_RESPONSE) 1721 .setRilRequest(toCallSessionRilRequest(rilRequest)) 1722 .setRilRequestId(rilSerial) 1723 .setRilError(rilError + 1)); 1724 } 1725 } 1726 1727 /** 1728 * Write SMS related solicited response event 1729 * 1730 * @param phoneId Phone id 1731 * @param rilSerial RIL request serial number 1732 * @param rilError RIL error 1733 * @param response SMS response 1734 */ writeOnSmsSolicitedResponse(int phoneId, int rilSerial, int rilError, SmsResponse response)1735 private synchronized void writeOnSmsSolicitedResponse(int phoneId, int rilSerial, int rilError, 1736 SmsResponse response) { 1737 1738 InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId); 1739 if (smsSession == null) { 1740 Rlog.e(TAG, "SMS session is missing"); 1741 } else { 1742 1743 int errorCode = 0; 1744 if (response != null) { 1745 errorCode = response.mErrorCode; 1746 } 1747 1748 smsSession.addEvent(new SmsSessionEventBuilder( 1749 SmsSession.Event.Type.SMS_SEND_RESULT) 1750 .setErrorCode(errorCode) 1751 .setRilErrno(rilError + 1) 1752 .setRilRequestId(rilSerial) 1753 ); 1754 1755 smsSession.decreaseExpectedResponse(); 1756 finishSmsSessionIfNeeded(smsSession); 1757 } 1758 } 1759 1760 /** 1761 * Write SMS related solicited response event 1762 * 1763 * @param phoneId Phone id 1764 * @param errorReason Defined in {@link SmsManager} RESULT_XXX. 1765 */ writeOnImsServiceSmsSolicitedResponse(int phoneId, @ImsSmsImplBase.SendStatusResult int resultCode, int errorReason)1766 public synchronized void writeOnImsServiceSmsSolicitedResponse(int phoneId, 1767 @ImsSmsImplBase.SendStatusResult int resultCode, int errorReason) { 1768 1769 InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId); 1770 if (smsSession == null) { 1771 Rlog.e(TAG, "SMS session is missing"); 1772 } else { 1773 1774 smsSession.addEvent(new SmsSessionEventBuilder( 1775 SmsSession.Event.Type.SMS_SEND_RESULT) 1776 .setImsServiceErrno(resultCode) 1777 .setErrorCode(errorReason) 1778 ); 1779 1780 smsSession.decreaseExpectedResponse(); 1781 finishSmsSessionIfNeeded(smsSession); 1782 } 1783 } 1784 1785 /** 1786 * Write deactivate data call response event 1787 * 1788 * @param phoneId Phone id 1789 * @param rilError RIL error 1790 */ writeOnDeactivateDataCallResponse(int phoneId, int rilError)1791 private void writeOnDeactivateDataCallResponse(int phoneId, int rilError) { 1792 addTelephonyEvent(new TelephonyEventBuilder(phoneId) 1793 .setDeactivateDataCallResponse(rilError + 1).build()); 1794 } 1795 1796 /** 1797 * Write RIL solicited response event 1798 * 1799 * @param phoneId Phone id 1800 * @param rilSerial RIL request serial number 1801 * @param rilError RIL error 1802 * @param rilRequest RIL request 1803 * @param ret The returned RIL response 1804 */ writeOnRilSolicitedResponse(int phoneId, int rilSerial, int rilError, int rilRequest, Object ret)1805 public void writeOnRilSolicitedResponse(int phoneId, int rilSerial, int rilError, 1806 int rilRequest, Object ret) { 1807 switch (rilRequest) { 1808 case RIL_REQUEST_SETUP_DATA_CALL: 1809 DataCallResponse response = (DataCallResponse) ret; 1810 writeOnSetupDataCallResponse(phoneId, rilSerial, rilError, rilRequest, response); 1811 break; 1812 case RIL_REQUEST_DEACTIVATE_DATA_CALL: 1813 writeOnDeactivateDataCallResponse(phoneId, rilError); 1814 break; 1815 case RIL_REQUEST_HANGUP: 1816 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: 1817 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: 1818 case RIL_REQUEST_DIAL: 1819 case RIL_REQUEST_ANSWER: 1820 writeOnCallSolicitedResponse(phoneId, rilSerial, rilError, rilRequest); 1821 break; 1822 case RIL_REQUEST_SEND_SMS: 1823 case RIL_REQUEST_SEND_SMS_EXPECT_MORE: 1824 case RIL_REQUEST_CDMA_SEND_SMS: 1825 case RIL_REQUEST_IMS_SEND_SMS: 1826 SmsResponse smsResponse = (SmsResponse) ret; 1827 writeOnSmsSolicitedResponse(phoneId, rilSerial, rilError, smsResponse); 1828 break; 1829 } 1830 } 1831 1832 /** 1833 * Write network validation event. 1834 * @param networkValidationState the network validation state. 1835 */ writeNetworkValidate(int networkValidationState)1836 public void writeNetworkValidate(int networkValidationState) { 1837 addTelephonyEvent( 1838 new TelephonyEventBuilder().setNetworkValidate(networkValidationState).build()); 1839 } 1840 1841 /** 1842 * Write data switch event. 1843 * @param subId data switch to the subscription with this id. 1844 * @param dataSwitch the reason and state of data switch. 1845 */ writeDataSwitch(int subId, DataSwitch dataSwitch)1846 public void writeDataSwitch(int subId, DataSwitch dataSwitch) { 1847 int phoneId = SubscriptionManager.getPhoneId(subId); 1848 addTelephonyEvent(new TelephonyEventBuilder(phoneId).setDataSwitch(dataSwitch).build()); 1849 } 1850 1851 /** 1852 * Write on demand data switch event. 1853 * @param onDemandDataSwitch the apn and state of on demand data switch. 1854 */ writeOnDemandDataSwitch(OnDemandDataSwitch onDemandDataSwitch)1855 public void writeOnDemandDataSwitch(OnDemandDataSwitch onDemandDataSwitch) { 1856 addTelephonyEvent( 1857 new TelephonyEventBuilder().setOnDemandDataSwitch(onDemandDataSwitch).build()); 1858 } 1859 1860 /** 1861 * Write phone state changed event 1862 * 1863 * @param phoneId Phone id 1864 * @param phoneState Phone state. See PhoneConstants.State for the details. 1865 */ writePhoneState(int phoneId, PhoneConstants.State phoneState)1866 public void writePhoneState(int phoneId, PhoneConstants.State phoneState) { 1867 int state; 1868 switch (phoneState) { 1869 case IDLE: 1870 state = TelephonyCallSession.Event.PhoneState.STATE_IDLE; 1871 break; 1872 case RINGING: 1873 state = TelephonyCallSession.Event.PhoneState.STATE_RINGING; 1874 break; 1875 case OFFHOOK: 1876 state = TelephonyCallSession.Event.PhoneState.STATE_OFFHOOK; 1877 break; 1878 default: 1879 state = TelephonyCallSession.Event.PhoneState.STATE_UNKNOWN; 1880 break; 1881 } 1882 1883 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 1884 if (callSession == null) { 1885 Rlog.e(TAG, "writePhoneState: Call session is missing"); 1886 } else { 1887 // For CS Calls Finish the Call Session after Receiving the Last Call Fail Cause 1888 // For IMS calls we receive the Disconnect Cause along with Call End event. 1889 // So we can finish the call session here. 1890 callSession.setLastKnownPhoneState(state); 1891 if ((state == TelephonyCallSession.Event.PhoneState.STATE_IDLE) 1892 && (!callSession.containsCsCalls())) { 1893 finishCallSession(callSession); 1894 } 1895 callSession.addEvent(new CallSessionEventBuilder( 1896 TelephonyCallSession.Event.Type.PHONE_STATE_CHANGED) 1897 .setPhoneState(state)); 1898 } 1899 } 1900 1901 /** 1902 * Extracts the call ID from an ImsSession. 1903 * 1904 * @param session The session. 1905 * @return The call ID for the session, or -1 if none was found. 1906 */ getCallId(ImsCallSession session)1907 private int getCallId(ImsCallSession session) { 1908 if (session == null) { 1909 return -1; 1910 } 1911 1912 try { 1913 return Integer.parseInt(session.getCallId()); 1914 } catch (NumberFormatException nfe) { 1915 return -1; 1916 } 1917 } 1918 1919 /** 1920 * Write IMS call state changed event 1921 * 1922 * @param phoneId Phone id 1923 * @param session IMS call session 1924 * @param callState IMS call state 1925 */ writeImsCallState(int phoneId, ImsCallSession session, ImsPhoneCall.State callState)1926 public void writeImsCallState(int phoneId, ImsCallSession session, 1927 ImsPhoneCall.State callState) { 1928 int state; 1929 switch (callState) { 1930 case IDLE: 1931 state = TelephonyCallSession.Event.CallState.CALL_IDLE; break; 1932 case ACTIVE: 1933 state = TelephonyCallSession.Event.CallState.CALL_ACTIVE; break; 1934 case HOLDING: 1935 state = TelephonyCallSession.Event.CallState.CALL_HOLDING; break; 1936 case DIALING: 1937 state = TelephonyCallSession.Event.CallState.CALL_DIALING; break; 1938 case ALERTING: 1939 state = TelephonyCallSession.Event.CallState.CALL_ALERTING; break; 1940 case INCOMING: 1941 state = TelephonyCallSession.Event.CallState.CALL_INCOMING; break; 1942 case WAITING: 1943 state = TelephonyCallSession.Event.CallState.CALL_WAITING; break; 1944 case DISCONNECTED: 1945 state = TelephonyCallSession.Event.CallState.CALL_DISCONNECTED; break; 1946 case DISCONNECTING: 1947 state = TelephonyCallSession.Event.CallState.CALL_DISCONNECTING; break; 1948 default: 1949 state = TelephonyCallSession.Event.CallState.CALL_UNKNOWN; break; 1950 } 1951 1952 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 1953 if (callSession == null) { 1954 Rlog.e(TAG, "Call session is missing"); 1955 } else { 1956 callSession.addEvent(new CallSessionEventBuilder( 1957 TelephonyCallSession.Event.Type.IMS_CALL_STATE_CHANGED) 1958 .setCallIndex(getCallId(session)) 1959 .setCallState(state)); 1960 } 1961 } 1962 1963 /** 1964 * Write IMS call start event 1965 * 1966 * @param phoneId Phone id 1967 * @param session IMS call session 1968 */ writeOnImsCallStart(int phoneId, ImsCallSession session)1969 public void writeOnImsCallStart(int phoneId, ImsCallSession session) { 1970 InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId); 1971 1972 callSession.addEvent( 1973 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_COMMAND) 1974 .setCallIndex(getCallId(session)) 1975 .setImsCommand(TelephonyCallSession.Event.ImsCommand.IMS_CMD_START)); 1976 } 1977 1978 /** 1979 * Write IMS incoming call event 1980 * 1981 * @param phoneId Phone id 1982 * @param session IMS call session 1983 */ writeOnImsCallReceive(int phoneId, ImsCallSession session)1984 public void writeOnImsCallReceive(int phoneId, ImsCallSession session) { 1985 InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId); 1986 1987 callSession.addEvent( 1988 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_CALL_RECEIVE) 1989 .setCallIndex(getCallId(session))); 1990 } 1991 1992 /** 1993 * Write IMS command event 1994 * 1995 * @param phoneId Phone id 1996 * @param session IMS call session 1997 * @param command IMS command 1998 */ writeOnImsCommand(int phoneId, ImsCallSession session, int command)1999 public void writeOnImsCommand(int phoneId, ImsCallSession session, int command) { 2000 2001 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 2002 if (callSession == null) { 2003 Rlog.e(TAG, "Call session is missing"); 2004 } else { 2005 callSession.addEvent( 2006 new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_COMMAND) 2007 .setCallIndex(getCallId(session)) 2008 .setImsCommand(command)); 2009 } 2010 } 2011 2012 /** 2013 * Convert IMS reason info into proto 2014 * 2015 * @param reasonInfo IMS reason info 2016 * @return Converted proto 2017 */ toImsReasonInfoProto(ImsReasonInfo reasonInfo)2018 private TelephonyProto.ImsReasonInfo toImsReasonInfoProto(ImsReasonInfo reasonInfo) { 2019 TelephonyProto.ImsReasonInfo ri = new TelephonyProto.ImsReasonInfo(); 2020 if (reasonInfo != null) { 2021 ri.reasonCode = reasonInfo.getCode(); 2022 ri.extraCode = reasonInfo.getExtraCode(); 2023 String extraMessage = reasonInfo.getExtraMessage(); 2024 if (extraMessage != null) { 2025 ri.extraMessage = extraMessage; 2026 } 2027 } 2028 return ri; 2029 } 2030 2031 /** 2032 * Convert CallQuality to proto. 2033 * 2034 * @param callQuality call quality to convert 2035 * @return Coverted proto 2036 */ toCallQualityProto( CallQuality callQuality)2037 public static TelephonyCallSession.Event.CallQuality toCallQualityProto( 2038 CallQuality callQuality) { 2039 TelephonyCallSession.Event.CallQuality cq = new TelephonyCallSession.Event.CallQuality(); 2040 if (callQuality != null) { 2041 cq.downlinkLevel = callQualityLevelToProtoEnum(callQuality 2042 .getDownlinkCallQualityLevel()); 2043 cq.uplinkLevel = callQualityLevelToProtoEnum(callQuality.getUplinkCallQualityLevel()); 2044 // callDuration is reported in millis, so convert to seconds 2045 cq.durationInSeconds = callQuality.getCallDuration() / 1000; 2046 cq.rtpPacketsTransmitted = callQuality.getNumRtpPacketsTransmitted(); 2047 cq.rtpPacketsReceived = callQuality.getNumRtpPacketsReceived(); 2048 cq.rtpPacketsTransmittedLost = callQuality.getNumRtpPacketsTransmittedLost(); 2049 cq.rtpPacketsNotReceived = callQuality.getNumRtpPacketsNotReceived(); 2050 cq.averageRelativeJitterMillis = callQuality.getAverageRelativeJitter(); 2051 cq.maxRelativeJitterMillis = callQuality.getMaxRelativeJitter(); 2052 cq.codecType = convertImsCodec(callQuality.getCodecType()); 2053 } 2054 return cq; 2055 } 2056 2057 /** 2058 * Convert Call quality level into proto defined value. 2059 */ callQualityLevelToProtoEnum(int level)2060 private static int callQualityLevelToProtoEnum(int level) { 2061 if (level == CallQuality.CALL_QUALITY_EXCELLENT) { 2062 return TelephonyCallSession.Event.CallQuality.CallQualityLevel.EXCELLENT; 2063 } else if (level == CallQuality.CALL_QUALITY_GOOD) { 2064 return TelephonyCallSession.Event.CallQuality.CallQualityLevel.GOOD; 2065 } else if (level == CallQuality.CALL_QUALITY_FAIR) { 2066 return TelephonyCallSession.Event.CallQuality.CallQualityLevel.FAIR; 2067 } else if (level == CallQuality.CALL_QUALITY_POOR) { 2068 return TelephonyCallSession.Event.CallQuality.CallQualityLevel.POOR; 2069 } else if (level == CallQuality.CALL_QUALITY_BAD) { 2070 return TelephonyCallSession.Event.CallQuality.CallQualityLevel.BAD; 2071 } else if (level == CallQuality.CALL_QUALITY_NOT_AVAILABLE) { 2072 return TelephonyCallSession.Event.CallQuality.CallQualityLevel.NOT_AVAILABLE; 2073 } else { 2074 return TelephonyCallSession.Event.CallQuality.CallQualityLevel.UNDEFINED; 2075 } 2076 } 2077 2078 /** 2079 * Write IMS call end event 2080 * 2081 * @param phoneId Phone id 2082 * @param session IMS call session 2083 * @param reasonInfo Call end reason 2084 */ writeOnImsCallTerminated(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo, CallQualityMetrics cqm, EmergencyNumber emergencyNumber, String countryIso)2085 public void writeOnImsCallTerminated(int phoneId, ImsCallSession session, 2086 ImsReasonInfo reasonInfo, CallQualityMetrics cqm, 2087 EmergencyNumber emergencyNumber, String countryIso) { 2088 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 2089 if (callSession == null) { 2090 Rlog.e(TAG, "Call session is missing"); 2091 } else { 2092 CallSessionEventBuilder callSessionEvent = new CallSessionEventBuilder( 2093 TelephonyCallSession.Event.Type.IMS_CALL_TERMINATED); 2094 callSessionEvent.setCallIndex(getCallId(session)); 2095 callSessionEvent.setImsReasonInfo(toImsReasonInfoProto(reasonInfo)); 2096 2097 if (cqm != null) { 2098 callSessionEvent.setCallQualitySummaryDl(cqm.getCallQualitySummaryDl()) 2099 .setCallQualitySummaryUl(cqm.getCallQualitySummaryUl()); 2100 } 2101 2102 if (emergencyNumber != null) { 2103 /** Only collect this emergency number information per sample percentage */ 2104 if (ThreadLocalRandom.current().nextDouble(0, 100) 2105 < getSamplePercentageForEmergencyCall(countryIso)) { 2106 callSessionEvent.setIsImsEmergencyCall(true); 2107 callSessionEvent.setImsEmergencyNumberInfo( 2108 convertEmergencyNumberToEmergencyNumberInfo(emergencyNumber)); 2109 } 2110 } 2111 callSession.addEvent(callSessionEvent); 2112 } 2113 } 2114 2115 /** 2116 * Write IMS call hangover event 2117 * 2118 * @param phoneId Phone id 2119 * @param eventType hangover type 2120 * @param session IMS call session 2121 * @param srcAccessTech Hangover starting RAT 2122 * @param targetAccessTech Hangover destination RAT 2123 * @param reasonInfo Hangover reason 2124 */ writeOnImsCallHandoverEvent(int phoneId, int eventType, ImsCallSession session, int srcAccessTech, int targetAccessTech, ImsReasonInfo reasonInfo)2125 public void writeOnImsCallHandoverEvent(int phoneId, int eventType, ImsCallSession session, 2126 int srcAccessTech, int targetAccessTech, 2127 ImsReasonInfo reasonInfo) { 2128 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 2129 if (callSession == null) { 2130 Rlog.e(TAG, "Call session is missing"); 2131 } else { 2132 callSession.addEvent( 2133 new CallSessionEventBuilder(eventType) 2134 .setCallIndex(getCallId(session)) 2135 .setSrcAccessTech(srcAccessTech) 2136 .setTargetAccessTech(targetAccessTech) 2137 .setImsReasonInfo(toImsReasonInfoProto(reasonInfo))); 2138 } 2139 } 2140 2141 /** 2142 * Write Send SMS event 2143 * 2144 * @param phoneId Phone id 2145 * @param rilSerial RIL request serial number 2146 * @param tech SMS RAT 2147 * @param format SMS format. Either 3GPP or 3GPP2. 2148 */ writeRilSendSms(int phoneId, int rilSerial, int tech, int format)2149 public synchronized void writeRilSendSms(int phoneId, int rilSerial, int tech, int format) { 2150 InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId); 2151 2152 smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_SEND) 2153 .setTech(tech) 2154 .setRilRequestId(rilSerial) 2155 .setFormat(format) 2156 ); 2157 2158 smsSession.increaseExpectedResponse(); 2159 } 2160 2161 /** 2162 * Write Send SMS event using ImsService. Expecting response from 2163 * {@link #writeOnSmsSolicitedResponse}. 2164 * 2165 * @param phoneId Phone id 2166 * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or 2167 * {@link SmsMessage#FORMAT_3GPP2}. 2168 * @param resultCode The result of sending the new SMS to the vendor layer to be sent to the 2169 * carrier network. 2170 */ writeImsServiceSendSms(int phoneId, String format, @ImsSmsImplBase.SendStatusResult int resultCode)2171 public synchronized void writeImsServiceSendSms(int phoneId, String format, 2172 @ImsSmsImplBase.SendStatusResult int resultCode) { 2173 InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId); 2174 smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_SEND) 2175 .setTech(SmsSession.Event.Tech.SMS_IMS) 2176 .setImsServiceErrno(resultCode) 2177 .setFormat(convertSmsFormat(format)) 2178 ); 2179 2180 smsSession.increaseExpectedResponse(); 2181 } 2182 2183 /** 2184 * Write incoming Broadcast SMS event 2185 * 2186 * @param phoneId Phone id 2187 * @param format CB msg format 2188 * @param priority CB msg priority 2189 * @param isCMAS true if msg is CMAS 2190 * @param isETWS true if msg is ETWS 2191 * @param serviceCategory Service category of CB msg 2192 * @param serialNumber Serial number of the message 2193 * @param deliveredTimestamp Message's delivered timestamp 2194 */ writeNewCBSms(int phoneId, int format, int priority, boolean isCMAS, boolean isETWS, int serviceCategory, int serialNumber, long deliveredTimestamp)2195 public synchronized void writeNewCBSms(int phoneId, int format, int priority, boolean isCMAS, 2196 boolean isETWS, int serviceCategory, int serialNumber, 2197 long deliveredTimestamp) { 2198 InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId); 2199 2200 int type; 2201 if (isCMAS) { 2202 type = SmsSession.Event.CBMessageType.CMAS; 2203 } else if (isETWS) { 2204 type = SmsSession.Event.CBMessageType.ETWS; 2205 } else { 2206 type = SmsSession.Event.CBMessageType.OTHER; 2207 } 2208 2209 SmsSession.Event.CBMessage cbm = new SmsSession.Event.CBMessage(); 2210 cbm.msgFormat = format; 2211 cbm.msgPriority = priority + 1; 2212 cbm.msgType = type; 2213 cbm.serviceCategory = serviceCategory; 2214 cbm.serialNumber = serialNumber; 2215 cbm.deliveredTimestampMillis = deliveredTimestamp; 2216 2217 smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.CB_SMS_RECEIVED) 2218 .setCellBroadcastMessage(cbm) 2219 ); 2220 2221 finishSmsSessionIfNeeded(smsSession); 2222 } 2223 2224 /** 2225 * Write an incoming multi-part SMS that was discarded because some parts were missing 2226 * 2227 * @param phoneId Phone id 2228 * @param format SMS format. Either 3GPP or 3GPP2. 2229 * @param receivedCount Number of received parts. 2230 * @param totalCount Total number of parts of the SMS. 2231 */ writeDroppedIncomingMultipartSms(int phoneId, String format, int receivedCount, int totalCount)2232 public void writeDroppedIncomingMultipartSms(int phoneId, String format, 2233 int receivedCount, int totalCount) { 2234 logv("Logged dropped multipart SMS: received " + receivedCount 2235 + " out of " + totalCount); 2236 2237 SmsSession.Event.IncompleteSms details = new SmsSession.Event.IncompleteSms(); 2238 details.receivedParts = receivedCount; 2239 details.totalParts = totalCount; 2240 2241 InProgressSmsSession smsSession = startNewSmsSession(phoneId); 2242 smsSession.addEvent( 2243 new SmsSessionEventBuilder(SmsSession.Event.Type.INCOMPLETE_SMS_RECEIVED) 2244 .setFormat(convertSmsFormat(format)) 2245 .setIncompleteSms(details)); 2246 2247 finishSmsSession(smsSession); 2248 } 2249 2250 /** 2251 * Write a generic SMS of any type 2252 * 2253 * @param phoneId Phone id 2254 * @param type Type of the SMS. 2255 * @param format SMS format. Either 3GPP or 3GPP2. 2256 * @param success Indicates if the SMS-PP was successfully delivered to the USIM. 2257 */ writeIncomingSmsWithType(int phoneId, int type, String format, boolean success)2258 private void writeIncomingSmsWithType(int phoneId, int type, String format, boolean success) { 2259 InProgressSmsSession smsSession = startNewSmsSession(phoneId); 2260 smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_RECEIVED) 2261 .setFormat(convertSmsFormat(format)) 2262 .setSmsType(type) 2263 .setErrorCode(success ? SmsManager.RESULT_ERROR_NONE : 2264 SmsManager.RESULT_ERROR_GENERIC_FAILURE)); 2265 finishSmsSession(smsSession); 2266 } 2267 2268 /** 2269 * Write an incoming SMS-PP for the USIM 2270 * 2271 * @param phoneId Phone id 2272 * @param format SMS format. Either 3GPP or 3GPP2. 2273 * @param success Indicates if the SMS-PP was successfully delivered to the USIM. 2274 */ writeIncomingSMSPP(int phoneId, String format, boolean success)2275 public void writeIncomingSMSPP(int phoneId, String format, boolean success) { 2276 logv("Logged SMS-PP session. Result = " + success); 2277 writeIncomingSmsWithType(phoneId, 2278 SmsSession.Event.SmsType.SMS_TYPE_SMS_PP, format, success); 2279 } 2280 2281 /** 2282 * Write an incoming SMS to update voicemail indicator 2283 * 2284 * @param phoneId Phone id 2285 * @param format SMS format. Either 3GPP or 3GPP2. 2286 */ writeIncomingVoiceMailSms(int phoneId, String format)2287 public void writeIncomingVoiceMailSms(int phoneId, String format) { 2288 logv("Logged VoiceMail message."); 2289 writeIncomingSmsWithType(phoneId, 2290 SmsSession.Event.SmsType.SMS_TYPE_VOICEMAIL_INDICATION, format, true); 2291 } 2292 2293 /** 2294 * Write an incoming SMS of type 0 2295 * 2296 * @param phoneId Phone id 2297 * @param format SMS format. Either 3GPP or 3GPP2. 2298 */ writeIncomingSmsTypeZero(int phoneId, String format)2299 public void writeIncomingSmsTypeZero(int phoneId, String format) { 2300 logv("Logged Type-0 SMS message."); 2301 writeIncomingSmsWithType(phoneId, 2302 SmsSession.Event.SmsType.SMS_TYPE_ZERO, format, true); 2303 } 2304 2305 /** 2306 * Write a successful incoming SMS session 2307 * 2308 * @param phoneId Phone id 2309 * @param type Type of the SMS. 2310 * @param smsOverIms true if the SMS was received over SMS, false otherwise 2311 * @param format SMS format. Either 3GPP or 3GPP2. 2312 * @param timestamps array with timestamps of each incoming SMS part. It contains a single 2313 * @param blocked indicates if the message was blocked or not. 2314 * @param success Indicates if the SMS-PP was successfully delivered to the USIM. 2315 */ writeIncomingSmsSessionWithType(int phoneId, int type, boolean smsOverIms, String format, long[] timestamps, boolean blocked, boolean success)2316 private void writeIncomingSmsSessionWithType(int phoneId, int type, boolean smsOverIms, 2317 String format, long[] timestamps, boolean blocked, boolean success) { 2318 logv("Logged SMS session consisting of " + timestamps.length 2319 + " parts, over IMS = " + smsOverIms 2320 + " blocked = " + blocked 2321 + " type = " + type); 2322 2323 InProgressSmsSession smsSession = startNewSmsSession(phoneId); 2324 for (long time : timestamps) { 2325 SmsSessionEventBuilder eventBuilder = 2326 new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_RECEIVED) 2327 .setFormat(convertSmsFormat(format)) 2328 .setTech(smsOverIms ? SmsSession.Event.Tech.SMS_IMS : 2329 SmsSession.Event.Tech.SMS_GSM) 2330 .setErrorCode(success ? SmsManager.RESULT_ERROR_NONE : 2331 SmsManager.RESULT_ERROR_GENERIC_FAILURE) 2332 .setSmsType(type) 2333 .setBlocked(blocked); 2334 smsSession.addEvent(time, eventBuilder); 2335 } 2336 finishSmsSession(smsSession); 2337 } 2338 2339 /** 2340 * Write an incoming WAP-PUSH message. 2341 * 2342 * @param phoneId Phone id 2343 * @param smsOverIms true if the SMS was received over SMS, false otherwise 2344 * @param format SMS format. Either 3GPP or 3GPP2. 2345 * @param timestamps array with timestamps of each incoming SMS part. It contains a single 2346 * @param success Indicates if the SMS-PP was successfully delivered to the USIM. 2347 */ writeIncomingWapPush(int phoneId, boolean smsOverIms, String format, long[] timestamps, boolean success)2348 public void writeIncomingWapPush(int phoneId, boolean smsOverIms, String format, 2349 long[] timestamps, boolean success) { 2350 writeIncomingSmsSessionWithType(phoneId, SmsSession.Event.SmsType.SMS_TYPE_WAP_PUSH, 2351 smsOverIms, format, timestamps, false, success); 2352 } 2353 2354 /** 2355 * Write a successful incoming SMS session 2356 * 2357 * @param phoneId Phone id 2358 * @param smsOverIms true if the SMS was received over SMS, false otherwise 2359 * @param format SMS format. Either 3GPP or 3GPP2. 2360 * @param timestamps array with timestamps of each incoming SMS part. It contains a single 2361 * @param blocked indicates if the message was blocked or not. 2362 */ writeIncomingSmsSession(int phoneId, boolean smsOverIms, String format, long[] timestamps, boolean blocked)2363 public void writeIncomingSmsSession(int phoneId, boolean smsOverIms, String format, 2364 long[] timestamps, boolean blocked) { 2365 writeIncomingSmsSessionWithType(phoneId, SmsSession.Event.SmsType.SMS_TYPE_NORMAL, 2366 smsOverIms, format, timestamps, blocked, true); 2367 } 2368 2369 /** 2370 * Write an error incoming SMS 2371 * 2372 * @param phoneId Phone id 2373 * @param smsOverIms true if the SMS was received over SMS, false otherwise 2374 * @param result Indicates the reason of the failure. 2375 */ writeIncomingSmsError(int phoneId, boolean smsOverIms, int result)2376 public void writeIncomingSmsError(int phoneId, boolean smsOverIms, int result) { 2377 logv("Incoming SMS error = " + result); 2378 2379 int smsError = SmsManager.RESULT_ERROR_GENERIC_FAILURE; 2380 switch (result) { 2381 case Intents.RESULT_SMS_HANDLED: 2382 // This should not happen. 2383 return; 2384 case Intents.RESULT_SMS_OUT_OF_MEMORY: 2385 smsError = SmsManager.RESULT_NO_MEMORY; 2386 break; 2387 case Intents.RESULT_SMS_UNSUPPORTED: 2388 smsError = SmsManager.RESULT_REQUEST_NOT_SUPPORTED; 2389 break; 2390 case Intents.RESULT_SMS_GENERIC_ERROR: 2391 default: 2392 smsError = SmsManager.RESULT_ERROR_GENERIC_FAILURE; 2393 break; 2394 } 2395 2396 InProgressSmsSession smsSession = startNewSmsSession(phoneId); 2397 2398 SmsSessionEventBuilder eventBuilder = 2399 new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_RECEIVED) 2400 .setErrorCode(smsError) 2401 .setTech(smsOverIms ? SmsSession.Event.Tech.SMS_IMS : 2402 SmsSession.Event.Tech.SMS_GSM); 2403 smsSession.addEvent(eventBuilder); 2404 finishSmsSession(smsSession); 2405 } 2406 2407 /** 2408 * Write NITZ event 2409 * 2410 * @param phoneId Phone id 2411 * @param timestamp NITZ time in milliseconds 2412 */ writeNITZEvent(int phoneId, long timestamp)2413 public void writeNITZEvent(int phoneId, long timestamp) { 2414 TelephonyEvent event = new TelephonyEventBuilder(phoneId).setNITZ(timestamp).build(); 2415 addTelephonyEvent(event); 2416 2417 annotateInProgressCallSession(event.timestampMillis, phoneId, 2418 new CallSessionEventBuilder( 2419 TelephonyCallSession.Event.Type.NITZ_TIME) 2420 .setNITZ(timestamp)); 2421 } 2422 2423 /** 2424 * Write Modem Restart event 2425 * 2426 * @param phoneId Phone id 2427 * @param reason Reason for the modem reset. 2428 */ writeModemRestartEvent(int phoneId, String reason)2429 public void writeModemRestartEvent(int phoneId, String reason) { 2430 final ModemRestart modemRestart = new ModemRestart(); 2431 String basebandVersion = Build.getRadioVersion(); 2432 if (basebandVersion != null) modemRestart.basebandVersion = basebandVersion; 2433 if (reason != null) modemRestart.reason = reason; 2434 TelephonyEvent event = new TelephonyEventBuilder(phoneId).setModemRestart( 2435 modemRestart).build(); 2436 addTelephonyEvent(event); 2437 } 2438 2439 /** 2440 * Write carrier identification matching event 2441 * 2442 * @param phoneId Phone id 2443 * @param version Carrier table version 2444 * @param cid Unique Carrier Id 2445 * @param unknownMcmnc MCC and MNC that map to this carrier 2446 * @param unknownGid1 Group id level 1 2447 * @param simInfo Subscription info 2448 */ writeCarrierIdMatchingEvent(int phoneId, int version, int cid, String unknownMcmnc, String unknownGid1, CarrierResolver.CarrierMatchingRule simInfo)2449 public void writeCarrierIdMatchingEvent(int phoneId, int version, int cid, 2450 String unknownMcmnc, String unknownGid1, 2451 CarrierResolver.CarrierMatchingRule simInfo) { 2452 final CarrierIdMatching carrierIdMatching = new CarrierIdMatching(); 2453 final CarrierIdMatchingResult carrierIdMatchingResult = new CarrierIdMatchingResult(); 2454 2455 // fill in information for unknown mccmnc and gid1 for unidentified carriers. 2456 if (cid != TelephonyManager.UNKNOWN_CARRIER_ID) { 2457 // Successful matching event if result only has carrierId 2458 carrierIdMatchingResult.carrierId = cid; 2459 // Unknown Gid1 event if result only has carrierId, gid1 and mccmnc 2460 if (unknownGid1 != null) { 2461 carrierIdMatchingResult.unknownMccmnc = unknownMcmnc; 2462 carrierIdMatchingResult.unknownGid1 = unknownGid1; 2463 } 2464 } else { 2465 // Unknown mccmnc event if result only has mccmnc 2466 if (unknownMcmnc != null) { 2467 carrierIdMatchingResult.unknownMccmnc = unknownMcmnc; 2468 } 2469 } 2470 2471 // fill in complete matching information from the SIM. 2472 carrierIdMatchingResult.mccmnc = TextUtils.emptyIfNull(simInfo.mccMnc); 2473 carrierIdMatchingResult.spn = TextUtils.emptyIfNull(simInfo.spn); 2474 carrierIdMatchingResult.pnn = TextUtils.emptyIfNull(simInfo.plmn); 2475 carrierIdMatchingResult.gid1 = TextUtils.emptyIfNull(simInfo.gid1); 2476 carrierIdMatchingResult.gid2 = TextUtils.emptyIfNull(simInfo.gid2); 2477 carrierIdMatchingResult.imsiPrefix = TextUtils.emptyIfNull(simInfo.imsiPrefixPattern); 2478 carrierIdMatchingResult.iccidPrefix = TextUtils.emptyIfNull(simInfo.iccidPrefix); 2479 carrierIdMatchingResult.preferApn = TextUtils.emptyIfNull(simInfo.apn); 2480 if (simInfo.privilegeAccessRule != null) { 2481 carrierIdMatchingResult.privilegeAccessRule = 2482 simInfo.privilegeAccessRule.stream().toArray(String[]::new); 2483 } 2484 2485 carrierIdMatching.cidTableVersion = version; 2486 carrierIdMatching.result = carrierIdMatchingResult; 2487 2488 TelephonyEvent event = new TelephonyEventBuilder(phoneId).setCarrierIdMatching( 2489 carrierIdMatching).build(); 2490 mLastCarrierId.put(phoneId, carrierIdMatching); 2491 addTelephonyEvent(event); 2492 } 2493 2494 /** 2495 * Write emergency number update event 2496 * 2497 * @param emergencyNumber Updated emergency number 2498 */ writeEmergencyNumberUpdateEvent(int phoneId, EmergencyNumber emergencyNumber)2499 public void writeEmergencyNumberUpdateEvent(int phoneId, EmergencyNumber emergencyNumber) { 2500 if (emergencyNumber == null) { 2501 return; 2502 } 2503 final EmergencyNumberInfo emergencyNumberInfo = 2504 convertEmergencyNumberToEmergencyNumberInfo(emergencyNumber); 2505 2506 TelephonyEvent event = new TelephonyEventBuilder(phoneId).setUpdatedEmergencyNumber( 2507 emergencyNumberInfo).build(); 2508 addTelephonyEvent(event); 2509 } 2510 2511 /** 2512 * Convert SMS format 2513 */ convertSmsFormat(String format)2514 private int convertSmsFormat(String format) { 2515 int formatCode = SmsSession.Event.Format.SMS_FORMAT_UNKNOWN; 2516 switch (format) { 2517 case SmsMessage.FORMAT_3GPP : { 2518 formatCode = SmsSession.Event.Format.SMS_FORMAT_3GPP; 2519 break; 2520 } 2521 case SmsMessage.FORMAT_3GPP2: { 2522 formatCode = SmsSession.Event.Format.SMS_FORMAT_3GPP2; 2523 break; 2524 } 2525 } 2526 return formatCode; 2527 } 2528 2529 /** 2530 * Convert IMS audio codec into proto defined value 2531 * 2532 * @param c IMS codec value 2533 * @return Codec value defined in call session proto 2534 */ convertImsCodec(int c)2535 private static int convertImsCodec(int c) { 2536 switch (c) { 2537 case ImsStreamMediaProfile.AUDIO_QUALITY_AMR: 2538 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR; 2539 case ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB: 2540 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR_WB; 2541 case ImsStreamMediaProfile.AUDIO_QUALITY_QCELP13K: 2542 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_QCELP13K; 2543 case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC: 2544 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC; 2545 case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_B: 2546 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_B; 2547 case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_WB: 2548 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_WB; 2549 case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_NW: 2550 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_NW; 2551 case ImsStreamMediaProfile.AUDIO_QUALITY_GSM_EFR: 2552 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_EFR; 2553 case ImsStreamMediaProfile.AUDIO_QUALITY_GSM_FR: 2554 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_FR; 2555 case ImsStreamMediaProfile.AUDIO_QUALITY_GSM_HR: 2556 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_HR; 2557 case ImsStreamMediaProfile.AUDIO_QUALITY_G711U: 2558 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G711U; 2559 case ImsStreamMediaProfile.AUDIO_QUALITY_G723: 2560 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G723; 2561 case ImsStreamMediaProfile.AUDIO_QUALITY_G711A: 2562 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G711A; 2563 case ImsStreamMediaProfile.AUDIO_QUALITY_G722: 2564 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G722; 2565 case ImsStreamMediaProfile.AUDIO_QUALITY_G711AB: 2566 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G711AB; 2567 case ImsStreamMediaProfile.AUDIO_QUALITY_G729: 2568 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G729; 2569 case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_NB: 2570 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_NB; 2571 case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_WB: 2572 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_WB; 2573 case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_SWB: 2574 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_SWB; 2575 case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_FB: 2576 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_FB; 2577 default: 2578 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_UNKNOWN; 2579 } 2580 } 2581 2582 /** 2583 * Convert GSM/CDMA audio codec into proto defined value 2584 * 2585 * @param c GSM/CDMA codec value 2586 * @return Codec value defined in call session proto 2587 */ convertGsmCdmaCodec(int c)2588 private int convertGsmCdmaCodec(int c) { 2589 switch (c) { 2590 case DriverCall.AUDIO_QUALITY_AMR: 2591 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR; 2592 case DriverCall.AUDIO_QUALITY_AMR_WB: 2593 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR_WB; 2594 case DriverCall.AUDIO_QUALITY_GSM_EFR: 2595 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_EFR; 2596 case DriverCall.AUDIO_QUALITY_GSM_FR: 2597 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_FR; 2598 case DriverCall.AUDIO_QUALITY_GSM_HR: 2599 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_HR; 2600 case DriverCall.AUDIO_QUALITY_EVRC: 2601 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC; 2602 case DriverCall.AUDIO_QUALITY_EVRC_B: 2603 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_B; 2604 case DriverCall.AUDIO_QUALITY_EVRC_WB: 2605 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_WB; 2606 case DriverCall.AUDIO_QUALITY_EVRC_NW: 2607 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_NW; 2608 default: 2609 return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_UNKNOWN; 2610 } 2611 } 2612 2613 /** 2614 * Write audio codec event 2615 * 2616 * @param phoneId Phone id 2617 * @param session IMS call session 2618 */ writeAudioCodecIms(int phoneId, ImsCallSession session)2619 public void writeAudioCodecIms(int phoneId, ImsCallSession session) { 2620 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 2621 if (callSession == null) { 2622 Rlog.e(TAG, "Call session is missing"); 2623 return; 2624 } 2625 2626 ImsCallProfile localCallProfile = session.getLocalCallProfile(); 2627 if (localCallProfile != null) { 2628 int codec = convertImsCodec(localCallProfile.mMediaProfile.mAudioQuality); 2629 callSession.addEvent(new CallSessionEventBuilder( 2630 TelephonyCallSession.Event.Type.AUDIO_CODEC) 2631 .setCallIndex(getCallId(session)) 2632 .setAudioCodec(codec)); 2633 2634 logv("Logged Audio Codec event. Value: " + codec); 2635 } 2636 } 2637 2638 /** 2639 * Write audio codec event 2640 * 2641 * @param phoneId Phone id 2642 * @param audioQuality Audio quality value 2643 */ writeAudioCodecGsmCdma(int phoneId, int audioQuality)2644 public void writeAudioCodecGsmCdma(int phoneId, int audioQuality) { 2645 InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); 2646 if (callSession == null) { 2647 Rlog.e(TAG, "Call session is missing"); 2648 return; 2649 } 2650 2651 int codec = convertGsmCdmaCodec(audioQuality); 2652 callSession.addEvent(new CallSessionEventBuilder( 2653 TelephonyCallSession.Event.Type.AUDIO_CODEC) 2654 .setAudioCodec(codec)); 2655 2656 logv("Logged Audio Codec event. Value: " + codec); 2657 } 2658 2659 //TODO: Expand the proto in the future writeOnImsCallProgressing(int phoneId, ImsCallSession session)2660 public void writeOnImsCallProgressing(int phoneId, ImsCallSession session) {} writeOnImsCallStarted(int phoneId, ImsCallSession session)2661 public void writeOnImsCallStarted(int phoneId, ImsCallSession session) {} writeOnImsCallStartFailed(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo)2662 public void writeOnImsCallStartFailed(int phoneId, ImsCallSession session, 2663 ImsReasonInfo reasonInfo) {} writeOnImsCallHeld(int phoneId, ImsCallSession session)2664 public void writeOnImsCallHeld(int phoneId, ImsCallSession session) {} writeOnImsCallHoldReceived(int phoneId, ImsCallSession session)2665 public void writeOnImsCallHoldReceived(int phoneId, ImsCallSession session) {} writeOnImsCallHoldFailed(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo)2666 public void writeOnImsCallHoldFailed(int phoneId, ImsCallSession session, 2667 ImsReasonInfo reasonInfo) {} writeOnImsCallResumed(int phoneId, ImsCallSession session)2668 public void writeOnImsCallResumed(int phoneId, ImsCallSession session) {} writeOnImsCallResumeReceived(int phoneId, ImsCallSession session)2669 public void writeOnImsCallResumeReceived(int phoneId, ImsCallSession session) {} writeOnImsCallResumeFailed(int phoneId, ImsCallSession session, ImsReasonInfo reasonInfo)2670 public void writeOnImsCallResumeFailed(int phoneId, ImsCallSession session, 2671 ImsReasonInfo reasonInfo) {} writeOnRilTimeoutResponse(int phoneId, int rilSerial, int rilRequest)2672 public void writeOnRilTimeoutResponse(int phoneId, int rilSerial, int rilRequest) {} 2673 2674 /** 2675 * Get the sample percentage of collecting metrics based on countries' population. 2676 * 2677 * The larger population the country has, the lower percentage we use to collect this 2678 * metrics. Since the exact population changes frequently, buckets of the population are used 2679 * instead of its exact number. Seven different levels of sampling percentage are assigned 2680 * based on the scale of population for countries. 2681 */ getSamplePercentageForEmergencyCall(String countryIso)2682 private double getSamplePercentageForEmergencyCall(String countryIso) { 2683 String countriesFor1Percentage = "cn,in"; 2684 String countriesFor5Percentage = "us,id,br,pk,ng,bd,ru,mx,jp,et,ph,eg,vn,cd,tr,ir,de"; 2685 String countriesFor15Percentage = "th,gb,fr,tz,it,za,mm,ke,kr,co,es,ug,ar,ua,dz,sd,iq"; 2686 String countriesFor25Percentage = "pl,ca,af,ma,sa,pe,uz,ve,my,ao,mz,gh,np,ye,mg,kp,cm"; 2687 String countriesFor35Percentage = "au,tw,ne,lk,bf,mw,ml,ro,kz,sy,cl,zm,gt,zw,nl,ec,sn"; 2688 String countriesFor45Percentage = "kh,td,so,gn,ss,rw,bj,tn,bi,be,cu,bo,ht,gr,do,cz,pt"; 2689 if (countriesFor1Percentage.contains(countryIso)) { 2690 return 1; 2691 } else if (countriesFor5Percentage.contains(countryIso)) { 2692 return 5; 2693 } else if (countriesFor15Percentage.contains(countryIso)) { 2694 return 15; 2695 } else if (countriesFor25Percentage.contains(countryIso)) { 2696 return 25; 2697 } else if (countriesFor35Percentage.contains(countryIso)) { 2698 return 35; 2699 } else if (countriesFor45Percentage.contains(countryIso)) { 2700 return 45; 2701 } else { 2702 return 50; 2703 } 2704 } 2705 mapSimStateToProto(int simState)2706 private static int mapSimStateToProto(int simState) { 2707 switch (simState) { 2708 case TelephonyManager.SIM_STATE_ABSENT: 2709 return SimState.SIM_STATE_ABSENT; 2710 case TelephonyManager.SIM_STATE_LOADED: 2711 return SimState.SIM_STATE_LOADED; 2712 default: 2713 return SimState.SIM_STATE_UNKNOWN; 2714 } 2715 } 2716 } 2717