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