• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.mms.service.metrics;
18 
19 import static com.android.mms.MmsStatsLog.INCOMING_MMS__RESULT__MMS_RESULT_ERROR_UNSPECIFIED;
20 import static com.android.mms.MmsStatsLog.INCOMING_MMS__RESULT__MMS_RESULT_SUCCESS;
21 import static com.android.mms.MmsStatsLog.OUTGOING_MMS__RESULT__MMS_RESULT_ERROR_UNSPECIFIED;
22 import static com.android.mms.MmsStatsLog.OUTGOING_MMS__RESULT__MMS_RESULT_SUCCESS;
23 
24 import android.app.Activity;
25 import android.content.Context;
26 import android.os.Binder;
27 import android.os.SystemClock;
28 import android.telephony.ServiceState;
29 import android.telephony.SmsManager;
30 import android.telephony.SubscriptionInfo;
31 import android.telephony.SubscriptionManager;
32 import android.telephony.TelephonyManager;
33 import android.telephony.UiccCardInfo;
34 
35 import com.android.internal.telephony.SmsApplication;
36 import com.android.mms.IncomingMms;
37 import com.android.mms.OutgoingMms;
38 
39 import java.util.List;
40 
41 /** Collects mms events for the pulled atom. */
42 public class MmsStats {
43     private static final String TAG = MmsStats.class.getSimpleName();
44 
45     private final Context mContext;
46     private final PersistMmsAtomsStorage mPersistMmsAtomsStorage;
47     private final String mCallingPkg;
48     private final boolean mIsIncomingMms;
49     private final long mTimestamp;
50     private int mSubId;
51     private TelephonyManager mTelephonyManager;
52 
MmsStats(Context context, PersistMmsAtomsStorage persistMmsAtomsStorage, int subId, TelephonyManager telephonyManager, String callingPkg, boolean isIncomingMms)53     public MmsStats(Context context, PersistMmsAtomsStorage persistMmsAtomsStorage, int subId,
54             TelephonyManager telephonyManager, String callingPkg, boolean isIncomingMms) {
55         mContext = context;
56         mPersistMmsAtomsStorage = persistMmsAtomsStorage;
57         mSubId = subId;
58         mTelephonyManager = telephonyManager;
59         mCallingPkg = callingPkg;
60         mIsIncomingMms = isIncomingMms;
61         mTimestamp = SystemClock.elapsedRealtime();
62     }
63 
64     /** Updates subId and corresponding telephonyManager. */
updateSubId(int subId, TelephonyManager telephonyManager)65     public void updateSubId(int subId, TelephonyManager telephonyManager) {
66         mSubId = subId;
67         mTelephonyManager = telephonyManager;
68     }
69 
70     /** Adds incoming or outgoing mms atom to storage. */
addAtomToStorage(int result)71     public void addAtomToStorage(int result) {
72         addAtomToStorage(result, 0, false);
73     }
74 
75     /** Adds incoming or outgoing mms atom to storage. */
addAtomToStorage(int result, int retryId, boolean handledByCarrierApp)76     public void addAtomToStorage(int result, int retryId, boolean handledByCarrierApp) {
77         long identity = Binder.clearCallingIdentity();
78         try {
79             if (mIsIncomingMms) {
80                 onIncomingMms(result, retryId, handledByCarrierApp);
81             } else {
82                 onOutgoingMms(result, retryId, handledByCarrierApp);
83             }
84         } finally {
85             Binder.restoreCallingIdentity(identity);
86         }
87     }
88 
89     /** Creates a new atom when MMS is received. */
onIncomingMms(int result, int retryId, boolean handledByCarrierApp)90     private void onIncomingMms(int result, int retryId, boolean handledByCarrierApp) {
91         IncomingMms incomingMms = IncomingMms.newBuilder()
92                 .setRat(getDataNetworkType())
93                 .setResult(getIncomingMmsResult(result))
94                 .setRoaming(getDataRoamingType())
95                 .setSimSlotIndex(getSlotIndex())
96                 .setIsMultiSim(getIsMultiSim())
97                 .setIsEsim(getIsEuicc())
98                 .setCarrierId(getSimCarrierId())
99                 .setAvgIntervalMillis(getInterval())
100                 .setMmsCount(1)
101                 .setRetryId(retryId)
102                 .setHandledByCarrierApp(handledByCarrierApp)
103                 .build();
104         mPersistMmsAtomsStorage.addIncomingMms(incomingMms);
105     }
106 
107     /** Creates a new atom when MMS is sent. */
onOutgoingMms(int result, int retryId, boolean handledByCarrierApp)108     private void onOutgoingMms(int result, int retryId, boolean handledByCarrierApp) {
109         OutgoingMms outgoingMms = OutgoingMms.newBuilder()
110                 .setRat(getDataNetworkType())
111                 .setResult(getOutgoingMmsResult(result))
112                 .setRoaming(getDataRoamingType())
113                 .setSimSlotIndex(getSlotIndex())
114                 .setIsMultiSim(getIsMultiSim())
115                 .setIsEsim(getIsEuicc())
116                 .setCarrierId(getSimCarrierId())
117                 .setAvgIntervalMillis(getInterval())
118                 .setMmsCount(1)
119                 .setIsFromDefaultApp(isDefaultMmsApp())
120                 .setRetryId(retryId)
121                 .setHandledByCarrierApp(handledByCarrierApp)
122                 .build();
123         mPersistMmsAtomsStorage.addOutgoingMms(outgoingMms);
124     }
125 
126     /** Returns data network type of current subscription. */
getDataNetworkType()127     private int getDataNetworkType() {
128         return mTelephonyManager.getDataNetworkType();
129     }
130 
131     /** Returns incoming mms result. */
getIncomingMmsResult(int result)132     private int getIncomingMmsResult(int result) {
133         switch (result) {
134             case SmsManager.MMS_ERROR_UNSPECIFIED:
135                 // SmsManager.MMS_ERROR_UNSPECIFIED(1) -> MMS_RESULT_ERROR_UNSPECIFIED(0)
136                 return INCOMING_MMS__RESULT__MMS_RESULT_ERROR_UNSPECIFIED;
137             case Activity.RESULT_OK:
138                 // Activity.RESULT_OK -> MMS_RESULT_SUCCESS(1)
139                 return INCOMING_MMS__RESULT__MMS_RESULT_SUCCESS;
140             default:
141                 // Int value of other SmsManager.MMS_ERROR matches MMS_RESULT_ERROR
142                 return result;
143         }
144     }
145 
146     /** Returns outgoing mms result. */
getOutgoingMmsResult(int result)147     private int getOutgoingMmsResult(int result) {
148         switch (result) {
149             case SmsManager.MMS_ERROR_UNSPECIFIED:
150                 // SmsManager.MMS_ERROR_UNSPECIFIED(1) -> MMS_RESULT_ERROR_UNSPECIFIED(0)
151                 return OUTGOING_MMS__RESULT__MMS_RESULT_ERROR_UNSPECIFIED;
152             case Activity.RESULT_OK:
153                 // Activity.RESULT_OK -> MMS_RESULT_SUCCESS(1)
154                 return OUTGOING_MMS__RESULT__MMS_RESULT_SUCCESS;
155             default:
156                 // Int value of other SmsManager.MMS_ERROR matches MMS_RESULT_ERROR
157                 return result;
158         }
159     }
160 
161     /** Returns data network roaming type of current subscription. */
getDataRoamingType()162     private int getDataRoamingType() {
163         ServiceState serviceState = mTelephonyManager.getServiceState();
164         return (serviceState != null) ? serviceState.getDataRoamingType() :
165                 ServiceState.ROAMING_TYPE_NOT_ROAMING;
166     }
167 
168     /** Returns slot index associated with the subscription. */
getSlotIndex()169     private int getSlotIndex() {
170         return SubscriptionManager.getSlotIndex(mSubId);
171     }
172 
173     /** Returns whether the device has multiple active SIM profiles. */
getIsMultiSim()174     private boolean getIsMultiSim() {
175         SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class);
176         if(subManager == null) {
177             return false;
178         }
179 
180         List<SubscriptionInfo> activeSubscriptionInfo = subManager.getActiveSubscriptionInfoList();
181         return (activeSubscriptionInfo.size() > 1);
182     }
183 
184     /** Returns if current subscription is embedded subscription. */
getIsEuicc()185     private boolean getIsEuicc() {
186         List<UiccCardInfo> uiccCardInfoList = mTelephonyManager.getUiccCardsInfo();
187         for (UiccCardInfo card : uiccCardInfoList) {
188             if (card.getPhysicalSlotIndex() == getSlotIndex()) {
189                 return card.isEuicc();
190             }
191         }
192         return false;
193     }
194 
195     /** Returns carrier id of the current subscription used by MMS. */
getSimCarrierId()196     private int getSimCarrierId() {
197         return mTelephonyManager.getSimCarrierId();
198     }
199 
200     /** Returns if the MMS was originated from the default MMS application. */
isDefaultMmsApp()201     private boolean isDefaultMmsApp() {
202         return SmsApplication.isDefaultMmsApplication(mContext, mCallingPkg);
203     }
204 
205     /**
206      * Returns the interval in milliseconds between sending/receiving MMS message and current time.
207      * Calculates the time taken to send message to the network
208      * or download message from the network.
209      */
getInterval()210     private long getInterval() {
211         return (SystemClock.elapsedRealtime() - mTimestamp);
212     }
213 }