• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.pm.PackageManager;
22 import android.content.pm.ResolveInfo;
23 import android.os.Binder;
24 import android.os.Handler;
25 import android.os.Message;
26 import android.os.RemoteException;
27 import android.service.carrier.CarrierMessagingService;
28 import android.service.carrier.ICarrierMessagingCallback;
29 import android.service.carrier.ICarrierMessagingService;
30 import android.service.carrier.MessagePdu;
31 import android.telephony.CarrierMessagingServiceManager;
32 import android.telephony.Rlog;
33 import android.util.LocalLog;
34 
35 import com.android.internal.annotations.VisibleForTesting;
36 import com.android.internal.telephony.uicc.UiccCard;
37 import com.android.internal.telephony.uicc.UiccController;
38 
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Optional;
44 import java.util.Set;
45 
46 /**
47  * Filters incoming SMS with carrier services.
48  * <p> A new instance must be created for filtering each message.
49  */
50 public class CarrierServicesSmsFilter {
51     protected static final boolean DBG = true;
52     /** onFilterComplete is not called. */
53     public static final int EVENT_ON_FILTER_COMPLETE_NOT_CALLED = 1;
54 
55     /** onFilterComplete timeout. */
56     public static final int FILTER_COMPLETE_TIMEOUT_MS = 10 * 60 * 1000; //10 minutes
57 
58     private final Context mContext;
59     private final Phone mPhone;
60     private final byte[][] mPdus;
61     private final int mDestPort;
62     private final String mPduFormat;
63     private final CarrierServicesSmsFilterCallbackInterface mCarrierServicesSmsFilterCallback;
64     private final String mLogTag;
65     private final CallbackTimeoutHandler mCallbackTimeoutHandler;
66     private final LocalLog mLocalLog;
67     private FilterAggregator mFilterAggregator;
68 
69     @VisibleForTesting
CarrierServicesSmsFilter( Context context, Phone phone, byte[][] pdus, int destPort, String pduFormat, CarrierServicesSmsFilterCallbackInterface carrierServicesSmsFilterCallback, String logTag, LocalLog localLog)70     public CarrierServicesSmsFilter(
71             Context context,
72             Phone phone,
73             byte[][] pdus,
74             int destPort,
75             String pduFormat,
76             CarrierServicesSmsFilterCallbackInterface carrierServicesSmsFilterCallback,
77             String logTag,
78             LocalLog localLog) {
79         mContext = context;
80         mPhone = phone;
81         mPdus = pdus;
82         mDestPort = destPort;
83         mPduFormat = pduFormat;
84         mCarrierServicesSmsFilterCallback = carrierServicesSmsFilterCallback;
85         mLogTag = logTag;
86         mCallbackTimeoutHandler = new CallbackTimeoutHandler();
87         mLocalLog = localLog;
88     }
89 
90     /**
91      * @return {@code true} if the SMS was handled by carrier services.
92      */
93     @VisibleForTesting
filter()94     public boolean filter() {
95         Optional<String> carrierAppForFiltering = getCarrierAppPackageForFiltering();
96         List<String> smsFilterPackages = new ArrayList<>();
97         if (carrierAppForFiltering.isPresent()) {
98             smsFilterPackages.add(carrierAppForFiltering.get());
99         }
100         String carrierImsPackage = CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
101                 new Intent(CarrierMessagingService.SERVICE_INTERFACE));
102         if (carrierImsPackage != null) {
103             smsFilterPackages.add(carrierImsPackage);
104         }
105 
106         if (mFilterAggregator != null) {
107             String errMsg = "Cannot reuse the same CarrierServiceSmsFilter object for filtering.";
108             loge(errMsg);
109             throw new RuntimeException(errMsg);
110         }
111 
112         int numPackages = smsFilterPackages.size();
113         if (numPackages > 0) {
114             mFilterAggregator = new FilterAggregator(numPackages);
115             //start the timer
116             mCallbackTimeoutHandler.sendMessageDelayed(mCallbackTimeoutHandler
117                             .obtainMessage(EVENT_ON_FILTER_COMPLETE_NOT_CALLED),
118                     FILTER_COMPLETE_TIMEOUT_MS);
119             for (String smsFilterPackage : smsFilterPackages) {
120                 filterWithPackage(smsFilterPackage, mFilterAggregator);
121             }
122             return true;
123         } else {
124             return false;
125         }
126     }
127 
getCarrierAppPackageForFiltering()128     private Optional<String> getCarrierAppPackageForFiltering() {
129         List<String> carrierPackages = null;
130         UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
131         if (card != null) {
132             carrierPackages = card.getCarrierPackageNamesForIntent(
133                     mContext.getPackageManager(),
134                     new Intent(CarrierMessagingService.SERVICE_INTERFACE));
135         } else {
136             Rlog.e(mLogTag, "UiccCard not initialized.");
137         }
138         if (carrierPackages != null && carrierPackages.size() == 1) {
139             log("Found carrier package.");
140             return Optional.of(carrierPackages.get(0));
141         }
142 
143         // It is possible that carrier app is not present as a CarrierPackage, but instead as a
144         // system app
145         List<String> systemPackages =
146                 getSystemAppForIntent(new Intent(CarrierMessagingService.SERVICE_INTERFACE));
147 
148         if (systemPackages != null && systemPackages.size() == 1) {
149             log("Found system package.");
150             return Optional.of(systemPackages.get(0));
151         }
152         logv("Unable to find carrier package: " + carrierPackages
153                 + ", nor systemPackages: " + systemPackages);
154         return Optional.empty();
155     }
156 
filterWithPackage(String packageName, FilterAggregator filterAggregator)157     private void filterWithPackage(String packageName, FilterAggregator filterAggregator) {
158         CarrierSmsFilter smsFilter = new CarrierSmsFilter(mPdus, mDestPort, mPduFormat);
159         CarrierSmsFilterCallback smsFilterCallback =
160                 new CarrierSmsFilterCallback(filterAggregator, smsFilter);
161         filterAggregator.addToCallbacks(smsFilterCallback);
162 
163         smsFilter.filterSms(packageName, smsFilterCallback);
164     }
165 
getSystemAppForIntent(Intent intent)166     private List<String> getSystemAppForIntent(Intent intent) {
167         List<String> packages = new ArrayList<String>();
168         PackageManager packageManager = mContext.getPackageManager();
169         List<ResolveInfo> receivers = packageManager.queryIntentServices(intent, 0);
170         String carrierFilterSmsPerm = "android.permission.CARRIER_FILTER_SMS";
171 
172         for (ResolveInfo info : receivers) {
173             if (info.serviceInfo == null) {
174                 loge("Can't get service information from " + info);
175                 continue;
176             }
177             String packageName = info.serviceInfo.packageName;
178             if (packageManager.checkPermission(carrierFilterSmsPerm, packageName)
179                     == packageManager.PERMISSION_GRANTED) {
180                 packages.add(packageName);
181                 if (DBG) log("getSystemAppForIntent: added package " + packageName);
182             }
183         }
184         return packages;
185     }
186 
log(String message)187     private void log(String message) {
188         Rlog.d(mLogTag, message);
189     }
190 
loge(String message)191     private void loge(String message) {
192         Rlog.e(mLogTag, message);
193     }
194 
logv(String message)195     private void logv(String message) {
196         Rlog.e(mLogTag, message);
197     }
198 
199     /**
200      * Result of filtering SMS is returned in this callback.
201      */
202     @VisibleForTesting
203     public interface CarrierServicesSmsFilterCallbackInterface {
onFilterComplete(int result)204         void onFilterComplete(int result);
205     }
206 
207     /**
208      * Asynchronously binds to the carrier messaging service, and filters out the message if
209      * instructed to do so by the carrier messaging service. A new instance must be used for every
210      * message.
211      */
212     private final class CarrierSmsFilter extends CarrierMessagingServiceManager {
213         private final byte[][] mPdus;
214         private final int mDestPort;
215         private final String mSmsFormat;
216         // Instantiated in filterSms.
217         private volatile CarrierSmsFilterCallback mSmsFilterCallback;
218 
CarrierSmsFilter(byte[][] pdus, int destPort, String smsFormat)219         CarrierSmsFilter(byte[][] pdus, int destPort, String smsFormat) {
220             mPdus = pdus;
221             mDestPort = destPort;
222             mSmsFormat = smsFormat;
223         }
224 
225         /**
226          * Attempts to bind to a {@link ICarrierMessagingService}. Filtering is initiated
227          * asynchronously once the service is ready using {@link #onServiceReady}.
228          */
filterSms(String carrierPackageName, CarrierSmsFilterCallback smsFilterCallback)229         void filterSms(String carrierPackageName, CarrierSmsFilterCallback smsFilterCallback) {
230             mSmsFilterCallback = smsFilterCallback;
231             if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
232                 loge("bindService() for carrier messaging service failed");
233                 smsFilterCallback.onFilterComplete(CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
234             } else {
235                 logv("bindService() for carrier messaging service succeeded");
236             }
237         }
238 
239         /**
240          * Invokes the {@code carrierMessagingService} to filter messages. The filtering result is
241          * delivered to {@code smsFilterCallback}.
242          */
243         @Override
onServiceReady(ICarrierMessagingService carrierMessagingService)244         protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
245             try {
246                 log("onServiceReady: calling filterSms");
247                 carrierMessagingService.filterSms(
248                         new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort,
249                         mPhone.getSubId(), mSmsFilterCallback);
250             } catch (RemoteException e) {
251                 loge("Exception filtering the SMS: " + e);
252                 mSmsFilterCallback.onFilterComplete(
253                         CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
254             }
255         }
256     }
257 
258     /**
259      * A callback used to notify the platform of the carrier messaging app filtering result. Once
260      * the result is ready, the carrier messaging service connection is disposed.
261      */
262     private final class CarrierSmsFilterCallback extends ICarrierMessagingCallback.Stub {
263         private final FilterAggregator mFilterAggregator;
264         private final CarrierMessagingServiceManager mCarrierMessagingServiceManager;
265         private boolean mIsOnFilterCompleteCalled;
266 
CarrierSmsFilterCallback(FilterAggregator filterAggregator, CarrierMessagingServiceManager carrierMessagingServiceManager)267         CarrierSmsFilterCallback(FilterAggregator filterAggregator,
268                 CarrierMessagingServiceManager carrierMessagingServiceManager) {
269             mFilterAggregator = filterAggregator;
270             mCarrierMessagingServiceManager = carrierMessagingServiceManager;
271             mIsOnFilterCompleteCalled = false;
272         }
273 
274         /**
275          * This method should be called only once.
276          */
277         @Override
onFilterComplete(int result)278         public void onFilterComplete(int result) {
279             log("onFilterComplete called with result: " + result);
280             // in the case that timeout has already passed and triggered, but the initial callback
281             // is run afterwards, we should not follow through
282             if (!mIsOnFilterCompleteCalled) {
283                 mIsOnFilterCompleteCalled = true;
284                 mCarrierMessagingServiceManager.disposeConnection(mContext);
285                 mFilterAggregator.onFilterComplete(result);
286             }
287         }
288 
289         @Override
onSendSmsComplete(int result, int messageRef)290         public void onSendSmsComplete(int result, int messageRef) {
291             loge("Unexpected onSendSmsComplete call with result: " + result);
292         }
293 
294         @Override
onSendMultipartSmsComplete(int result, int[] messageRefs)295         public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
296             loge("Unexpected onSendMultipartSmsComplete call with result: " + result);
297         }
298 
299         @Override
onSendMmsComplete(int result, byte[] sendConfPdu)300         public void onSendMmsComplete(int result, byte[] sendConfPdu) {
301             loge("Unexpected onSendMmsComplete call with result: " + result);
302         }
303 
304         @Override
onDownloadMmsComplete(int result)305         public void onDownloadMmsComplete(int result) {
306             loge("Unexpected onDownloadMmsComplete call with result: " + result);
307         }
308     }
309 
310     private final class FilterAggregator {
311         private final Object mFilterLock = new Object();
312         private int mNumPendingFilters;
313         private final Set<CarrierSmsFilterCallback> mCallbacks;
314         private int mFilterResult;
315 
FilterAggregator(int numFilters)316         FilterAggregator(int numFilters) {
317             mNumPendingFilters = numFilters;
318             mCallbacks = new HashSet<>();
319             mFilterResult = CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT;
320         }
321 
onFilterComplete(int result)322         void onFilterComplete(int result) {
323             synchronized (mFilterLock) {
324                 mNumPendingFilters--;
325                 combine(result);
326                 if (mNumPendingFilters == 0) {
327                     // Calling identity was the CarrierMessagingService in this callback, change it
328                     // back to ours.
329                     long token = Binder.clearCallingIdentity();
330                     try {
331                         mCarrierServicesSmsFilterCallback.onFilterComplete(mFilterResult);
332                     } finally {
333                         // return back to the CarrierMessagingService, restore the calling identity.
334                         Binder.restoreCallingIdentity(token);
335                     }
336                     //all onFilterCompletes called before timeout has triggered
337                     //remove the pending message
338                     log("onFilterComplete: called successfully with result = " + result);
339                     mCallbackTimeoutHandler.removeMessages(EVENT_ON_FILTER_COMPLETE_NOT_CALLED);
340                 } else {
341                     log("onFilterComplete: waiting for pending filters " + mNumPendingFilters);
342                 }
343             }
344         }
345 
combine(int result)346         private void combine(int result) {
347             mFilterResult = mFilterResult | result;
348         }
349 
addToCallbacks(CarrierSmsFilterCallback callback)350         private void addToCallbacks(CarrierSmsFilterCallback callback) {
351             mCallbacks.add(callback);
352         }
353 
354     }
355 
356     protected final class CallbackTimeoutHandler extends Handler {
357 
358         private static final boolean DBG = true;
359 
360         @Override
handleMessage(Message msg)361         public void handleMessage(Message msg) {
362             if (DBG) {
363                 log("CallbackTimeoutHandler handleMessage(" + msg.what + ")");
364             }
365 
366             switch(msg.what) {
367                 case EVENT_ON_FILTER_COMPLETE_NOT_CALLED:
368                     mLocalLog.log("CarrierServicesSmsFilter: onFilterComplete timeout: not"
369                             + " called before " + FILTER_COMPLETE_TIMEOUT_MS + " milliseconds.");
370                     handleFilterCallbacksTimeout();
371                     break;
372             }
373         }
374 
handleFilterCallbacksTimeout()375         private void handleFilterCallbacksTimeout() {
376             for (CarrierSmsFilterCallback callback : mFilterAggregator.mCallbacks) {
377                 log("handleFilterCallbacksTimeout: calling onFilterComplete");
378                 callback.onFilterComplete(CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
379             }
380         }
381     }
382 }
383