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