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