1 /* 2 * Copyright (C) 2016 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.server.telecom.callfiltering; 18 19 import android.Manifest; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.ServiceConnection; 24 import android.content.pm.ResolveInfo; 25 import android.os.Binder; 26 import android.os.IBinder; 27 import android.os.RemoteException; 28 import android.os.UserHandle; 29 import android.telecom.CallScreeningService; 30 import android.telecom.Log; 31 import android.text.TextUtils; 32 33 import com.android.internal.telecom.ICallScreeningAdapter; 34 import com.android.internal.telecom.ICallScreeningService; 35 import com.android.server.telecom.Call; 36 import com.android.server.telecom.CallsManager; 37 import com.android.server.telecom.DefaultDialerCache; 38 import com.android.server.telecom.LogUtils; 39 import com.android.server.telecom.ParcelableCallUtils; 40 import com.android.server.telecom.PhoneAccountRegistrar; 41 import com.android.server.telecom.TelecomServiceImpl; 42 import com.android.server.telecom.TelecomSystem; 43 44 import java.util.List; 45 46 /** 47 * Binds to {@link ICallScreeningService} to allow call blocking. A single instance of this class 48 * handles a single call. 49 */ 50 public class CallScreeningServiceFilter implements IncomingCallFilter.CallFilter { 51 private class CallScreeningServiceConnection implements ServiceConnection { 52 @Override 53 public void onServiceConnected(ComponentName componentName, IBinder service) { 54 Log.startSession("CSCR.oSC"); 55 try { 56 synchronized (mTelecomLock) { 57 Log.addEvent(mCall, LogUtils.Events.SCREENING_BOUND, componentName); 58 if (!mHasFinished) { 59 onServiceBound(ICallScreeningService.Stub.asInterface(service)); 60 } 61 } 62 } finally { 63 Log.endSession(); 64 } 65 } 66 67 @Override 68 public void onServiceDisconnected(ComponentName componentName) { 69 Log.startSession("CSCR.oSD"); 70 try { 71 synchronized (mTelecomLock) { 72 finishCallScreening(); 73 } 74 } finally { 75 Log.endSession(); 76 } 77 } 78 } 79 80 private class CallScreeningAdapter extends ICallScreeningAdapter.Stub { 81 @Override 82 public void allowCall(String callId) { 83 Log.startSession("CSCR.aC"); 84 long token = Binder.clearCallingIdentity(); 85 try { 86 synchronized (mTelecomLock) { 87 Log.d(this, "allowCall(%s)", callId); 88 if (mCall != null && mCall.getId().equals(callId)) { 89 mResult = new CallFilteringResult( 90 true, // shouldAllowCall 91 false, //shouldReject 92 true, //shouldAddToCallLog 93 true // shouldShowNotification 94 ); 95 } else { 96 Log.w(this, "allowCall, unknown call id: %s", callId); 97 } 98 finishCallScreening(); 99 } 100 } finally { 101 Binder.restoreCallingIdentity(token); 102 Log.endSession(); 103 } 104 } 105 106 @Override 107 public void disallowCall( 108 String callId, 109 boolean shouldReject, 110 boolean shouldAddToCallLog, 111 boolean shouldShowNotification) { 112 Log.startSession("CSCR.dC"); 113 long token = Binder.clearCallingIdentity(); 114 try { 115 synchronized (mTelecomLock) { 116 Log.i(this, "disallowCall(%s), shouldReject: %b, shouldAddToCallLog: %b, " 117 + "shouldShowNotification: %b", callId, shouldReject, 118 shouldAddToCallLog, shouldShowNotification); 119 if (mCall != null && mCall.getId().equals(callId)) { 120 mResult = new CallFilteringResult( 121 false, // shouldAllowCall 122 shouldReject, //shouldReject 123 shouldAddToCallLog, //shouldAddToCallLog 124 shouldShowNotification // shouldShowNotification 125 ); 126 } else { 127 Log.w(this, "disallowCall, unknown call id: %s", callId); 128 } 129 finishCallScreening(); 130 } 131 } finally { 132 Binder.restoreCallingIdentity(token); 133 Log.endSession(); 134 } 135 } 136 } 137 138 private final Context mContext; 139 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 140 private final CallsManager mCallsManager; 141 private final DefaultDialerCache mDefaultDialerCache; 142 private final ParcelableCallUtils.Converter mParcelableCallUtilsConverter; 143 private final TelecomSystem.SyncRoot mTelecomLock; 144 145 private Call mCall; 146 private CallFilterResultCallback mCallback; 147 private ICallScreeningService mService; 148 private ServiceConnection mConnection; 149 150 private boolean mHasFinished = false; 151 private CallFilteringResult mResult = new CallFilteringResult( 152 true, // shouldAllowCall 153 false, //shouldReject 154 true, //shouldAddToCallLog 155 true // shouldShowNotification 156 ); 157 158 public CallScreeningServiceFilter( 159 Context context, 160 CallsManager callsManager, 161 PhoneAccountRegistrar phoneAccountRegistrar, 162 DefaultDialerCache defaultDialerCache, 163 ParcelableCallUtils.Converter parcelableCallUtilsConverter, 164 TelecomSystem.SyncRoot lock) { 165 mContext = context; 166 mPhoneAccountRegistrar = phoneAccountRegistrar; 167 mCallsManager = callsManager; 168 mDefaultDialerCache = defaultDialerCache; 169 mParcelableCallUtilsConverter = parcelableCallUtilsConverter; 170 mTelecomLock = lock; 171 } 172 173 @Override 174 public void startFilterLookup(Call call, CallFilterResultCallback callback) { 175 if (mHasFinished) { 176 Log.w(this, "Attempting to reuse CallScreeningServiceFilter. Ignoring."); 177 return; 178 } 179 Log.addEvent(call, LogUtils.Events.SCREENING_SENT); 180 mCall = call; 181 mCallback = callback; 182 if (!bindService()) { 183 Log.i(this, "Could not bind to call screening service"); 184 finishCallScreening(); 185 } 186 } 187 188 private void finishCallScreening() { 189 if (!mHasFinished) { 190 Log.addEvent(mCall, LogUtils.Events.SCREENING_COMPLETED, mResult); 191 mCallback.onCallFilteringComplete(mCall, mResult); 192 193 if (mConnection != null) { 194 // We still need to call unbind even if the service disconnected. 195 mContext.unbindService(mConnection); 196 mConnection = null; 197 } 198 mService = null; 199 mHasFinished = true; 200 } 201 } 202 203 private boolean bindService() { 204 String dialerPackage = mDefaultDialerCache 205 .getDefaultDialerApplication(UserHandle.USER_CURRENT); 206 if (TextUtils.isEmpty(dialerPackage)) { 207 Log.i(this, "Default dialer is empty. Not performing call screening."); 208 return false; 209 } 210 211 Intent intent = new Intent(CallScreeningService.SERVICE_INTERFACE) 212 .setPackage(dialerPackage); 213 List<ResolveInfo> entries = mContext.getPackageManager().queryIntentServicesAsUser( 214 intent, 0, mCallsManager.getCurrentUserHandle().getIdentifier()); 215 if (entries.isEmpty()) { 216 Log.i(this, "There are no call screening services installed on this device."); 217 return false; 218 } 219 220 ResolveInfo entry = entries.get(0); 221 if (entry.serviceInfo == null) { 222 Log.w(this, "The call screening service has invalid service info"); 223 return false; 224 } 225 226 if (entry.serviceInfo.permission == null || !entry.serviceInfo.permission.equals( 227 Manifest.permission.BIND_SCREENING_SERVICE)) { 228 Log.w(this, "CallScreeningService must require BIND_SCREENING_SERVICE permission: " + 229 entry.serviceInfo.packageName); 230 return false; 231 } 232 233 ComponentName componentName = 234 new ComponentName(entry.serviceInfo.packageName, entry.serviceInfo.name); 235 Log.addEvent(mCall, LogUtils.Events.BIND_SCREENING, componentName); 236 intent.setComponent(componentName); 237 ServiceConnection connection = new CallScreeningServiceConnection(); 238 if (mContext.bindServiceAsUser( 239 intent, 240 connection, 241 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, 242 UserHandle.CURRENT)) { 243 Log.d(this, "bindService, found service, waiting for it to connect"); 244 mConnection = connection; 245 return true; 246 } 247 248 return false; 249 } 250 251 private void onServiceBound(ICallScreeningService service) { 252 mService = service; 253 try { 254 mService.screenCall(new CallScreeningAdapter(), 255 mParcelableCallUtilsConverter.toParcelableCall( 256 mCall, 257 false, /* includeVideoProvider */ 258 mPhoneAccountRegistrar)); 259 } catch (RemoteException e) { 260 Log.e(this, e, "Failed to set the call screening adapter."); 261 finishCallScreening(); 262 } 263 } 264 } 265