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