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