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