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