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