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.RemoteException; 25 import android.service.carrier.CarrierMessagingService; 26 import android.service.carrier.ICarrierMessagingCallback; 27 import android.service.carrier.ICarrierMessagingService; 28 import android.service.carrier.MessagePdu; 29 import android.telephony.CarrierMessagingServiceManager; 30 import android.telephony.Rlog; 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 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.List; 39 import java.util.Optional; 40 41 /** 42 * Filters incoming SMS with carrier services. 43 * <p> A new instance must be created for filtering each message. 44 */ 45 public class CarrierServicesSmsFilter { 46 protected static final boolean DBG = true; 47 48 private final Context mContext; 49 private final Phone mPhone; 50 private final byte[][] mPdus; 51 private final int mDestPort; 52 private final String mPduFormat; 53 private final CarrierServicesSmsFilterCallbackInterface mCarrierServicesSmsFilterCallback; 54 private final String mLogTag; 55 56 @VisibleForTesting CarrierServicesSmsFilter( Context context, Phone phone, byte[][] pdus, int destPort, String pduFormat, CarrierServicesSmsFilterCallbackInterface carrierServicesSmsFilterCallback, String logTag)57 public CarrierServicesSmsFilter( 58 Context context, 59 Phone phone, 60 byte[][] pdus, 61 int destPort, 62 String pduFormat, 63 CarrierServicesSmsFilterCallbackInterface carrierServicesSmsFilterCallback, 64 String logTag) { 65 mContext = context; 66 mPhone = phone; 67 mPdus = pdus; 68 mDestPort = destPort; 69 mPduFormat = pduFormat; 70 mCarrierServicesSmsFilterCallback = carrierServicesSmsFilterCallback; 71 mLogTag = logTag; 72 } 73 74 /** 75 * @return {@code true} if the SMS was handled by carrier services. 76 */ 77 @VisibleForTesting filter()78 public boolean filter() { 79 Optional<String> carrierAppForFiltering = getCarrierAppPackageForFiltering(); 80 List<String> smsFilterPackages = new ArrayList<>(); 81 if (carrierAppForFiltering.isPresent()) { 82 smsFilterPackages.add(carrierAppForFiltering.get()); 83 } 84 String carrierImsPackage = CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone, 85 new Intent(CarrierMessagingService.SERVICE_INTERFACE)); 86 if (carrierImsPackage != null) { 87 smsFilterPackages.add(carrierImsPackage); 88 } 89 FilterAggregator filterAggregator = new FilterAggregator(smsFilterPackages.size()); 90 for (String smsFilterPackage : smsFilterPackages) { 91 filterWithPackage(smsFilterPackage, filterAggregator); 92 } 93 boolean handled = smsFilterPackages.size() > 0; 94 return handled; 95 } 96 getCarrierAppPackageForFiltering()97 private Optional<String> getCarrierAppPackageForFiltering() { 98 List<String> carrierPackages = null; 99 UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId()); 100 if (card != null) { 101 carrierPackages = card.getCarrierPackageNamesForIntent( 102 mContext.getPackageManager(), 103 new Intent(CarrierMessagingService.SERVICE_INTERFACE)); 104 } else { 105 Rlog.e(mLogTag, "UiccCard not initialized."); 106 } 107 if (carrierPackages != null && carrierPackages.size() == 1) { 108 log("Found carrier package."); 109 return Optional.of(carrierPackages.get(0)); 110 } 111 112 // It is possible that carrier app is not present as a CarrierPackage, but instead as a 113 // system app 114 List<String> systemPackages = 115 getSystemAppForIntent(new Intent(CarrierMessagingService.SERVICE_INTERFACE)); 116 117 if (systemPackages != null && systemPackages.size() == 1) { 118 log("Found system package."); 119 return Optional.of(systemPackages.get(0)); 120 } 121 logv("Unable to find carrier package: " + carrierPackages 122 + ", nor systemPackages: " + systemPackages); 123 return Optional.empty(); 124 } 125 filterWithPackage(String packageName, FilterAggregator filterAggregator)126 private void filterWithPackage(String packageName, FilterAggregator filterAggregator) { 127 CarrierSmsFilter smsFilter = new CarrierSmsFilter(mPdus, mDestPort, mPduFormat); 128 CarrierSmsFilterCallback smsFilterCallback = 129 new CarrierSmsFilterCallback(filterAggregator, smsFilter); 130 smsFilter.filterSms(packageName, smsFilterCallback); 131 } 132 getSystemAppForIntent(Intent intent)133 private List<String> getSystemAppForIntent(Intent intent) { 134 List<String> packages = new ArrayList<String>(); 135 PackageManager packageManager = mContext.getPackageManager(); 136 List<ResolveInfo> receivers = packageManager.queryIntentServices(intent, 0); 137 String carrierFilterSmsPerm = "android.permission.CARRIER_FILTER_SMS"; 138 139 for (ResolveInfo info : receivers) { 140 if (info.serviceInfo == null) { 141 loge("Can't get service information from " + info); 142 continue; 143 } 144 String packageName = info.serviceInfo.packageName; 145 if (packageManager.checkPermission(carrierFilterSmsPerm, packageName) 146 == packageManager.PERMISSION_GRANTED) { 147 packages.add(packageName); 148 if (DBG) log("getSystemAppForIntent: added package " + packageName); 149 } 150 } 151 return packages; 152 } 153 log(String message)154 private void log(String message) { 155 Rlog.d(mLogTag, message); 156 } 157 loge(String message)158 private void loge(String message) { 159 Rlog.e(mLogTag, message); 160 } 161 logv(String message)162 private void logv(String message) { 163 Rlog.e(mLogTag, message); 164 } 165 166 /** 167 * Result of filtering SMS is returned in this callback. 168 */ 169 @VisibleForTesting 170 public interface CarrierServicesSmsFilterCallbackInterface { onFilterComplete(int result)171 void onFilterComplete(int result); 172 } 173 174 /** 175 * Asynchronously binds to the carrier messaging service, and filters out the message if 176 * instructed to do so by the carrier messaging service. A new instance must be used for every 177 * message. 178 */ 179 private final class CarrierSmsFilter extends CarrierMessagingServiceManager { 180 private final byte[][] mPdus; 181 private final int mDestPort; 182 private final String mSmsFormat; 183 // Instantiated in filterSms. 184 private volatile CarrierSmsFilterCallback mSmsFilterCallback; 185 CarrierSmsFilter(byte[][] pdus, int destPort, String smsFormat)186 CarrierSmsFilter(byte[][] pdus, int destPort, String smsFormat) { 187 mPdus = pdus; 188 mDestPort = destPort; 189 mSmsFormat = smsFormat; 190 } 191 192 /** 193 * Attempts to bind to a {@link ICarrierMessagingService}. Filtering is initiated 194 * asynchronously once the service is ready using {@link #onServiceReady}. 195 */ filterSms(String carrierPackageName, CarrierSmsFilterCallback smsFilterCallback)196 void filterSms(String carrierPackageName, CarrierSmsFilterCallback smsFilterCallback) { 197 mSmsFilterCallback = smsFilterCallback; 198 if (!bindToCarrierMessagingService(mContext, carrierPackageName)) { 199 loge("bindService() for carrier messaging service failed"); 200 smsFilterCallback.onFilterComplete(CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT); 201 } else { 202 logv("bindService() for carrier messaging service succeeded"); 203 } 204 } 205 206 /** 207 * Invokes the {@code carrierMessagingService} to filter messages. The filtering result is 208 * delivered to {@code smsFilterCallback}. 209 */ 210 @Override onServiceReady(ICarrierMessagingService carrierMessagingService)211 protected void onServiceReady(ICarrierMessagingService carrierMessagingService) { 212 try { 213 carrierMessagingService.filterSms( 214 new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort, 215 mPhone.getSubId(), mSmsFilterCallback); 216 } catch (RemoteException e) { 217 loge("Exception filtering the SMS: " + e); 218 mSmsFilterCallback.onFilterComplete( 219 CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT); 220 } 221 } 222 } 223 224 /** 225 * A callback used to notify the platform of the carrier messaging app filtering result. Once 226 * the result is ready, the carrier messaging service connection is disposed. 227 */ 228 private final class CarrierSmsFilterCallback extends ICarrierMessagingCallback.Stub { 229 private final FilterAggregator mFilterAggregator; 230 private final CarrierMessagingServiceManager mCarrierMessagingServiceManager; 231 CarrierSmsFilterCallback(FilterAggregator filterAggregator, CarrierMessagingServiceManager carrierMessagingServiceManager)232 CarrierSmsFilterCallback(FilterAggregator filterAggregator, 233 CarrierMessagingServiceManager carrierMessagingServiceManager) { 234 mFilterAggregator = filterAggregator; 235 mCarrierMessagingServiceManager = carrierMessagingServiceManager; 236 } 237 238 /** 239 * This method should be called only once. 240 */ 241 @Override onFilterComplete(int result)242 public void onFilterComplete(int result) { 243 mCarrierMessagingServiceManager.disposeConnection(mContext); 244 mFilterAggregator.onFilterComplete(result); 245 } 246 247 @Override onSendSmsComplete(int result, int messageRef)248 public void onSendSmsComplete(int result, int messageRef) { 249 loge("Unexpected onSendSmsComplete call with result: " + result); 250 } 251 252 @Override onSendMultipartSmsComplete(int result, int[] messageRefs)253 public void onSendMultipartSmsComplete(int result, int[] messageRefs) { 254 loge("Unexpected onSendMultipartSmsComplete call with result: " + result); 255 } 256 257 @Override onSendMmsComplete(int result, byte[] sendConfPdu)258 public void onSendMmsComplete(int result, byte[] sendConfPdu) { 259 loge("Unexpected onSendMmsComplete call with result: " + result); 260 } 261 262 @Override onDownloadMmsComplete(int result)263 public void onDownloadMmsComplete(int result) { 264 loge("Unexpected onDownloadMmsComplete call with result: " + result); 265 } 266 } 267 268 private final class FilterAggregator { 269 private final Object mFilterLock = new Object(); 270 private int mNumPendingFilters; 271 private int mFilterResult; 272 FilterAggregator(int numFilters)273 FilterAggregator(int numFilters) { 274 mNumPendingFilters = numFilters; 275 mFilterResult = CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT; 276 } 277 onFilterComplete(int result)278 void onFilterComplete(int result) { 279 synchronized (mFilterLock) { 280 mNumPendingFilters--; 281 combine(result); 282 if (mNumPendingFilters == 0) { 283 // Calling identity was the CarrierMessagingService in this callback, change it 284 // back to ours. 285 long token = Binder.clearCallingIdentity(); 286 try { 287 mCarrierServicesSmsFilterCallback.onFilterComplete(mFilterResult); 288 } finally { 289 // return back to the CarrierMessagingService, restore the calling identity. 290 Binder.restoreCallingIdentity(token); 291 } 292 } 293 } 294 } 295 combine(int result)296 private void combine(int result) { 297 mFilterResult = mFilterResult | result; 298 } 299 } 300 } 301