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