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