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