TelecomServiceImpl.java revision a53eb7f3b260c0601f0a01dae597a789450b2872
1/* 2 * Copyright (C) 2014 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 17package com.android.server.telecom; 18 19import android.Manifest; 20import android.app.AppOpsManager; 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.content.pm.PackageManager; 25import android.content.res.Resources; 26import android.os.Binder; 27import android.os.Bundle; 28import android.os.Handler; 29import android.os.IBinder; 30import android.os.Looper; 31import android.os.Message; 32import android.os.ServiceManager; 33import android.os.UserHandle; 34import android.telecom.CallState; 35import android.telecom.PhoneAccount; 36import android.telecom.PhoneAccountHandle; 37import android.telecom.TelecomManager; 38import android.telephony.TelephonyManager; 39 40import com.android.internal.telecom.ITelecomService; 41 42import java.util.List; 43 44/** 45 * Implementation of the ITelecom interface. 46 */ 47public class TelecomServiceImpl extends ITelecomService.Stub { 48 private static final String REGISTER_PROVIDER_OR_SUBSCRIPTION = 49 "com.android.server.telecom.permission.REGISTER_PROVIDER_OR_SUBSCRIPTION"; 50 51 /** ${inheritDoc} */ 52 @Override 53 public IBinder asBinder() { 54 return super.asBinder(); 55 } 56 57 /** 58 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the 59 * request after sending. The main thread will notify the request when it is complete. 60 */ 61 private static final class MainThreadRequest { 62 /** The result of the request that is run on the main thread */ 63 public Object result; 64 } 65 66 /** 67 * A handler that processes messages on the main thread in the phone process. Since many 68 * of the Phone calls are not thread safe this is needed to shuttle the requests from the 69 * inbound binder threads to the main thread in the phone process. 70 */ 71 private final class MainThreadHandler extends Handler { 72 @Override 73 public void handleMessage(Message msg) { 74 if (msg.obj instanceof MainThreadRequest) { 75 MainThreadRequest request = (MainThreadRequest) msg.obj; 76 Object result = null; 77 switch (msg.what) { 78 case MSG_SILENCE_RINGER: 79 mCallsManager.getRinger().silence(); 80 break; 81 case MSG_SHOW_CALL_SCREEN: 82 mCallsManager.getInCallController().bringToForeground(msg.arg1 == 1); 83 break; 84 case MSG_END_CALL: 85 result = endCallInternal(); 86 break; 87 case MSG_ACCEPT_RINGING_CALL: 88 acceptRingingCallInternal(); 89 break; 90 case MSG_CANCEL_MISSED_CALLS_NOTIFICATION: 91 mMissedCallNotifier.clearMissedCalls(); 92 break; 93 case MSG_IS_TTY_SUPPORTED: 94 result = mCallsManager.isTtySupported(); 95 break; 96 case MSG_GET_CURRENT_TTY_MODE: 97 result = mCallsManager.getCurrentTtyMode(); 98 break; 99 } 100 101 if (result != null) { 102 request.result = result; 103 synchronized(request) { 104 request.notifyAll(); 105 } 106 } 107 } 108 } 109 } 110 111 /** Private constructor; @see init() */ 112 private static final String TAG = TelecomServiceImpl.class.getSimpleName(); 113 114 private static final String SERVICE_NAME = "telecom"; 115 116 private static final int MSG_SILENCE_RINGER = 1; 117 private static final int MSG_SHOW_CALL_SCREEN = 2; 118 private static final int MSG_END_CALL = 3; 119 private static final int MSG_ACCEPT_RINGING_CALL = 4; 120 private static final int MSG_CANCEL_MISSED_CALLS_NOTIFICATION = 5; 121 private static final int MSG_IS_TTY_SUPPORTED = 6; 122 private static final int MSG_GET_CURRENT_TTY_MODE = 7; 123 124 /** The singleton instance. */ 125 private static TelecomServiceImpl sInstance; 126 127 private final MainThreadHandler mMainThreadHandler = new MainThreadHandler(); 128 private final CallsManager mCallsManager = CallsManager.getInstance(); 129 private final MissedCallNotifier mMissedCallNotifier; 130 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 131 private final AppOpsManager mAppOpsManager; 132 133 private TelecomServiceImpl( 134 MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar) { 135 mMissedCallNotifier = missedCallNotifier; 136 mPhoneAccountRegistrar = phoneAccountRegistrar; 137 mAppOpsManager = 138 (AppOpsManager) TelecomApp.getInstance().getSystemService(Context.APP_OPS_SERVICE); 139 140 publish(); 141 } 142 143 /** 144 * Initialize the singleton TelecommServiceImpl instance. 145 * This is only done once, at startup, from TelecommApp.onCreate(). 146 */ 147 static TelecomServiceImpl init( 148 MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar) { 149 synchronized (TelecomServiceImpl.class) { 150 if (sInstance == null) { 151 sInstance = new TelecomServiceImpl(missedCallNotifier, phoneAccountRegistrar); 152 } else { 153 Log.wtf(TAG, "init() called multiple times! sInstance %s", sInstance); 154 } 155 return sInstance; 156 } 157 } 158 159 // 160 // Implementation of the ITelecomService interface. 161 // 162 163 @Override 164 public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) { 165 try { 166 return mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount(uriScheme); 167 } catch (Exception e) { 168 Log.e(this, e, "getDefaultOutgoingPhoneAccount"); 169 throw e; 170 } 171 } 172 173 @Override 174 public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() { 175 try { 176 return mPhoneAccountRegistrar.getUserSelectedOutgoingPhoneAccount(); 177 } catch (Exception e) { 178 Log.e(this, e, "getUserSelectedOutgoingPhoneAccount"); 179 throw e; 180 } 181 } 182 183 @Override 184 public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) { 185 enforceModifyPermission(); 186 187 try { 188 mPhoneAccountRegistrar.setUserSelectedOutgoingPhoneAccount(accountHandle); 189 } catch (Exception e) { 190 Log.e(this, e, "setUserSelectedOutgoingPhoneAccount"); 191 throw e; 192 } 193 } 194 195 @Override 196 public List<PhoneAccountHandle> getCallCapablePhoneAccounts() { 197 try { 198 return mPhoneAccountRegistrar.getCallCapablePhoneAccounts(); 199 } catch (Exception e) { 200 Log.e(this, e, "getCallCapablePhoneAccounts"); 201 throw e; 202 } 203 } 204 205 @Override 206 public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) { 207 try { 208 return mPhoneAccountRegistrar.getCallCapablePhoneAccounts(uriScheme); 209 } catch (Exception e) { 210 Log.e(this, e, "getPhoneAccountsSupportingScheme"); 211 throw e; 212 } 213 } 214 215 @Override 216 public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) { 217 try { 218 return mPhoneAccountRegistrar.getPhoneAccount(accountHandle); 219 } catch (Exception e) { 220 Log.e(this, e, "getPhoneAccount %s", accountHandle); 221 throw e; 222 } 223 } 224 225 @Override 226 public int getAllPhoneAccountsCount() { 227 try { 228 return mPhoneAccountRegistrar.getAllPhoneAccountsCount(); 229 } catch (Exception e) { 230 Log.e(this, e, "getAllPhoneAccountsCount"); 231 throw e; 232 } 233 } 234 235 @Override 236 public List<PhoneAccount> getAllPhoneAccounts() { 237 try { 238 return mPhoneAccountRegistrar.getAllPhoneAccounts(); 239 } catch (Exception e) { 240 Log.e(this, e, "getAllPhoneAccounts"); 241 throw e; 242 } 243 } 244 245 @Override 246 public List<PhoneAccountHandle> getAllPhoneAccountHandles() { 247 try { 248 return mPhoneAccountRegistrar.getAllPhoneAccountHandles(); 249 } catch (Exception e) { 250 Log.e(this, e, "getAllPhoneAccounts"); 251 throw e; 252 } 253 } 254 255 @Override 256 public PhoneAccountHandle getSimCallManager() { 257 try { 258 return mPhoneAccountRegistrar.getSimCallManager(); 259 } catch (Exception e) { 260 Log.e(this, e, "getSimCallManager"); 261 throw e; 262 } 263 } 264 265 @Override 266 public void setSimCallManager(PhoneAccountHandle accountHandle) { 267 enforceModifyPermission(); 268 269 try { 270 mPhoneAccountRegistrar.setSimCallManager(accountHandle); 271 } catch (Exception e) { 272 Log.e(this, e, "setSimCallManager"); 273 throw e; 274 } 275 } 276 277 @Override 278 public List<PhoneAccountHandle> getSimCallManagers() { 279 try { 280 return mPhoneAccountRegistrar.getConnectionManagerPhoneAccounts(); 281 } catch (Exception e) { 282 Log.e(this, e, "getSimCallManagers"); 283 throw e; 284 } 285 } 286 287 @Override 288 public void registerPhoneAccount(PhoneAccount account) { 289 try { 290 enforcePhoneAccountModificationForPackage( 291 account.getAccountHandle().getComponentName().getPackageName()); 292 if (account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) || 293 account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 294 enforceRegisterProviderOrSubscriptionPermission(); 295 } 296 297 mPhoneAccountRegistrar.registerPhoneAccount(account); 298 } catch (Exception e) { 299 Log.e(this, e, "registerPhoneAccount %s", account); 300 throw e; 301 } 302 } 303 304 @Override 305 public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) { 306 try { 307 enforcePhoneAccountModificationForPackage( 308 accountHandle.getComponentName().getPackageName()); 309 mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle); 310 } catch (Exception e) { 311 Log.e(this, e, "unregisterPhoneAccount %s", accountHandle); 312 throw e; 313 } 314 } 315 316 @Override 317 public void clearAccounts(String packageName) { 318 try { 319 enforcePhoneAccountModificationForPackage(packageName); 320 mPhoneAccountRegistrar.clearAccounts(packageName); 321 } catch (Exception e) { 322 Log.e(this, e, "clearAccounts %s", packageName); 323 throw e; 324 } 325 } 326 327 /** 328 * @see android.telecom.TelecomManager#silenceRinger 329 */ 330 @Override 331 public void silenceRinger() { 332 Log.d(this, "silenceRinger"); 333 enforceModifyPermission(); 334 sendRequestAsync(MSG_SILENCE_RINGER, 0); 335 } 336 337 /** 338 * @see android.telecom.TelecomManager#getDefaultPhoneApp 339 */ 340 @Override 341 public ComponentName getDefaultPhoneApp() { 342 Resources resources = TelecomApp.getInstance().getResources(); 343 return new ComponentName( 344 resources.getString(R.string.ui_default_package), 345 resources.getString(R.string.dialer_default_class)); 346 } 347 348 /** 349 * @see android.telecom.TelecomManager#isInCall 350 */ 351 @Override 352 public boolean isInCall() { 353 enforceReadPermission(); 354 // Do not use sendRequest() with this method since it could cause a deadlock with 355 // audio service, which we call into from the main thread: AudioManager.setMode(). 356 final int callState = mCallsManager.getCallState(); 357 return callState == TelephonyManager.CALL_STATE_OFFHOOK 358 || callState == TelephonyManager.CALL_STATE_RINGING; 359 } 360 361 /** 362 * @see android.telecom.TelecomManager#isRinging 363 */ 364 @Override 365 public boolean isRinging() { 366 enforceReadPermission(); 367 return mCallsManager.getCallState() == TelephonyManager.CALL_STATE_RINGING; 368 } 369 370 /** 371 * @see TelecomManager#getCallState 372 */ 373 @Override 374 public int getCallState() { 375 return mCallsManager.getCallState(); 376 } 377 378 /** 379 * @see android.telecom.TelecomManager#endCall 380 */ 381 @Override 382 public boolean endCall() { 383 enforceModifyPermission(); 384 return (boolean) sendRequest(MSG_END_CALL); 385 } 386 387 /** 388 * @see android.telecom.TelecomManager#acceptRingingCall 389 */ 390 @Override 391 public void acceptRingingCall() { 392 enforceModifyPermission(); 393 sendRequestAsync(MSG_ACCEPT_RINGING_CALL, 0); 394 } 395 396 /** 397 * @see android.telecom.TelecomManager#showInCallScreen 398 */ 399 @Override 400 public void showInCallScreen(boolean showDialpad) { 401 enforceReadPermissionOrDefaultDialer(); 402 sendRequestAsync(MSG_SHOW_CALL_SCREEN, showDialpad ? 1 : 0); 403 } 404 405 /** 406 * @see android.telecom.TelecomManager#cancelMissedCallsNotification 407 */ 408 @Override 409 public void cancelMissedCallsNotification() { 410 enforceModifyPermissionOrDefaultDialer(); 411 sendRequestAsync(MSG_CANCEL_MISSED_CALLS_NOTIFICATION, 0); 412 } 413 414 /** 415 * @see android.telecom.TelecomManager#handleMmi 416 */ 417 @Override 418 public boolean handlePinMmi(String dialString) { 419 enforceModifyPermissionOrDefaultDialer(); 420 421 // Switch identity so that TelephonyManager checks Telecom's permissions instead. 422 long token = Binder.clearCallingIdentity(); 423 boolean retval = getTelephonyManager().handlePinMmi(dialString); 424 Binder.restoreCallingIdentity(token); 425 426 return retval; 427 } 428 429 /** 430 * @see android.telecom.TelecomManager#isTtySupported 431 */ 432 @Override 433 public boolean isTtySupported() { 434 enforceReadPermission(); 435 return (boolean) sendRequest(MSG_IS_TTY_SUPPORTED); 436 } 437 438 /** 439 * @see android.telecom.TelecomManager#getCurrentTtyMode 440 */ 441 @Override 442 public int getCurrentTtyMode() { 443 enforceReadPermission(); 444 return (int) sendRequest(MSG_GET_CURRENT_TTY_MODE); 445 } 446 447 /** 448 * @see android.telecom.TelecomManager#addNewIncomingCall 449 */ 450 @Override 451 public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) { 452 if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) { 453 mAppOpsManager.checkPackage( 454 Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName()); 455 456 Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL); 457 intent.setPackage(TelecomApp.getInstance().getPackageName()); 458 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 459 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); 460 if (extras != null) { 461 intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras); 462 } 463 464 long token = Binder.clearCallingIdentity(); 465 TelecomApp.getInstance().startActivityAsUser(intent, UserHandle.CURRENT); 466 Binder.restoreCallingIdentity(token); 467 } 468 } 469 470 // 471 // Supporting methods for the ITelecomService interface implementation. 472 // 473 474 private void acceptRingingCallInternal() { 475 Call call = mCallsManager.getFirstCallWithState(CallState.RINGING); 476 if (call != null) { 477 call.answer(call.getVideoState()); 478 } 479 } 480 481 private boolean endCallInternal() { 482 // Always operate on the foreground call if one exists, otherwise get the first call in 483 // priority order by call-state. 484 Call call = mCallsManager.getForegroundCall(); 485 if (call == null) { 486 call = mCallsManager.getFirstCallWithState( 487 CallState.ACTIVE, 488 CallState.DIALING, 489 CallState.RINGING, 490 CallState.ON_HOLD); 491 } 492 493 if (call != null) { 494 if (call.getState() == CallState.RINGING) { 495 call.reject(false /* rejectWithMessage */, null); 496 } else { 497 call.disconnect(); 498 } 499 return true; 500 } 501 502 return false; 503 } 504 505 private void enforcePhoneAccountModificationForPackage(String packageName) { 506 // TODO: Use a new telecomm permission for this instead of reusing modify. 507 508 int result = TelecomApp.getInstance().checkCallingOrSelfPermission( 509 Manifest.permission.MODIFY_PHONE_STATE); 510 511 // Callers with MODIFY_PHONE_STATE can use the PhoneAccount mechanism to implement 512 // built-in behavior even when PhoneAccounts are not exposed as a third-part API. They 513 // may also modify PhoneAccounts on behalf of any 'packageName'. 514 515 if (result != PackageManager.PERMISSION_GRANTED) { 516 // Other callers are only allowed to modify PhoneAccounts if the relevant system 517 // feature is enabled ... 518 enforceConnectionServiceFeature(); 519 // ... and the PhoneAccounts they refer to are for their own package. 520 enforceCallingPackage(packageName); 521 } 522 } 523 524 private void enforceReadPermissionOrDefaultDialer() { 525 if (!isDefaultDialerCalling()) { 526 enforceReadPermission(); 527 } 528 } 529 530 private void enforceModifyPermissionOrDefaultDialer() { 531 if (!isDefaultDialerCalling()) { 532 enforceModifyPermission(); 533 } 534 } 535 536 private void enforceCallingPackage(String packageName) { 537 mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName); 538 } 539 540 private void enforceConnectionServiceFeature() { 541 enforceFeature(PackageManager.FEATURE_CONNECTION_SERVICE); 542 } 543 544 private void enforceRegisterProviderOrSubscriptionPermission() { 545 enforcePermission(REGISTER_PROVIDER_OR_SUBSCRIPTION); 546 } 547 548 private void enforceReadPermission() { 549 enforcePermission(Manifest.permission.READ_PHONE_STATE); 550 } 551 552 private void enforceModifyPermission() { 553 enforcePermission(Manifest.permission.MODIFY_PHONE_STATE); 554 } 555 556 private void enforcePermission(String permission) { 557 TelecomApp.getInstance().enforceCallingOrSelfPermission(permission, null); 558 } 559 560 private void enforceFeature(String feature) { 561 PackageManager pm = TelecomApp.getInstance().getPackageManager(); 562 if (!pm.hasSystemFeature(feature)) { 563 throw new UnsupportedOperationException( 564 "System does not support feature " + feature); 565 } 566 } 567 568 private boolean isDefaultDialerCalling() { 569 ComponentName defaultDialerComponent = getDefaultPhoneApp(); 570 if (defaultDialerComponent != null) { 571 try { 572 mAppOpsManager.checkPackage( 573 Binder.getCallingUid(), defaultDialerComponent.getPackageName()); 574 return true; 575 } catch (SecurityException e) { 576 Log.e(TAG, e, "Could not get default dialer."); 577 } 578 } 579 return false; 580 } 581 582 private TelephonyManager getTelephonyManager() { 583 return (TelephonyManager) 584 TelecomApp.getInstance().getSystemService(Context.TELEPHONY_SERVICE); 585 } 586 587 private void publish() { 588 Log.d(this, "publish: %s", this); 589 ServiceManager.addService(SERVICE_NAME, this); 590 } 591 592 private MainThreadRequest sendRequestAsync(int command, int arg1) { 593 MainThreadRequest request = new MainThreadRequest(); 594 mMainThreadHandler.obtainMessage(command, arg1, 0, request).sendToTarget(); 595 return request; 596 } 597 598 /** 599 * Posts the specified command to be executed on the main thread, waits for the request to 600 * complete, and returns the result. 601 */ 602 private Object sendRequest(int command) { 603 if (Looper.myLooper() == mMainThreadHandler.getLooper()) { 604 MainThreadRequest request = new MainThreadRequest(); 605 mMainThreadHandler.handleMessage(mMainThreadHandler.obtainMessage(command, request)); 606 return request.result; 607 } else { 608 MainThreadRequest request = sendRequestAsync(command, 0); 609 610 // Wait for the request to complete 611 synchronized (request) { 612 while (request.result == null) { 613 try { 614 request.wait(); 615 } catch (InterruptedException e) { 616 // Do nothing, go back and wait until the request is complete 617 } 618 } 619 } 620 return request.result; 621 } 622 } 623} 624