TelephonyRegistry.java revision 71f6cb1324ecec9206c6bde1ab8abd31199b1927
1/*
2 * Copyright (C) 2007 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;
18
19import android.content.Context;
20import android.content.Intent;
21import android.content.pm.PackageManager;
22import android.net.LinkCapabilities;
23import android.net.LinkProperties;
24import android.os.Binder;
25import android.os.Bundle;
26import android.os.IBinder;
27import android.os.RemoteException;
28import android.telephony.CellLocation;
29import android.telephony.PhoneStateListener;
30import android.telephony.ServiceState;
31import android.telephony.SignalStrength;
32import android.telephony.TelephonyManager;
33import android.text.TextUtils;
34import android.util.Slog;
35
36import java.util.ArrayList;
37import java.io.FileDescriptor;
38import java.io.PrintWriter;
39import java.net.NetworkInterface;
40
41import com.android.internal.app.IBatteryStats;
42import com.android.internal.telephony.ITelephonyRegistry;
43import com.android.internal.telephony.IPhoneStateListener;
44import com.android.internal.telephony.DefaultPhoneNotifier;
45import com.android.internal.telephony.Phone;
46import com.android.internal.telephony.ServiceStateTracker;
47import com.android.internal.telephony.TelephonyIntents;
48import com.android.server.am.BatteryStatsService;
49
50/**
51 * Since phone process can be restarted, this class provides a centralized place
52 * that applications can register and be called back from.
53 */
54class TelephonyRegistry extends ITelephonyRegistry.Stub {
55    private static final String TAG = "TelephonyRegistry";
56
57    private static class Record {
58        String pkgForDebug;
59
60        IBinder binder;
61
62        IPhoneStateListener callback;
63
64        int events;
65    }
66
67    private final Context mContext;
68
69    // access should be inside synchronized (mRecords) for these two fields
70    private final ArrayList<IBinder> mRemoveList = new ArrayList<IBinder>();
71    private final ArrayList<Record> mRecords = new ArrayList<Record>();
72
73    private final IBatteryStats mBatteryStats;
74
75    private int mCallState = TelephonyManager.CALL_STATE_IDLE;
76
77    private String mCallIncomingNumber = "";
78
79    private ServiceState mServiceState = new ServiceState();
80
81    private SignalStrength mSignalStrength = new SignalStrength();
82
83    private boolean mMessageWaiting = false;
84
85    private boolean mCallForwarding = false;
86
87    private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
88
89    private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN;
90
91    private boolean mDataConnectionPossible = false;
92
93    private String mDataConnectionReason = "";
94
95    private String mDataConnectionApn = "";
96
97    private ArrayList<String> mConnectedApns;
98
99    private LinkProperties mDataConnectionLinkProperties;
100
101    private LinkCapabilities mDataConnectionLinkCapabilities;
102
103    private Bundle mCellLocation = new Bundle();
104
105    private int mDataConnectionNetworkType;
106
107    private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
108
109    static final int PHONE_STATE_PERMISSION_MASK =
110                PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
111                PhoneStateListener.LISTEN_CALL_STATE |
112                PhoneStateListener.LISTEN_DATA_ACTIVITY |
113                PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
114                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
115
116    // we keep a copy of all of the state so we can send it out when folks
117    // register for it
118    //
119    // In these calls we call with the lock held. This is safe becasuse remote
120    // calls go through a oneway interface and local calls going through a
121    // handler before they get to app code.
122
123    TelephonyRegistry(Context context) {
124        CellLocation  location = CellLocation.getEmpty();
125
126        // Note that location can be null for non-phone builds like
127        // like the generic one.
128        if (location != null) {
129            location.fillInNotifierBundle(mCellLocation);
130        }
131        mContext = context;
132        mBatteryStats = BatteryStatsService.getService();
133        mConnectedApns = new ArrayList<String>();
134    }
135
136    public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
137            boolean notifyNow) {
138        // Slog.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" +
139        // Integer.toHexString(events));
140        if (events != 0) {
141            /* Checks permission and throws Security exception */
142            checkListenerPermission(events);
143
144            synchronized (mRecords) {
145                // register
146                Record r = null;
147                find_and_add: {
148                    IBinder b = callback.asBinder();
149                    final int N = mRecords.size();
150                    for (int i = 0; i < N; i++) {
151                        r = mRecords.get(i);
152                        if (b == r.binder) {
153                            break find_and_add;
154                        }
155                    }
156                    r = new Record();
157                    r.binder = b;
158                    r.callback = callback;
159                    r.pkgForDebug = pkgForDebug;
160                    mRecords.add(r);
161                }
162                int send = events & (events ^ r.events);
163                r.events = events;
164                if (notifyNow) {
165                    if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
166                        try {
167                            r.callback.onServiceStateChanged(new ServiceState(mServiceState));
168                        } catch (RemoteException ex) {
169                            remove(r.binder);
170                        }
171                    }
172                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
173                        try {
174                            int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
175                            r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
176                                    : gsmSignalStrength));
177                        } catch (RemoteException ex) {
178                            remove(r.binder);
179                        }
180                    }
181                    if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
182                        try {
183                            r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
184                        } catch (RemoteException ex) {
185                            remove(r.binder);
186                        }
187                    }
188                    if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
189                        try {
190                            r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
191                        } catch (RemoteException ex) {
192                            remove(r.binder);
193                        }
194                    }
195                    if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
196                        try {
197                            r.callback.onCellLocationChanged(new Bundle(mCellLocation));
198                        } catch (RemoteException ex) {
199                            remove(r.binder);
200                        }
201                    }
202                    if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
203                        try {
204                            r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
205                        } catch (RemoteException ex) {
206                            remove(r.binder);
207                        }
208                    }
209                    if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
210                        try {
211                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
212                                mDataConnectionNetworkType);
213                        } catch (RemoteException ex) {
214                            remove(r.binder);
215                        }
216                    }
217                    if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
218                        try {
219                            r.callback.onDataActivity(mDataActivity);
220                        } catch (RemoteException ex) {
221                            remove(r.binder);
222                        }
223                    }
224                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
225                        try {
226                            r.callback.onSignalStrengthsChanged(mSignalStrength);
227                        } catch (RemoteException ex) {
228                            remove(r.binder);
229                        }
230                    }
231                    if ((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
232                        try {
233                            r.callback.onOtaspChanged(mOtaspMode);
234                        } catch (RemoteException ex) {
235                            remove(r.binder);
236                        }
237                    }
238                }
239            }
240        } else {
241            remove(callback.asBinder());
242        }
243    }
244
245    private void remove(IBinder binder) {
246        synchronized (mRecords) {
247            final int recordCount = mRecords.size();
248            for (int i = 0; i < recordCount; i++) {
249                if (mRecords.get(i).binder == binder) {
250                    mRecords.remove(i);
251                    return;
252                }
253            }
254        }
255    }
256
257    public void notifyCallState(int state, String incomingNumber) {
258        if (!checkNotifyPermission("notifyCallState()")) {
259            return;
260        }
261        synchronized (mRecords) {
262            mCallState = state;
263            mCallIncomingNumber = incomingNumber;
264            for (Record r : mRecords) {
265                if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
266                    try {
267                        r.callback.onCallStateChanged(state, incomingNumber);
268                    } catch (RemoteException ex) {
269                        mRemoveList.add(r.binder);
270                    }
271                }
272            }
273            handleRemoveListLocked();
274        }
275        broadcastCallStateChanged(state, incomingNumber);
276    }
277
278    public void notifyServiceState(ServiceState state) {
279        if (!checkNotifyPermission("notifyServiceState()")){
280            return;
281        }
282        Slog.i(TAG, "notifyServiceState: " + state);
283        synchronized (mRecords) {
284            mServiceState = state;
285            for (Record r : mRecords) {
286                if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
287                    try {
288                        r.callback.onServiceStateChanged(new ServiceState(state));
289                    } catch (RemoteException ex) {
290                        mRemoveList.add(r.binder);
291                    }
292                }
293            }
294            handleRemoveListLocked();
295        }
296        broadcastServiceStateChanged(state);
297    }
298
299    public void notifySignalStrength(SignalStrength signalStrength) {
300        if (!checkNotifyPermission("notifySignalStrength()")) {
301            return;
302        }
303        synchronized (mRecords) {
304            mSignalStrength = signalStrength;
305            for (Record r : mRecords) {
306                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
307                    try {
308                        r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
309                    } catch (RemoteException ex) {
310                        mRemoveList.add(r.binder);
311                    }
312                }
313                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
314                    try {
315                        int gsmSignalStrength = signalStrength.getGsmSignalStrength();
316                        r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
317                                : gsmSignalStrength));
318                    } catch (RemoteException ex) {
319                        mRemoveList.add(r.binder);
320                    }
321                }
322            }
323            handleRemoveListLocked();
324        }
325        broadcastSignalStrengthChanged(signalStrength);
326    }
327
328    public void notifyMessageWaitingChanged(boolean mwi) {
329        if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
330            return;
331        }
332        synchronized (mRecords) {
333            mMessageWaiting = mwi;
334            for (Record r : mRecords) {
335                if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
336                    try {
337                        r.callback.onMessageWaitingIndicatorChanged(mwi);
338                    } catch (RemoteException ex) {
339                        mRemoveList.add(r.binder);
340                    }
341                }
342            }
343            handleRemoveListLocked();
344        }
345    }
346
347    public void notifyCallForwardingChanged(boolean cfi) {
348        if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
349            return;
350        }
351        synchronized (mRecords) {
352            mCallForwarding = cfi;
353            for (Record r : mRecords) {
354                if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
355                    try {
356                        r.callback.onCallForwardingIndicatorChanged(cfi);
357                    } catch (RemoteException ex) {
358                        mRemoveList.add(r.binder);
359                    }
360                }
361            }
362            handleRemoveListLocked();
363        }
364    }
365
366    public void notifyDataActivity(int state) {
367        if (!checkNotifyPermission("notifyDataActivity()" )) {
368            return;
369        }
370        synchronized (mRecords) {
371            mDataActivity = state;
372            for (Record r : mRecords) {
373                if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
374                    try {
375                        r.callback.onDataActivity(state);
376                    } catch (RemoteException ex) {
377                        mRemoveList.add(r.binder);
378                    }
379                }
380            }
381            handleRemoveListLocked();
382        }
383    }
384
385    public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
386            String reason, String apn, String apnType, LinkProperties linkProperties,
387            LinkCapabilities linkCapabilities, int networkType) {
388        if (!checkNotifyPermission("notifyDataConnection()" )) {
389            return;
390        }
391        Slog.i(TAG, "notifyDataConnection: state=" + state + " isDataConnectivityPossible="
392                + isDataConnectivityPossible + " reason='" + reason
393                + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType);
394        synchronized (mRecords) {
395            boolean modified = false;
396            if (state == TelephonyManager.DATA_CONNECTED) {
397                if (!mConnectedApns.contains(apnType)) {
398                    mConnectedApns.add(apnType);
399                    if (mDataConnectionState != state) {
400                        mDataConnectionState = state;
401                        modified = true;
402                    }
403                }
404            } else {
405                if (mConnectedApns.remove(apnType)) {
406                    if (mConnectedApns.isEmpty()) {
407                        mDataConnectionState = state;
408                        modified = true;
409                    } else {
410                        // leave mDataConnectionState as is and
411                        // send out the new status for the APN in question.
412                    }
413                }
414            }
415            mDataConnectionPossible = isDataConnectivityPossible;
416            mDataConnectionReason = reason;
417            mDataConnectionLinkProperties = linkProperties;
418            mDataConnectionLinkCapabilities = linkCapabilities;
419            if (mDataConnectionNetworkType != networkType) {
420                mDataConnectionNetworkType = networkType;
421                // need to tell registered listeners about the new network type
422                modified = true;
423            }
424            if (modified) {
425                Slog.d(TAG, "onDataConnectionStateChanged(" + state + ", " + networkType + ")");
426                for (Record r : mRecords) {
427                    if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
428                        try {
429                            r.callback.onDataConnectionStateChanged(state, networkType);
430                        } catch (RemoteException ex) {
431                            mRemoveList.add(r.binder);
432                        }
433                    }
434                }
435                handleRemoveListLocked();
436            }
437        }
438        broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
439                apnType, linkProperties, linkCapabilities);
440    }
441
442    public void notifyDataConnectionFailed(String reason, String apnType) {
443        if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
444            return;
445        }
446        /*
447         * This is commented out because there is no onDataConnectionFailed callback
448         * in PhoneStateListener. There should be.
449        synchronized (mRecords) {
450            mDataConnectionFailedReason = reason;
451            final int N = mRecords.size();
452            for (int i=N-1; i>=0; i--) {
453                Record r = mRecords.get(i);
454                if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_FAILED) != 0) {
455                    // XXX
456                }
457            }
458        }
459        */
460        broadcastDataConnectionFailed(reason, apnType);
461    }
462
463    public void notifyCellLocation(Bundle cellLocation) {
464        if (!checkNotifyPermission("notifyCellLocation()")) {
465            return;
466        }
467        synchronized (mRecords) {
468            mCellLocation = cellLocation;
469            for (Record r : mRecords) {
470                if ((r.events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
471                    try {
472                        r.callback.onCellLocationChanged(new Bundle(cellLocation));
473                    } catch (RemoteException ex) {
474                        mRemoveList.add(r.binder);
475                    }
476
477                }
478            }
479            handleRemoveListLocked();
480        }
481    }
482
483    public void notifyOtaspChanged(int otaspMode) {
484        if (!checkNotifyPermission("notifyOtaspChanged()" )) {
485            return;
486        }
487        synchronized (mRecords) {
488            mOtaspMode = otaspMode;
489            for (Record r : mRecords) {
490                if ((r.events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
491                    try {
492                        r.callback.onOtaspChanged(otaspMode);
493                    } catch (RemoteException ex) {
494                        mRemoveList.add(r.binder);
495                    }
496                }
497            }
498            handleRemoveListLocked();
499        }
500    }
501
502    @Override
503    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
504        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
505                != PackageManager.PERMISSION_GRANTED) {
506            pw.println("Permission Denial: can't dump telephony.registry from from pid="
507                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
508            return;
509        }
510        synchronized (mRecords) {
511            final int recordCount = mRecords.size();
512            pw.println("last known state:");
513            pw.println("  mCallState=" + mCallState);
514            pw.println("  mCallIncomingNumber=" + mCallIncomingNumber);
515            pw.println("  mServiceState=" + mServiceState);
516            pw.println("  mSignalStrength=" + mSignalStrength);
517            pw.println("  mMessageWaiting=" + mMessageWaiting);
518            pw.println("  mCallForwarding=" + mCallForwarding);
519            pw.println("  mDataActivity=" + mDataActivity);
520            pw.println("  mDataConnectionState=" + mDataConnectionState);
521            pw.println("  mDataConnectionPossible=" + mDataConnectionPossible);
522            pw.println("  mDataConnectionReason=" + mDataConnectionReason);
523            pw.println("  mDataConnectionApn=" + mDataConnectionApn);
524            pw.println("  mDataConnectionLinkProperties=" + mDataConnectionLinkProperties);
525            pw.println("  mDataConnectionLinkCapabilities=" + mDataConnectionLinkCapabilities);
526            pw.println("  mCellLocation=" + mCellLocation);
527            pw.println("registrations: count=" + recordCount);
528            for (Record r : mRecords) {
529                pw.println("  " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events));
530            }
531        }
532    }
533
534    //
535    // the legacy intent broadcasting
536    //
537
538    private void broadcastServiceStateChanged(ServiceState state) {
539        long ident = Binder.clearCallingIdentity();
540        try {
541            mBatteryStats.notePhoneState(state.getState());
542        } catch (RemoteException re) {
543            // Can't do much
544        } finally {
545            Binder.restoreCallingIdentity(ident);
546        }
547
548        Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
549        Bundle data = new Bundle();
550        state.fillInNotifierBundle(data);
551        intent.putExtras(data);
552        mContext.sendStickyBroadcast(intent);
553    }
554
555    private void broadcastSignalStrengthChanged(SignalStrength signalStrength) {
556        long ident = Binder.clearCallingIdentity();
557        try {
558            mBatteryStats.notePhoneSignalStrength(signalStrength);
559        } catch (RemoteException e) {
560            /* The remote entity disappeared, we can safely ignore the exception. */
561        } finally {
562            Binder.restoreCallingIdentity(ident);
563        }
564
565        Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
566        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
567        Bundle data = new Bundle();
568        signalStrength.fillInNotifierBundle(data);
569        intent.putExtras(data);
570        mContext.sendStickyBroadcast(intent);
571    }
572
573    private void broadcastCallStateChanged(int state, String incomingNumber) {
574        long ident = Binder.clearCallingIdentity();
575        try {
576            if (state == TelephonyManager.CALL_STATE_IDLE) {
577                mBatteryStats.notePhoneOff();
578            } else {
579                mBatteryStats.notePhoneOn();
580            }
581        } catch (RemoteException e) {
582            /* The remote entity disappeared, we can safely ignore the exception. */
583        } finally {
584            Binder.restoreCallingIdentity(ident);
585        }
586
587        Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
588        intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertCallState(state).toString());
589        if (!TextUtils.isEmpty(incomingNumber)) {
590            intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
591        }
592        mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE);
593    }
594
595    private void broadcastDataConnectionStateChanged(int state,
596            boolean isDataConnectivityPossible,
597            String reason, String apn, String apnType, LinkProperties linkProperties,
598            LinkCapabilities linkCapabilities) {
599        // Note: not reporting to the battery stats service here, because the
600        // status bar takes care of that after taking into account all of the
601        // required info.
602        Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
603        intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertDataState(state).toString());
604        if (!isDataConnectivityPossible) {
605            intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, true);
606        }
607        if (reason != null) {
608            intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason);
609        }
610        if (linkProperties != null) {
611            intent.putExtra(Phone.DATA_LINK_PROPERTIES_KEY, linkProperties);
612            String iface = linkProperties.getInterfaceName();
613            if (iface != null) {
614                intent.putExtra(Phone.DATA_IFACE_NAME_KEY, iface);
615            }
616        }
617        if (linkCapabilities != null) {
618            intent.putExtra(Phone.DATA_LINK_CAPABILITIES_KEY, linkCapabilities);
619        }
620        intent.putExtra(Phone.DATA_APN_KEY, apn);
621        intent.putExtra(Phone.DATA_APN_TYPE_KEY, apnType);
622        mContext.sendStickyBroadcast(intent);
623    }
624
625    private void broadcastDataConnectionFailed(String reason, String apnType) {
626        Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
627        intent.putExtra(Phone.FAILURE_REASON_KEY, reason);
628        intent.putExtra(Phone.DATA_APN_TYPE_KEY, apnType);
629        mContext.sendStickyBroadcast(intent);
630    }
631
632    private boolean checkNotifyPermission(String method) {
633        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
634                == PackageManager.PERMISSION_GRANTED) {
635            return true;
636        }
637        String msg = "Modify Phone State Permission Denial: " + method + " from pid="
638                + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
639        Slog.w(TAG, msg);
640        return false;
641    }
642
643    private void checkListenerPermission(int events) {
644        if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
645            mContext.enforceCallingOrSelfPermission(
646                    android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
647
648        }
649
650        if ((events & PHONE_STATE_PERMISSION_MASK) != 0) {
651            mContext.enforceCallingOrSelfPermission(
652                    android.Manifest.permission.READ_PHONE_STATE, null);
653        }
654    }
655
656    private void handleRemoveListLocked() {
657        if (mRemoveList.size() > 0) {
658            for (IBinder b: mRemoveList) {
659                remove(b);
660            }
661            mRemoveList.clear();
662        }
663    }
664}
665