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