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