1 /* 2 * Copyright (C) 2020 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.telephony.ims.RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED; 20 import static android.telephony.ims.RegistrationManager.REGISTRATION_STATE_REGISTERED; 21 import static android.telephony.ims.RegistrationManager.REGISTRATION_STATE_REGISTERING; 22 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS; 23 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT; 24 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO; 25 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE; 26 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; 27 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; 28 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; 29 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR; 30 import static android.text.format.DateUtils.SECOND_IN_MILLIS; 31 import static android.util.Patterns.EMAIL_ADDRESS; 32 33 import android.annotation.Nullable; 34 import android.os.SystemClock; 35 import android.telephony.AccessNetworkConstants; 36 import android.telephony.AccessNetworkConstants.TransportType; 37 import android.telephony.Annotation.NetworkType; 38 import android.telephony.NetworkRegistrationInfo; 39 import android.telephony.ServiceState; 40 import android.telephony.TelephonyManager; 41 import android.telephony.ims.ImsReasonInfo; 42 import android.telephony.ims.ProvisioningManager; 43 import android.telephony.ims.RegistrationManager.ImsRegistrationState; 44 import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities; 45 import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability; 46 import android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech; 47 48 import com.android.internal.annotations.VisibleForTesting; 49 import com.android.internal.telephony.Phone; 50 import com.android.internal.telephony.PhoneFactory; 51 import com.android.internal.telephony.imsphone.ImsPhone; 52 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationStats; 53 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination; 54 import com.android.telephony.Rlog; 55 56 import java.util.regex.Pattern; 57 58 /** Tracks IMS registration metrics for each phone. */ 59 public class ImsStats { 60 private static final String TAG = ImsStats.class.getSimpleName(); 61 62 /** 63 * Minimal duration of the registration state. 64 * 65 * <p>Registration state (including changes in capable/available features) with duration shorter 66 * than this will be ignored as they are considered transient states. 67 */ 68 private static final long MIN_REGISTRATION_DURATION_MILLIS = 1L * SECOND_IN_MILLIS; 69 70 /** 71 * Maximum length of the extra message in the termination reason. 72 * 73 * <p>If the extra message is longer than this length, it will be truncated. 74 */ 75 private static final int MAX_EXTRA_MESSAGE_LENGTH = 128; 76 77 /** Pattern used to match UUIDs in IMS extra messages for filtering. */ 78 private static final Pattern PATTERN_UUID = 79 Pattern.compile( 80 "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"); 81 82 /** Replacement for UUIDs. */ 83 private static final String REPLACEMENT_UUID = "<UUID_REDACTED>"; 84 85 /** 86 * Pattern used to match URI (e.g. sip, tel) in IMS extra messages for filtering. 87 * 88 * <p>NOTE: this simple pattern aims to catch the most common URI schemes. It is not meant to be 89 * RFC-complaint. 90 */ 91 private static final Pattern PATTERN_URI = 92 Pattern.compile("([a-zA-Z]{2,}:)" + EMAIL_ADDRESS.pattern()); 93 94 /** Replacement for URI. */ 95 private static final String REPLACEMENT_URI = "$1<REDACTED>"; 96 97 /** 98 * Pattern used to match IPv4 addresses in IMS extra messages for filtering. 99 * 100 * <p>This is a copy of {@code android.util.Patterns.IP_ADDRESS}, which is deprecated and might 101 * be removed in the future. 102 */ 103 private static final Pattern PATTERN_IPV4 = 104 Pattern.compile( 105 "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" 106 + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" 107 + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" 108 + "|[1-9][0-9]|[0-9]))"); 109 110 /** Replacement for IPv4 addresses. */ 111 private static final String REPLACEMENT_IPV4 = "<IPV4_REDACTED>"; 112 113 /** 114 * Pattern used to match IPv6 addresses in IMS extra messages for filtering. 115 * 116 * <p>NOTE: this pattern aims to catch the most common IPv6 addresses. It is not meant to be 117 * RFC-complaint or free of false positives. 118 */ 119 private static final Pattern PATTERN_IPV6 = 120 Pattern.compile( 121 // Full address 122 "([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}" 123 // Abbreviated address, e.g. 2001:4860:4860::8888 124 + "|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}){1,6}" 125 // Abbreviated network address, e.g. 2607:F8B0:: 126 + "|([0-9a-fA-F]{1,4}:){1,7}:" 127 // Abbreviated address, e.g. ::1 128 + "|:(:[0-9a-fA-F]{1,4}){1,7}"); 129 130 /** Replacement for IPv6 addresses. */ 131 private static final String REPLACEMENT_IPV6 = "<IPV6_REDACTED>"; 132 133 /** 134 * Pattern used to match potential IMEI values in IMS extra messages for filtering. 135 * 136 * <p>This includes segmented IMEI or IMEI/SV, as well as unsegmented IMEI/SV. 137 */ 138 private static final Pattern PATTERN_IMEI = 139 Pattern.compile( 140 "(^|[^0-9])(?:" 141 // IMEI, AABBBBBB-CCCCCC-D format; IMEI/SV, AABBBBBB-CCCCCC-EE format 142 + "[0-9]{8}-[0-9]{6}-[0-9][0-9]?" 143 // IMEI, AA-BBBBBB-CCCCCC-D format; IMEI/SV, AA-BBBBBB-CCCCCC-EE format 144 + "|[0-9]{2}-[0-9]{6}-[0-9]{6}-[0-9][0-9]?" 145 // IMEI/SV, unsegmented 146 + "|[0-9]{16}" 147 + ")($|[^0-9])"); 148 149 /** Replacement for IMEI. */ 150 private static final String REPLACEMENT_IMEI = "$1<IMEI_REDACTED>$2"; 151 152 /** 153 * Pattern used to match potential unsegmented IMEI/IMSI values in IMS extra messages for 154 * filtering. 155 */ 156 private static final Pattern PATTERN_UNSEGMENTED_IMEI_IMSI = 157 Pattern.compile("(^|[^0-9])[0-9]{15}($|[^0-9])"); 158 159 /** Replacement for unsegmented IMEI/IMSI. */ 160 private static final String REPLACEMENT_UNSEGMENTED_IMEI_IMSI = "$1<IMEI_IMSI_REDACTED>$2"; 161 162 /** 163 * Pattern used to match hostnames in IMS extra messages for filtering. 164 * 165 * <p>This pattern differs from {@link android.util.Patterns.DOMAIN_NAME} in a few ways: it 166 * requires the name to have at least 3 segments (shorter names are nearly always public or 167 * typos, i.e. missing space after period), does not check the validity of TLDs, and does not 168 * support punycodes in TLDs. 169 */ 170 private static final Pattern PATTERN_HOSTNAME = 171 Pattern.compile("([0-9a-zA-Z][0-9a-zA-Z_\\-]{0,61}[0-9a-zA-Z]\\.){2,}[a-zA-Z]{2,}"); 172 173 /** Replacement for hostnames. */ 174 private static final String REPLACEMENT_HOSTNAME = "<HOSTNAME_REDACTED>"; 175 176 /** 177 * Pattern used to match potential IDs in IMS extra messages for filtering. 178 * 179 * <p>This pattern target numbers that are potential IDs in unknown formats. It should be 180 * replaced after all other replacements are done to ensure complete and correct filtering. 181 * 182 * <p>Specifically, this pattern looks for any number (including hex) that is separated by dots 183 * or dashes has at least 6 significant digits, and any unsegmented numbers that has at least 5 184 * significant digits. 185 */ 186 private static final Pattern PATTERN_UNKNOWN_ID = 187 Pattern.compile( 188 "(^|[^0-9a-fA-F])(([-\\.]?0)*[1-9a-fA-F]([-\\.]?[0-9a-fA-F]){5,}" 189 + "|0*[1-9a-fA-F]([0-9a-fA-F]){4,})"); 190 191 /** Replacement for potential IDs. */ 192 private static final String REPLACEMENT_UNKNOWN_ID = "$1<ID_REDACTED>"; 193 194 private final ImsPhone mPhone; 195 private final PersistAtomsStorage mStorage; 196 197 @ImsRegistrationState private int mLastRegistrationState = REGISTRATION_STATE_NOT_REGISTERED; 198 199 private long mLastTimestamp; 200 @Nullable private ImsRegistrationStats mLastRegistrationStats; 201 @TransportType int mLastTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 202 // Available features are those reported by ImsService to be available for use. 203 private MmTelCapabilities mLastAvailableFeatures = new MmTelCapabilities(); 204 205 // Capable features (enabled by device/carrier). Theses are available before IMS is registered 206 // and not necessarily updated when RAT changes. 207 private final MmTelCapabilities mLastWwanCapableFeatures = new MmTelCapabilities(); 208 private final MmTelCapabilities mLastWlanCapableFeatures = new MmTelCapabilities(); 209 ImsStats(ImsPhone phone)210 public ImsStats(ImsPhone phone) { 211 mPhone = phone; 212 mStorage = PhoneFactory.getMetricsCollector().getAtomsStorage(); 213 } 214 215 /** 216 * Finalizes the durations of the current IMS registration stats segment. 217 * 218 * <p>This method is also invoked whenever the registration state, feature capability, or 219 * feature availability changes. 220 */ conclude()221 public synchronized void conclude() { 222 long now = getTimeMillis(); 223 224 // Currently not tracking time spent on registering. 225 if (mLastRegistrationState == REGISTRATION_STATE_REGISTERED) { 226 ImsRegistrationStats stats = copyOf(mLastRegistrationStats); 227 long duration = now - mLastTimestamp; 228 229 if (duration < MIN_REGISTRATION_DURATION_MILLIS) { 230 logw("conclude: discarding transient stats, duration=%d", duration); 231 } else { 232 stats.registeredMillis = duration; 233 234 stats.voiceAvailableMillis = 235 mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0; 236 stats.videoAvailableMillis = 237 mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0; 238 stats.utAvailableMillis = 239 mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0; 240 stats.smsAvailableMillis = 241 mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0; 242 243 MmTelCapabilities lastCapableFeatures = 244 stats.rat == TelephonyManager.NETWORK_TYPE_IWLAN 245 ? mLastWlanCapableFeatures 246 : mLastWwanCapableFeatures; 247 stats.voiceCapableMillis = 248 lastCapableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0; 249 stats.videoCapableMillis = 250 lastCapableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0; 251 stats.utCapableMillis = 252 lastCapableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0; 253 stats.smsCapableMillis = 254 lastCapableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0; 255 256 mStorage.addImsRegistrationStats(stats); 257 } 258 } 259 260 mLastTimestamp = now; 261 } 262 263 /** Updates the stats when registered features changed. */ onImsCapabilitiesChanged( @msRegistrationTech int radioTech, MmTelCapabilities capabilities)264 public synchronized void onImsCapabilitiesChanged( 265 @ImsRegistrationTech int radioTech, MmTelCapabilities capabilities) { 266 conclude(); 267 268 boolean ratChanged = false; 269 @NetworkType int newRat = convertRegistrationTechToNetworkType(radioTech); 270 mLastTransportType = 271 (newRat == TelephonyManager.NETWORK_TYPE_IWLAN) 272 ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN 273 : AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 274 if (mLastRegistrationStats != null && mLastRegistrationStats.rat != newRat) { 275 mLastRegistrationStats.rat = newRat; 276 ratChanged = true; 277 } 278 279 boolean voiceAvailableNow = capabilities.isCapable(CAPABILITY_TYPE_VOICE); 280 boolean voiceAvailabilityChanged = 281 (mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE) != voiceAvailableNow); 282 mLastAvailableFeatures = capabilities; 283 284 // Notify voice RAT change if 1. RAT changed while voice over IMS is available, or 2. voice 285 // over IMS availability changed 286 if ((ratChanged && voiceAvailableNow) || voiceAvailabilityChanged) { 287 mPhone.getDefaultPhone().getServiceStateTracker().getServiceStateStats() 288 .onImsVoiceRegistrationChanged(); 289 } 290 } 291 292 /** Updates the stats when capable features changed. */ onSetFeatureResponse( @mTelCapability int feature, @ImsRegistrationTech int network, int value)293 public synchronized void onSetFeatureResponse( 294 @MmTelCapability int feature, @ImsRegistrationTech int network, int value) { 295 MmTelCapabilities lastCapableFeatures = getLastCapableFeaturesForTech(network); 296 if (lastCapableFeatures != null) { 297 conclude(); 298 if (value == ProvisioningManager.PROVISIONING_VALUE_ENABLED) { 299 lastCapableFeatures.addCapabilities(feature); 300 } else { 301 lastCapableFeatures.removeCapabilities(feature); 302 } 303 } 304 } 305 306 /** Updates the stats when IMS registration is progressing. */ onImsRegistering(@ransportType int imsRadioTech)307 public synchronized void onImsRegistering(@TransportType int imsRadioTech) { 308 conclude(); 309 310 mLastTransportType = imsRadioTech; 311 mLastRegistrationStats = getDefaultImsRegistrationStats(); 312 mLastRegistrationStats.rat = convertTransportTypeToNetworkType(imsRadioTech); 313 mLastRegistrationState = REGISTRATION_STATE_REGISTERING; 314 } 315 316 /** Updates the stats when IMS registration succeeds. */ onImsRegistered(@ransportType int imsRadioTech)317 public synchronized void onImsRegistered(@TransportType int imsRadioTech) { 318 conclude(); 319 320 mLastTransportType = imsRadioTech; 321 // NOTE: mLastRegistrationStats can be null (no registering phase). 322 if (mLastRegistrationStats == null) { 323 mLastRegistrationStats = getDefaultImsRegistrationStats(); 324 } 325 mLastRegistrationStats.rat = convertTransportTypeToNetworkType(imsRadioTech); 326 mLastRegistrationState = REGISTRATION_STATE_REGISTERED; 327 } 328 329 /** Updates the stats and generates a termination atom when IMS registration fails/ends. */ onImsUnregistered(ImsReasonInfo reasonInfo)330 public synchronized void onImsUnregistered(ImsReasonInfo reasonInfo) { 331 conclude(); 332 333 // Generate end reason atom. 334 // NOTE: mLastRegistrationStats can be null (no registering phase). 335 ImsRegistrationTermination termination = new ImsRegistrationTermination(); 336 if (mLastRegistrationStats != null) { 337 termination.carrierId = mLastRegistrationStats.carrierId; 338 termination.ratAtEnd = getRatAtEnd(mLastRegistrationStats.rat); 339 } else { 340 termination.carrierId = mPhone.getDefaultPhone().getCarrierId(); 341 // We cannot tell whether the registration was intended for WWAN or WLAN 342 termination.ratAtEnd = TelephonyManager.NETWORK_TYPE_UNKNOWN; 343 } 344 termination.isMultiSim = SimSlotState.isMultiSim(); 345 termination.setupFailed = (mLastRegistrationState != REGISTRATION_STATE_REGISTERED); 346 termination.reasonCode = reasonInfo.getCode(); 347 termination.extraCode = reasonInfo.getExtraCode(); 348 termination.extraMessage = filterExtraMessage(reasonInfo.getExtraMessage()); 349 termination.count = 1; 350 mStorage.addImsRegistrationTermination(termination); 351 352 // Reset state to unregistered. 353 mLastRegistrationState = REGISTRATION_STATE_NOT_REGISTERED; 354 mLastRegistrationStats = null; 355 mLastAvailableFeatures = new MmTelCapabilities(); 356 } 357 358 /** Updates the RAT when service state changes. */ onServiceStateChanged(ServiceState state)359 public synchronized void onServiceStateChanged(ServiceState state) { 360 if (mLastTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN 361 && mLastRegistrationStats != null) { 362 mLastRegistrationStats.rat = 363 ServiceStateStats.getRat(state, NetworkRegistrationInfo.DOMAIN_PS); 364 } 365 } 366 367 /** 368 * Returns the current RAT used for IMS voice registration, or {@link 369 * TelephonyManager#NETWORK_TYPE_UNKNOWN} if there isn't any. 370 */ 371 @NetworkType getImsVoiceRadioTech()372 public synchronized int getImsVoiceRadioTech() { 373 if (mLastRegistrationStats == null 374 || !mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE)) { 375 return TelephonyManager.NETWORK_TYPE_UNKNOWN; 376 } 377 return mLastRegistrationStats.rat; 378 } 379 380 @NetworkType getRatAtEnd(@etworkType int lastStateRat)381 private int getRatAtEnd(@NetworkType int lastStateRat) { 382 return lastStateRat == TelephonyManager.NETWORK_TYPE_IWLAN ? lastStateRat : getWwanPsRat(); 383 } 384 385 @NetworkType convertTransportTypeToNetworkType(@ransportType int transportType)386 private int convertTransportTypeToNetworkType(@TransportType int transportType) { 387 switch (transportType) { 388 case AccessNetworkConstants.TRANSPORT_TYPE_WWAN: 389 return getWwanPsRat(); 390 case AccessNetworkConstants.TRANSPORT_TYPE_WLAN: 391 return TelephonyManager.NETWORK_TYPE_IWLAN; 392 default: 393 return TelephonyManager.NETWORK_TYPE_UNKNOWN; 394 } 395 } 396 397 @NetworkType getWwanPsRat()398 private int getWwanPsRat() { 399 return ServiceStateStats.getRat( 400 mPhone.getServiceStateTracker().getServiceState(), 401 NetworkRegistrationInfo.DOMAIN_PS); 402 } 403 getDefaultImsRegistrationStats()404 private ImsRegistrationStats getDefaultImsRegistrationStats() { 405 Phone phone = mPhone.getDefaultPhone(); 406 ImsRegistrationStats stats = new ImsRegistrationStats(); 407 stats.carrierId = phone.getCarrierId(); 408 stats.simSlotIndex = phone.getPhoneId(); 409 return stats; 410 } 411 412 @Nullable getLastCapableFeaturesForTech(@msRegistrationTech int radioTech)413 private MmTelCapabilities getLastCapableFeaturesForTech(@ImsRegistrationTech int radioTech) { 414 switch (radioTech) { 415 case REGISTRATION_TECH_NONE: 416 return null; 417 case REGISTRATION_TECH_IWLAN: 418 return mLastWlanCapableFeatures; 419 default: 420 return mLastWwanCapableFeatures; 421 } 422 } 423 424 @NetworkType convertRegistrationTechToNetworkType(@msRegistrationTech int radioTech)425 private int convertRegistrationTechToNetworkType(@ImsRegistrationTech int radioTech) { 426 switch (radioTech) { 427 case REGISTRATION_TECH_NONE: 428 return TelephonyManager.NETWORK_TYPE_UNKNOWN; 429 case REGISTRATION_TECH_LTE: 430 return TelephonyManager.NETWORK_TYPE_LTE; 431 case REGISTRATION_TECH_IWLAN: 432 return TelephonyManager.NETWORK_TYPE_IWLAN; 433 case REGISTRATION_TECH_NR: 434 return TelephonyManager.NETWORK_TYPE_NR; 435 default: 436 loge("convertRegistrationTechToNetworkType: unknown radio tech %d", radioTech); 437 return getWwanPsRat(); 438 } 439 } 440 copyOf(ImsRegistrationStats source)441 private static ImsRegistrationStats copyOf(ImsRegistrationStats source) { 442 ImsRegistrationStats dest = new ImsRegistrationStats(); 443 444 dest.carrierId = source.carrierId; 445 dest.simSlotIndex = source.simSlotIndex; 446 dest.rat = source.rat; 447 dest.registeredMillis = source.registeredMillis; 448 dest.voiceCapableMillis = source.voiceCapableMillis; 449 dest.voiceAvailableMillis = source.voiceAvailableMillis; 450 dest.smsCapableMillis = source.smsCapableMillis; 451 dest.smsAvailableMillis = source.smsAvailableMillis; 452 dest.videoCapableMillis = source.videoCapableMillis; 453 dest.videoAvailableMillis = source.videoAvailableMillis; 454 dest.utCapableMillis = source.utCapableMillis; 455 dest.utAvailableMillis = source.utAvailableMillis; 456 457 return dest; 458 } 459 460 @VisibleForTesting getTimeMillis()461 protected long getTimeMillis() { 462 return SystemClock.elapsedRealtime(); 463 } 464 465 /** Filters IMS extra messages to ensure length limit and remove IDs. */ filterExtraMessage(@ullable String str)466 public static String filterExtraMessage(@Nullable String str) { 467 if (str == null) { 468 return ""; 469 } 470 471 str = PATTERN_UUID.matcher(str).replaceAll(REPLACEMENT_UUID); 472 str = PATTERN_URI.matcher(str).replaceAll(REPLACEMENT_URI); 473 str = PATTERN_HOSTNAME.matcher(str).replaceAll(REPLACEMENT_HOSTNAME); 474 str = PATTERN_IPV4.matcher(str).replaceAll(REPLACEMENT_IPV4); 475 str = PATTERN_IPV6.matcher(str).replaceAll(REPLACEMENT_IPV6); 476 str = PATTERN_IMEI.matcher(str).replaceAll(REPLACEMENT_IMEI); 477 str = PATTERN_UNSEGMENTED_IMEI_IMSI.matcher(str) 478 .replaceAll(REPLACEMENT_UNSEGMENTED_IMEI_IMSI); 479 str = PATTERN_UNKNOWN_ID.matcher(str).replaceAll(REPLACEMENT_UNKNOWN_ID); 480 481 return str.length() > MAX_EXTRA_MESSAGE_LENGTH 482 ? str.substring(0, MAX_EXTRA_MESSAGE_LENGTH) 483 : str; 484 } 485 logw(String format, Object... args)486 private void logw(String format, Object... args) { 487 Rlog.w(TAG, "[" + mPhone.getPhoneId() + "] " + String.format(format, args)); 488 } 489 loge(String format, Object... args)490 private void loge(String format, Object... args) { 491 Rlog.e(TAG, "[" + mPhone.getPhoneId() + "] " + String.format(format, args)); 492 } 493 } 494