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