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