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