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 com.android.internal.telephony.InboundSmsHandler.SOURCE_INJECTED_FROM_IMS;
20 import static com.android.internal.telephony.InboundSmsHandler.SOURCE_INJECTED_FROM_UNKNOWN;
21 import static com.android.internal.telephony.InboundSmsHandler.SOURCE_NOT_INJECTED;
22 import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE;
23 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__ERROR__SMS_ERROR_GENERIC;
24 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__ERROR__SMS_ERROR_NOT_SUPPORTED;
25 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__ERROR__SMS_ERROR_NO_MEMORY;
26 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__ERROR__SMS_SUCCESS;
27 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_FORMAT__SMS_FORMAT_3GPP;
28 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_FORMAT__SMS_FORMAT_3GPP2;
29 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_TECH__SMS_TECH_CS_3GPP;
30 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_TECH__SMS_TECH_CS_3GPP2;
31 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_TECH__SMS_TECH_IMS;
32 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_TECH__SMS_TECH_UNKNOWN;
33 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_TYPE__SMS_TYPE_NORMAL;
34 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_TYPE__SMS_TYPE_SMS_PP;
35 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_TYPE__SMS_TYPE_VOICEMAIL_INDICATION;
36 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_TYPE__SMS_TYPE_WAP_PUSH;
37 import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__SMS_TYPE__SMS_TYPE_ZERO;
38 import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR;
39 import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR_FALLBACK;
40 import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR_RETRY;
41 import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_SUCCESS;
42 import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_UNKNOWN;
43 
44 import android.annotation.Nullable;
45 import android.app.Activity;
46 import android.provider.Telephony.Sms.Intents;
47 import android.telephony.Annotation.NetworkType;
48 import android.telephony.ServiceState;
49 import android.telephony.SmsManager;
50 import android.telephony.TelephonyManager;
51 import android.telephony.ims.stub.ImsRegistrationImplBase;
52 import android.telephony.ims.stub.ImsSmsImplBase;
53 import android.telephony.ims.stub.ImsSmsImplBase.SendStatusResult;
54 
55 import com.android.internal.telephony.InboundSmsHandler;
56 import com.android.internal.telephony.Phone;
57 import com.android.internal.telephony.PhoneConstants;
58 import com.android.internal.telephony.PhoneFactory;
59 import com.android.internal.telephony.ServiceStateTracker;
60 import com.android.internal.telephony.flags.Flags;
61 import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms;
62 import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms;
63 import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms;
64 import com.android.internal.telephony.satellite.metrics.CarrierRoamingSatelliteSessionStats;
65 import com.android.telephony.Rlog;
66 
67 import java.util.Objects;
68 import java.util.Random;
69 
70 /** Collects sms events per phone ID for the pulled atom. */
71 public class SmsStats {
72     private static final String TAG = SmsStats.class.getSimpleName();
73 
74     /** 3GPP error for out of service: "no network service" in TS 27.005 cl 3.2.5 */
75     private static final int NO_NETWORK_ERROR_3GPP = 331;
76 
77     /** 3GPP2 error for out of service: "Other radio interface problem" in N.S0005 Table 171 */
78     private static final int NO_NETWORK_ERROR_3GPP2 = 66;
79 
80     private final Phone mPhone;
81 
82     private final PersistAtomsStorage mAtomsStorage =
83             PhoneFactory.getMetricsCollector().getAtomsStorage();
84 
85     private static final Random RANDOM = new Random();
86 
SmsStats(Phone phone)87     public SmsStats(Phone phone) {
88         mPhone = phone;
89     }
90 
91     /** Create a new atom when multi-part incoming SMS is dropped due to missing parts. */
onDroppedIncomingMultipartSms(boolean is3gpp2, int receivedCount, int totalCount, boolean isEmergency)92     public void onDroppedIncomingMultipartSms(boolean is3gpp2, int receivedCount, int totalCount,
93             boolean isEmergency) {
94         IncomingSms proto = getIncomingDefaultProto(is3gpp2, SOURCE_NOT_INJECTED, isEmergency);
95         // Keep SMS tech as unknown because it's possible that it changed overtime and is not
96         // necessarily the current one. Similarly mark the RAT as unknown.
97         proto.smsTech = INCOMING_SMS__SMS_TECH__SMS_TECH_UNKNOWN;
98         proto.rat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
99         proto.error = INCOMING_SMS__ERROR__SMS_ERROR_GENERIC;
100         proto.totalParts = totalCount;
101         proto.receivedParts = receivedCount;
102         mAtomsStorage.addIncomingSms(proto);
103     }
104 
105     /** Create a new atom when an SMS for the voicemail indicator is received. */
onIncomingSmsVoicemail(boolean is3gpp2, @InboundSmsHandler.SmsSource int smsSource)106     public void onIncomingSmsVoicemail(boolean is3gpp2,
107             @InboundSmsHandler.SmsSource int smsSource) {
108         IncomingSms proto = getIncomingDefaultProto(is3gpp2, smsSource, false);
109         proto.smsType = INCOMING_SMS__SMS_TYPE__SMS_TYPE_VOICEMAIL_INDICATION;
110         mAtomsStorage.addIncomingSms(proto);
111     }
112 
113     /** Create a new atom when an SMS of type zero is received. */
onIncomingSmsTypeZero(@nboundSmsHandler.SmsSource int smsSource)114     public void onIncomingSmsTypeZero(@InboundSmsHandler.SmsSource int smsSource) {
115         IncomingSms proto = getIncomingDefaultProto(false /* is3gpp2 */, smsSource, false);
116         proto.smsType = INCOMING_SMS__SMS_TYPE__SMS_TYPE_ZERO;
117         mAtomsStorage.addIncomingSms(proto);
118     }
119 
120     /** Create a new atom when an SMS-PP for the SIM card is received. */
onIncomingSmsPP(@nboundSmsHandler.SmsSource int smsSource, boolean success)121     public void onIncomingSmsPP(@InboundSmsHandler.SmsSource int smsSource, boolean success) {
122         IncomingSms proto = getIncomingDefaultProto(false /* is3gpp2 */, smsSource, false);
123         proto.smsType = INCOMING_SMS__SMS_TYPE__SMS_TYPE_SMS_PP;
124         proto.error = getIncomingSmsError(success);
125         mAtomsStorage.addIncomingSms(proto);
126     }
127 
128     /** Create a new atom when an SMS is received successfully. */
onIncomingSmsSuccess(boolean is3gpp2, @InboundSmsHandler.SmsSource int smsSource, int messageCount, boolean blocked, long messageId, boolean isEmergency)129     public void onIncomingSmsSuccess(boolean is3gpp2,
130             @InboundSmsHandler.SmsSource int smsSource, int messageCount,
131             boolean blocked, long messageId, boolean isEmergency) {
132         IncomingSms proto = getIncomingDefaultProto(is3gpp2, smsSource, isEmergency);
133         proto.totalParts = messageCount;
134         proto.receivedParts = messageCount;
135         proto.blocked = blocked;
136         proto.messageId = messageId;
137         mAtomsStorage.addIncomingSms(proto);
138     }
139 
140     /** Create a new atom when an incoming SMS has an error. */
onIncomingSmsError(boolean is3gpp2, @InboundSmsHandler.SmsSource int smsSource, int result, boolean isEmergency)141     public void onIncomingSmsError(boolean is3gpp2,
142             @InboundSmsHandler.SmsSource int smsSource, int result, boolean isEmergency) {
143         IncomingSms proto = getIncomingDefaultProto(is3gpp2, smsSource, isEmergency);
144         proto.error = getIncomingSmsError(result);
145         mAtomsStorage.addIncomingSms(proto);
146     }
147 
148     /** Create a new atom when an incoming WAP_PUSH SMS is received. */
onIncomingSmsWapPush(@nboundSmsHandler.SmsSource int smsSource, int messageCount, int result, long messageId, boolean isEmergency)149     public void onIncomingSmsWapPush(@InboundSmsHandler.SmsSource int smsSource,
150             int messageCount, int result, long messageId, boolean isEmergency) {
151         IncomingSms proto = getIncomingDefaultProto(false, smsSource, isEmergency);
152         proto.smsType = INCOMING_SMS__SMS_TYPE__SMS_TYPE_WAP_PUSH;
153         proto.totalParts = messageCount;
154         proto.receivedParts = messageCount;
155         proto.error = getIncomingSmsError(result);
156         proto.messageId = messageId;
157         mAtomsStorage.addIncomingSms(proto);
158     }
159 
160     /** Create a new atom when an outgoing SMS is sent. */
onOutgoingSms(boolean isOverIms, boolean is3gpp2, boolean fallbackToCs, @SmsManager.Result int sendErrorCode, long messageId, boolean isFromDefaultApp, long intervalMillis, boolean isEmergency)161     public void onOutgoingSms(boolean isOverIms, boolean is3gpp2, boolean fallbackToCs,
162             @SmsManager.Result int sendErrorCode, long messageId, boolean isFromDefaultApp,
163             long intervalMillis, boolean isEmergency) {
164         onOutgoingSms(isOverIms, is3gpp2, fallbackToCs, sendErrorCode, NO_ERROR_CODE,
165                 messageId, isFromDefaultApp, intervalMillis, isEmergency);
166     }
167 
168     /** Create a new atom when an outgoing SMS is sent. */
onOutgoingSms(boolean isOverIms, boolean is3gpp2, boolean fallbackToCs, @SmsManager.Result int sendErrorCode, int networkErrorCode, long messageId, boolean isFromDefaultApp, long intervalMillis, boolean isEmergency)169     public void onOutgoingSms(boolean isOverIms, boolean is3gpp2, boolean fallbackToCs,
170             @SmsManager.Result int sendErrorCode, int networkErrorCode, long messageId,
171             boolean isFromDefaultApp, long intervalMillis, boolean isEmergency) {
172         OutgoingSms proto =
173                 getOutgoingDefaultProto(is3gpp2, isOverIms, messageId, isFromDefaultApp,
174                         intervalMillis, isEmergency);
175 
176         // The field errorCode is used for up-to-Android-13 devices. From Android 14, sendErrorCode
177         // and networkErrorCode will be used. The field errorCode will be deprecated when most
178         // devices use Android 14 or higher versions.
179         if (isOverIms) {
180             // Populate error code and result for IMS case
181             proto.errorCode = sendErrorCode;
182             if (fallbackToCs) {
183                 proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR_FALLBACK;
184             } else if (sendErrorCode == SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY) {
185                 proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR_RETRY;
186             } else if (sendErrorCode != SmsManager.RESULT_ERROR_NONE) {
187                 proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR;
188             }
189         } else {
190             // Populate error code and result for CS case
191             if (sendErrorCode == SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY) {
192                 proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR_RETRY;
193             } else if (sendErrorCode != SmsManager.RESULT_ERROR_NONE) {
194                 proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR;
195             }
196             proto.errorCode = networkErrorCode;
197             if (sendErrorCode == SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE
198                     && networkErrorCode == NO_ERROR_CODE) {
199                 proto.errorCode = is3gpp2 ? NO_NETWORK_ERROR_3GPP2 : NO_NETWORK_ERROR_3GPP;
200             }
201         }
202 
203         proto.sendErrorCode = sendErrorCode;
204         proto.networkErrorCode = networkErrorCode;
205 
206         mAtomsStorage.addOutgoingSms(proto);
207         CarrierRoamingSatelliteSessionStats sessionStats =
208                 CarrierRoamingSatelliteSessionStats.getInstance(mPhone.getSubId());
209         sessionStats.onOutgoingSms(mPhone.getSubId());
210     }
211 
212     /** Create a new atom when user attempted to send an outgoing short code sms. */
onOutgoingShortCodeSms(int category, int xmlVersion)213     public void onOutgoingShortCodeSms(int category, int xmlVersion) {
214         OutgoingShortCodeSms proto = new OutgoingShortCodeSms();
215         proto.category = category;
216         proto.xmlVersion = xmlVersion;
217         proto.shortCodeSmsCount = 1;
218         mAtomsStorage.addOutgoingShortCodeSms(proto);
219     }
220 
221     /** Creates a proto for a normal single-part {@code IncomingSms} with default values. */
getIncomingDefaultProto(boolean is3gpp2, @InboundSmsHandler.SmsSource int smsSource, boolean isEmergency)222     private IncomingSms getIncomingDefaultProto(boolean is3gpp2,
223             @InboundSmsHandler.SmsSource int smsSource, boolean isEmergency) {
224         IncomingSms proto = new IncomingSms();
225         proto.smsFormat = getSmsFormat(is3gpp2);
226         proto.smsTech = getSmsTech(smsSource, is3gpp2);
227         proto.rat = getRat(smsSource);
228         proto.smsType = INCOMING_SMS__SMS_TYPE__SMS_TYPE_NORMAL;
229         proto.totalParts = 1;
230         proto.receivedParts = 1;
231         proto.blocked = false;
232         proto.error = INCOMING_SMS__ERROR__SMS_SUCCESS;
233         proto.isRoaming = getIsRoaming();
234         proto.simSlotIndex = getPhoneId();
235         proto.isMultiSim = SimSlotState.isMultiSim();
236         proto.isEsim = SimSlotState.isEsim(getPhoneId());
237         proto.carrierId = getCarrierId();
238         // Message ID is initialized with random number, as it is not available for all incoming
239         // SMS messages (e.g. those handled by OS or error cases).
240         proto.messageId = RANDOM.nextLong();
241         proto.count = 1;
242         proto.isManagedProfile = mPhone.isManagedProfile();
243         proto.isNtn = isNonTerrestrialNetwork();
244         proto.isEmergency = isEmergency;
245         return proto;
246     }
247 
248     /** Create a proto for a normal {@code OutgoingSms} with default values. */
getOutgoingDefaultProto(boolean is3gpp2, boolean isOverIms, long messageId, boolean isFromDefaultApp, long intervalMillis, boolean isEmergency)249     private OutgoingSms getOutgoingDefaultProto(boolean is3gpp2, boolean isOverIms,
250             long messageId, boolean isFromDefaultApp, long intervalMillis, boolean isEmergency) {
251         OutgoingSms proto = new OutgoingSms();
252         proto.smsFormat = getSmsFormat(is3gpp2);
253         proto.smsTech = getSmsTech(isOverIms, is3gpp2);
254         proto.rat = getRat(isOverIms);
255         proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_SUCCESS;
256         proto.errorCode = isOverIms ? SmsManager.RESULT_ERROR_NONE : NO_ERROR_CODE;
257         proto.isRoaming = getIsRoaming();
258         proto.isFromDefaultApp = isFromDefaultApp;
259         proto.simSlotIndex = getPhoneId();
260         proto.isMultiSim = SimSlotState.isMultiSim();
261         proto.isEsim = SimSlotState.isEsim(getPhoneId());
262         proto.carrierId = getCarrierId();
263         // If the message ID is invalid, generate a random value
264         proto.messageId = messageId != 0L ? messageId : RANDOM.nextLong();
265         // Setting the retry ID to zero. If needed, it will be incremented when the atom is added
266         // in the persistent storage.
267         proto.retryId = 0;
268         proto.intervalMillis = intervalMillis;
269         proto.count = 1;
270         proto.isManagedProfile = mPhone.isManagedProfile();
271         proto.isEmergency = isEmergency;
272         proto.isNtn = isNonTerrestrialNetwork();
273         return proto;
274     }
275 
getSmsFormat(boolean is3gpp2)276     private static int getSmsFormat(boolean is3gpp2) {
277         if (is3gpp2) {
278             return INCOMING_SMS__SMS_FORMAT__SMS_FORMAT_3GPP2;
279         } else {
280             return INCOMING_SMS__SMS_FORMAT__SMS_FORMAT_3GPP;
281         }
282     }
283 
getSmsTech(@nboundSmsHandler.SmsSource int smsSource, boolean is3gpp2)284     private int getSmsTech(@InboundSmsHandler.SmsSource int smsSource, boolean is3gpp2) {
285         if (smsSource == SOURCE_INJECTED_FROM_UNKNOWN) {
286             return INCOMING_SMS__SMS_TECH__SMS_TECH_UNKNOWN;
287         }
288         return getSmsTech(smsSource == SOURCE_INJECTED_FROM_IMS, is3gpp2);
289     }
290 
getSmsTech(boolean isOverIms, boolean is3gpp2)291     private int getSmsTech(boolean isOverIms, boolean is3gpp2) {
292         if (isOverIms) {
293             return INCOMING_SMS__SMS_TECH__SMS_TECH_IMS;
294         } else if (is3gpp2) {
295             return INCOMING_SMS__SMS_TECH__SMS_TECH_CS_3GPP2;
296         } else {
297             return INCOMING_SMS__SMS_TECH__SMS_TECH_CS_3GPP;
298         }
299     }
300 
getIncomingSmsError(int result)301     private static int getIncomingSmsError(int result) {
302         switch (result) {
303             case Activity.RESULT_OK:
304             case Intents.RESULT_SMS_HANDLED:
305                 return INCOMING_SMS__ERROR__SMS_SUCCESS;
306             case Intents.RESULT_SMS_OUT_OF_MEMORY:
307                 return INCOMING_SMS__ERROR__SMS_ERROR_NO_MEMORY;
308             case Intents.RESULT_SMS_UNSUPPORTED:
309                 return INCOMING_SMS__ERROR__SMS_ERROR_NOT_SUPPORTED;
310             case Intents.RESULT_SMS_GENERIC_ERROR:
311             default:
312                 return INCOMING_SMS__ERROR__SMS_ERROR_GENERIC;
313         }
314     }
315 
getIncomingSmsError(boolean success)316     private static int getIncomingSmsError(boolean success) {
317         if (success) {
318             return INCOMING_SMS__ERROR__SMS_SUCCESS;
319         } else {
320             return INCOMING_SMS__ERROR__SMS_ERROR_GENERIC;
321         }
322     }
323 
getOutgoingSmsError(@endStatusResult int imsSendResult)324     private static int getOutgoingSmsError(@SendStatusResult int imsSendResult) {
325         switch (imsSendResult) {
326             case ImsSmsImplBase.SEND_STATUS_OK:
327                 return OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_SUCCESS;
328             case ImsSmsImplBase.SEND_STATUS_ERROR:
329                 return OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR;
330             case ImsSmsImplBase.SEND_STATUS_ERROR_RETRY:
331                 return OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR_RETRY;
332             case ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK:
333                 return OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR_FALLBACK;
334             default:
335                 return OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_UNKNOWN;
336         }
337     }
338 
339     /**
340      * Returns a hash value to identify messages that are identical for the purpose of merging them
341      * together when storage is full.
342      */
getSmsHashCode(OutgoingSms sms)343     static int getSmsHashCode(OutgoingSms sms) {
344         return Objects.hash(sms.smsFormat, sms.smsTech, sms.rat, sms.sendResult, sms.errorCode,
345                     sms.isRoaming, sms.isFromDefaultApp, sms.simSlotIndex, sms.isMultiSim,
346                     sms.isEsim, sms.carrierId);
347     }
348 
349     /**
350      * Returns a hash value to identify messages that are identical for the purpose of merging them
351      * together when storage is full.
352      */
getSmsHashCode(IncomingSms sms)353     static int getSmsHashCode(IncomingSms sms) {
354         return Objects.hash(sms.smsFormat, sms.smsTech, sms.rat, sms.smsType,
355             sms.totalParts, sms.receivedParts, sms.blocked, sms.error,
356             sms.isRoaming, sms.simSlotIndex, sms.isMultiSim, sms.isEsim, sms.carrierId);
357     }
358 
getPhoneId()359     private int getPhoneId() {
360         Phone phone = mPhone;
361         if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
362             phone = mPhone.getDefaultPhone();
363         }
364         return phone.getPhoneId();
365     }
366 
367     @Nullable
getServiceState()368     private ServiceState getServiceState() {
369         Phone phone = mPhone;
370         if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
371             phone = mPhone.getDefaultPhone();
372         }
373         ServiceStateTracker serviceStateTracker = phone.getServiceStateTracker();
374         return serviceStateTracker != null ? serviceStateTracker.getServiceState() : null;
375     }
376 
getRat(@nboundSmsHandler.SmsSource int smsSource)377     private @NetworkType int getRat(@InboundSmsHandler.SmsSource int smsSource) {
378         if (smsSource == SOURCE_INJECTED_FROM_UNKNOWN) {
379             return TelephonyManager.NETWORK_TYPE_UNKNOWN;
380         }
381         return getRat(smsSource == SOURCE_INJECTED_FROM_IMS);
382     }
383 
getRat(boolean isOverIms)384     private @NetworkType int getRat(boolean isOverIms) {
385         if (isOverIms) {
386             if (mPhone.getImsRegistrationTech()
387                     == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) {
388                 return TelephonyManager.NETWORK_TYPE_IWLAN;
389             }
390         }
391         // TODO(b/168837897): Returns the RAT at the time the SMS was received..
392         ServiceState serviceState = getServiceState();
393         return serviceState != null
394                 ? serviceState.getVoiceNetworkType() : TelephonyManager.NETWORK_TYPE_UNKNOWN;
395     }
396 
getIsRoaming()397     private boolean getIsRoaming() {
398         ServiceState serviceState = getServiceState();
399         return ServiceStateStats.isNetworkRoaming(serviceState);
400     }
401 
getCarrierId()402     private int getCarrierId() {
403         Phone phone = mPhone;
404         if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
405             phone = mPhone.getDefaultPhone();
406         }
407         return phone.getCarrierId();
408     }
409 
isNonTerrestrialNetwork()410     private boolean isNonTerrestrialNetwork() {
411         if (!Flags.carrierEnabledSatelliteFlag()) {
412             return false;
413         }
414 
415         ServiceState ss = getServiceState();
416         if (ss != null) {
417             return ss.isUsingNonTerrestrialNetwork();
418         } else {
419             Rlog.e(TAG, "isNonTerrestrialNetwork(), ServiceState is null");
420             return false;
421         }
422     }
423 
loge(String format, Object... args)424     private void loge(String format, Object... args) {
425         Rlog.e(TAG, "[" + mPhone.getPhoneId() + "]" + String.format(format, args));
426     }
427 }
428