TelecomServiceImpl.java revision f1863270a872c18f73fc59ab581194ed203e6612
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> getEnabledPhoneAccounts() { 197 try { 198 return mPhoneAccountRegistrar.getEnabledPhoneAccounts(); 199 } catch (Exception e) { 200 Log.e(this, e, "getEnabledPhoneAccounts"); 201 throw e; 202 } 203 } 204 205 @Override 206 public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) { 207 try { 208 return mPhoneAccountRegistrar.getEnabledPhoneAccounts(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 // If the account is marked as enabled or has CAPABILITY_ALWAYS_ENABLED set, check to 298 // ensure the caller has modify permission. If they do not, set the account to be 299 // disabled and remove CAPABILITY_ALWAYS_ENABLED. 300 if (account.isEnabled() || 301 account.hasCapabilities(PhoneAccount.CAPABILITY_ALWAYS_ENABLED)) { 302 try { 303 enforceModifyPermission(); 304 } catch (SecurityException e) { 305 // Caller does not have modify permission, so change account to disabled by 306 // default and remove the CAPABILITY_ALWAYS_ENABLED capability. 307 int capabilities = account.getCapabilities() & 308 ~PhoneAccount.CAPABILITY_ALWAYS_ENABLED; 309 account = account.toBuilder() 310 .setEnabled(false) 311 .setCapabilities(capabilities) 312 .build(); 313 } 314 } 315 316 mPhoneAccountRegistrar.registerPhoneAccount(account); 317 } catch (Exception e) { 318 Log.e(this, e, "registerPhoneAccount %s", account); 319 throw e; 320 } 321 } 322 323 @Override 324 public void setPhoneAccountEnabled(PhoneAccountHandle account, boolean isEnabled) { 325 try { 326 enforceModifyPermission(); 327 mPhoneAccountRegistrar.setPhoneAccountEnabled(account, isEnabled); 328 } catch (Exception e) { 329 Log.e(this, e, "setPhoneAccountEnabled %s %d", account, isEnabled ? 1 : 0); 330 throw e; 331 } 332 } 333 334 @Override 335 public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) { 336 try { 337 enforcePhoneAccountModificationForPackage( 338 accountHandle.getComponentName().getPackageName()); 339 mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle); 340 } catch (Exception e) { 341 Log.e(this, e, "unregisterPhoneAccount %s", accountHandle); 342 throw e; 343 } 344 } 345 346 @Override 347 public void clearAccounts(String packageName) { 348 try { 349 enforcePhoneAccountModificationForPackage(packageName); 350 mPhoneAccountRegistrar.clearAccounts(packageName); 351 } catch (Exception e) { 352 Log.e(this, e, "clearAccounts %s", packageName); 353 throw e; 354 } 355 } 356 357 /** 358 * @see android.telecom.TelecomManager#silenceRinger 359 */ 360 @Override 361 public void silenceRinger() { 362 Log.d(this, "silenceRinger"); 363 enforceModifyPermission(); 364 sendRequestAsync(MSG_SILENCE_RINGER, 0); 365 } 366 367 /** 368 * @see android.telecom.TelecomManager#getDefaultPhoneApp 369 */ 370 @Override 371 public ComponentName getDefaultPhoneApp() { 372 Resources resources = TelecomApp.getInstance().getResources(); 373 return new ComponentName( 374 resources.getString(R.string.ui_default_package), 375 resources.getString(R.string.dialer_default_class)); 376 } 377 378 /** 379 * @see android.telecom.TelecomManager#isInCall 380 */ 381 @Override 382 public boolean isInCall() { 383 enforceReadPermission(); 384 // Do not use sendRequest() with this method since it could cause a deadlock with 385 // audio service, which we call into from the main thread: AudioManager.setMode(). 386 final int callState = mCallsManager.getCallState(); 387 return callState == TelephonyManager.CALL_STATE_OFFHOOK 388 || callState == TelephonyManager.CALL_STATE_RINGING; 389 } 390 391 /** 392 * @see android.telecom.TelecomManager#isRinging 393 */ 394 @Override 395 public boolean isRinging() { 396 enforceReadPermission(); 397 return mCallsManager.getCallState() == TelephonyManager.CALL_STATE_RINGING; 398 } 399 400 /** 401 * @see TelecomManager#getCallState 402 */ 403 @Override 404 public int getCallState() { 405 enforceReadPermission(); 406 return mCallsManager.getCallState(); 407 } 408 409 /** 410 * @see android.telecom.TelecomManager#endCall 411 */ 412 @Override 413 public boolean endCall() { 414 enforceModifyPermission(); 415 return (boolean) sendRequest(MSG_END_CALL); 416 } 417 418 /** 419 * @see android.telecom.TelecomManager#acceptRingingCall 420 */ 421 @Override 422 public void acceptRingingCall() { 423 enforceModifyPermission(); 424 sendRequestAsync(MSG_ACCEPT_RINGING_CALL, 0); 425 } 426 427 /** 428 * @see android.telecom.TelecomManager#showInCallScreen 429 */ 430 @Override 431 public void showInCallScreen(boolean showDialpad) { 432 enforceReadPermissionOrDefaultDialer(); 433 sendRequestAsync(MSG_SHOW_CALL_SCREEN, showDialpad ? 1 : 0); 434 } 435 436 /** 437 * @see android.telecom.TelecomManager#cancelMissedCallsNotification 438 */ 439 @Override 440 public void cancelMissedCallsNotification() { 441 enforceModifyPermissionOrDefaultDialer(); 442 sendRequestAsync(MSG_CANCEL_MISSED_CALLS_NOTIFICATION, 0); 443 } 444 445 /** 446 * @see android.telecom.TelecomManager#handleMmi 447 */ 448 @Override 449 public boolean handlePinMmi(String dialString) { 450 enforceModifyPermissionOrDefaultDialer(); 451 452 // Switch identity so that TelephonyManager checks Telecom's permissions instead. 453 long token = Binder.clearCallingIdentity(); 454 boolean retval = getTelephonyManager().handlePinMmi(dialString); 455 Binder.restoreCallingIdentity(token); 456 457 return retval; 458 } 459 460 /** 461 * @see android.telecom.TelecomManager#isTtySupported 462 */ 463 @Override 464 public boolean isTtySupported() { 465 enforceReadPermission(); 466 return (boolean) sendRequest(MSG_IS_TTY_SUPPORTED); 467 } 468 469 /** 470 * @see android.telecom.TelecomManager#getCurrentTtyMode 471 */ 472 @Override 473 public int getCurrentTtyMode() { 474 enforceReadPermission(); 475 return (int) sendRequest(MSG_GET_CURRENT_TTY_MODE); 476 } 477 478 /** 479 * @see android.telecom.TelecomManager#addNewIncomingCall 480 */ 481 @Override 482 public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) { 483 if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) { 484 mAppOpsManager.checkPackage( 485 Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName()); 486 487 Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL); 488 intent.setPackage(TelecomApp.getInstance().getPackageName()); 489 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 490 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); 491 if (extras != null) { 492 intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras); 493 } 494 495 long token = Binder.clearCallingIdentity(); 496 TelecomApp.getInstance().startActivityAsUser(intent, UserHandle.CURRENT); 497 Binder.restoreCallingIdentity(token); 498 } 499 } 500 501 // 502 // Supporting methods for the ITelecomService interface implementation. 503 // 504 505 private void acceptRingingCallInternal() { 506 Call call = mCallsManager.getFirstCallWithState(CallState.RINGING); 507 if (call != null) { 508 call.answer(call.getVideoState()); 509 } 510 } 511 512 private boolean endCallInternal() { 513 // Always operate on the foreground call if one exists, otherwise get the first call in 514 // priority order by call-state. 515 Call call = mCallsManager.getForegroundCall(); 516 if (call == null) { 517 call = mCallsManager.getFirstCallWithState( 518 CallState.ACTIVE, 519 CallState.DIALING, 520 CallState.RINGING, 521 CallState.ON_HOLD); 522 } 523 524 if (call != null) { 525 if (call.getState() == CallState.RINGING) { 526 call.reject(false /* rejectWithMessage */, null); 527 } else { 528 call.disconnect(); 529 } 530 return true; 531 } 532 533 return false; 534 } 535 536 private void enforcePhoneAccountModificationForPackage(String packageName) { 537 // TODO: Use a new telecomm permission for this instead of reusing modify. 538 539 int result = TelecomApp.getInstance().checkCallingOrSelfPermission( 540 Manifest.permission.MODIFY_PHONE_STATE); 541 542 // Callers with MODIFY_PHONE_STATE can use the PhoneAccount mechanism to implement 543 // built-in behavior even when PhoneAccounts are not exposed as a third-part API. They 544 // may also modify PhoneAccounts on behalf of any 'packageName'. 545 546 if (result != PackageManager.PERMISSION_GRANTED) { 547 // Other callers are only allowed to modify PhoneAccounts if the relevant system 548 // feature is enabled ... 549 enforceConnectionServiceFeature(); 550 // ... and the PhoneAccounts they refer to are for their own package. 551 enforceCallingPackage(packageName); 552 } 553 } 554 555 private void enforceReadPermissionOrDefaultDialer() { 556 if (!isDefaultDialerCalling()) { 557 enforceReadPermission(); 558 } 559 } 560 561 private void enforceModifyPermissionOrDefaultDialer() { 562 if (!isDefaultDialerCalling()) { 563 enforceModifyPermission(); 564 } 565 } 566 567 private void enforceCallingPackage(String packageName) { 568 mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName); 569 } 570 571 private void enforceConnectionServiceFeature() { 572 enforceFeature(PackageManager.FEATURE_CONNECTION_SERVICE); 573 } 574 575 private void enforceRegisterProviderOrSubscriptionPermission() { 576 enforcePermission(REGISTER_PROVIDER_OR_SUBSCRIPTION); 577 } 578 579 private void enforceReadPermission() { 580 enforcePermission(Manifest.permission.READ_PHONE_STATE); 581 } 582 583 private void enforceModifyPermission() { 584 enforcePermission(Manifest.permission.MODIFY_PHONE_STATE); 585 } 586 587 private void enforcePermission(String permission) { 588 TelecomApp.getInstance().enforceCallingOrSelfPermission(permission, null); 589 } 590 591 private void enforceFeature(String feature) { 592 PackageManager pm = TelecomApp.getInstance().getPackageManager(); 593 if (!pm.hasSystemFeature(feature)) { 594 throw new UnsupportedOperationException( 595 "System does not support feature " + feature); 596 } 597 } 598 599 private boolean isDefaultDialerCalling() { 600 ComponentName defaultDialerComponent = getDefaultPhoneApp(); 601 if (defaultDialerComponent != null) { 602 try { 603 mAppOpsManager.checkPackage( 604 Binder.getCallingUid(), defaultDialerComponent.getPackageName()); 605 return true; 606 } catch (SecurityException e) { 607 Log.e(TAG, e, "Could not get default dialer."); 608 } 609 } 610 return false; 611 } 612 613 private TelephonyManager getTelephonyManager() { 614 return (TelephonyManager) 615 TelecomApp.getInstance().getSystemService(Context.TELEPHONY_SERVICE); 616 } 617 618 private void publish() { 619 Log.d(this, "publish: %s", this); 620 ServiceManager.addService(SERVICE_NAME, this); 621 } 622 623 private MainThreadRequest sendRequestAsync(int command, int arg1) { 624 MainThreadRequest request = new MainThreadRequest(); 625 mMainThreadHandler.obtainMessage(command, arg1, 0, request).sendToTarget(); 626 return request; 627 } 628 629 /** 630 * Posts the specified command to be executed on the main thread, waits for the request to 631 * complete, and returns the result. 632 */ 633 private Object sendRequest(int command) { 634 if (Looper.myLooper() == mMainThreadHandler.getLooper()) { 635 MainThreadRequest request = new MainThreadRequest(); 636 mMainThreadHandler.handleMessage(mMainThreadHandler.obtainMessage(command, request)); 637 return request.result; 638 } else { 639 MainThreadRequest request = sendRequestAsync(command, 0); 640 641 // Wait for the request to complete 642 synchronized (request) { 643 while (request.result == null) { 644 try { 645 request.wait(); 646 } catch (InterruptedException e) { 647 // Do nothing, go back and wait until the request is complete 648 } 649 } 650 } 651 return request.result; 652 } 653 } 654} 655