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