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