TelephonyRegistry.java revision f9cb86aebe9647e0fe0137fc198ba16c017445c6
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.app.ActivityManager;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
25import android.net.LinkProperties;
26import android.net.NetworkCapabilities;
27import android.os.Binder;
28import android.os.Bundle;
29import android.os.Handler;
30import android.os.IBinder;
31import android.os.Message;
32import android.os.RemoteException;
33import android.os.UserHandle;
34import android.telephony.CellLocation;
35import android.telephony.DataConnectionRealTimeInfo;
36import android.telephony.PhoneStateListener;
37import android.telephony.ServiceState;
38import android.telephony.SignalStrength;
39import android.telephony.CellInfo;
40import android.telephony.TelephonyManager;
41import android.telephony.DisconnectCause;
42import android.telephony.PreciseCallState;
43import android.telephony.PreciseDataConnectionState;
44import android.telephony.PreciseDisconnectCause;
45import android.text.TextUtils;
46import android.util.Slog;
47
48import java.util.ArrayList;
49import java.util.List;
50import java.io.FileDescriptor;
51import java.io.PrintWriter;
52
53import com.android.internal.app.IBatteryStats;
54import com.android.internal.telephony.ITelephonyRegistry;
55import com.android.internal.telephony.IPhoneStateListener;
56import com.android.internal.telephony.DefaultPhoneNotifier;
57import com.android.internal.telephony.PhoneConstants;
58import com.android.internal.telephony.ServiceStateTracker;
59import com.android.internal.telephony.TelephonyIntents;
60import com.android.server.am.BatteryStatsService;
61
62/**
63 * Since phone process can be restarted, this class provides a centralized place
64 * that applications can register and be called back from.
65 */
66class TelephonyRegistry extends ITelephonyRegistry.Stub {
67    private static final String TAG = "TelephonyRegistry";
68    private static final boolean DBG = false;
69    private static final boolean DBG_LOC = false;
70
71    private static class Record {
72        String pkgForDebug;
73
74        IBinder binder;
75
76        IPhoneStateListener callback;
77
78        int callerUid;
79
80        int events;
81
82        @Override
83        public String toString() {
84            return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid +
85                    " events=" + Integer.toHexString(events) + "}";
86        }
87    }
88
89    private final Context mContext;
90
91    // access should be inside synchronized (mRecords) for these two fields
92    private final ArrayList<IBinder> mRemoveList = new ArrayList<IBinder>();
93    private final ArrayList<Record> mRecords = new ArrayList<Record>();
94
95    private final IBatteryStats mBatteryStats;
96
97    private int mCallState = TelephonyManager.CALL_STATE_IDLE;
98
99    private String mCallIncomingNumber = "";
100
101    private ServiceState mServiceState = new ServiceState();
102
103    private SignalStrength mSignalStrength = new SignalStrength();
104
105    private boolean mMessageWaiting = false;
106
107    private boolean mCallForwarding = false;
108
109    private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
110
111    private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN;
112
113    private boolean mDataConnectionPossible = false;
114
115    private String mDataConnectionReason = "";
116
117    private String mDataConnectionApn = "";
118
119    private ArrayList<String> mConnectedApns;
120
121    private LinkProperties mDataConnectionLinkProperties;
122
123    private NetworkCapabilities mDataConnectionNetworkCapabilities;
124
125    private Bundle mCellLocation = new Bundle();
126
127    private int mDataConnectionNetworkType;
128
129    private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
130
131    private List<CellInfo> mCellInfo = null;
132
133    private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
134
135    private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
136
137    private int mForegroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
138
139    private int mBackgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
140
141    private PreciseCallState mPreciseCallState = new PreciseCallState();
142
143    private PreciseDataConnectionState mPreciseDataConnectionState =
144                new PreciseDataConnectionState();
145
146    static final int PHONE_STATE_PERMISSION_MASK =
147                PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
148                PhoneStateListener.LISTEN_CALL_STATE |
149                PhoneStateListener.LISTEN_DATA_ACTIVITY |
150                PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
151                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
152
153    static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
154                PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
155                PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
156
157    private static final int MSG_USER_SWITCHED = 1;
158
159    private final Handler mHandler = new Handler() {
160        @Override
161        public void handleMessage(Message msg) {
162            switch (msg.what) {
163                case MSG_USER_SWITCHED: {
164                    if (DBG) Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
165                    TelephonyRegistry.this.notifyCellLocation(mCellLocation);
166                    break;
167                }
168            }
169        }
170    };
171
172    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
173        @Override
174        public void onReceive(Context context, Intent intent) {
175            String action = intent.getAction();
176            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
177                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
178                       intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
179            }
180        }
181    };
182
183    // we keep a copy of all of the state so we can send it out when folks
184    // register for it
185    //
186    // In these calls we call with the lock held. This is safe becasuse remote
187    // calls go through a oneway interface and local calls going through a
188    // handler before they get to app code.
189
190    TelephonyRegistry(Context context) {
191        CellLocation  location = CellLocation.getEmpty();
192
193        // Note that location can be null for non-phone builds like
194        // like the generic one.
195        if (location != null) {
196            location.fillInNotifierBundle(mCellLocation);
197        }
198        mContext = context;
199        mBatteryStats = BatteryStatsService.getService();
200        mConnectedApns = new ArrayList<String>();
201    }
202
203    public void systemRunning() {
204        // Watch for interesting updates
205        final IntentFilter filter = new IntentFilter();
206        filter.addAction(Intent.ACTION_USER_SWITCHED);
207        filter.addAction(Intent.ACTION_USER_REMOVED);
208        mContext.registerReceiver(mBroadcastReceiver, filter);
209    }
210
211    @Override
212    public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
213            boolean notifyNow) {
214        int callerUid = UserHandle.getCallingUserId();
215        int myUid = UserHandle.myUserId();
216        if (DBG) {
217            Slog.d(TAG, "listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
218                + " myUid=" + myUid
219                + " callerUid=" + callerUid);
220        }
221        if (events != 0) {
222            /* Checks permission and throws Security exception */
223            checkListenerPermission(events);
224
225            synchronized (mRecords) {
226                // register
227                Record r = null;
228                find_and_add: {
229                    IBinder b = callback.asBinder();
230                    final int N = mRecords.size();
231                    for (int i = 0; i < N; i++) {
232                        r = mRecords.get(i);
233                        if (b == r.binder) {
234                            break find_and_add;
235                        }
236                    }
237                    r = new Record();
238                    r.binder = b;
239                    r.callback = callback;
240                    r.pkgForDebug = pkgForDebug;
241                    r.callerUid = callerUid;
242                    mRecords.add(r);
243                    if (DBG) Slog.i(TAG, "listen: add new record=" + r);
244                }
245                int send = events & (events ^ r.events);
246                r.events = events;
247                if (notifyNow) {
248                    if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
249                        try {
250                            r.callback.onServiceStateChanged(new ServiceState(mServiceState));
251                        } catch (RemoteException ex) {
252                            remove(r.binder);
253                        }
254                    }
255                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
256                        try {
257                            int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
258                            r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
259                                    : gsmSignalStrength));
260                        } catch (RemoteException ex) {
261                            remove(r.binder);
262                        }
263                    }
264                    if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
265                        try {
266                            r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
267                        } catch (RemoteException ex) {
268                            remove(r.binder);
269                        }
270                    }
271                    if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
272                        try {
273                            r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
274                        } catch (RemoteException ex) {
275                            remove(r.binder);
276                        }
277                    }
278                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
279                        try {
280                            if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
281                            r.callback.onCellLocationChanged(new Bundle(mCellLocation));
282                        } catch (RemoteException ex) {
283                            remove(r.binder);
284                        }
285                    }
286                    if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
287                        try {
288                            r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
289                        } catch (RemoteException ex) {
290                            remove(r.binder);
291                        }
292                    }
293                    if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
294                        try {
295                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
296                                mDataConnectionNetworkType);
297                        } catch (RemoteException ex) {
298                            remove(r.binder);
299                        }
300                    }
301                    if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
302                        try {
303                            r.callback.onDataActivity(mDataActivity);
304                        } catch (RemoteException ex) {
305                            remove(r.binder);
306                        }
307                    }
308                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
309                        try {
310                            r.callback.onSignalStrengthsChanged(mSignalStrength);
311                        } catch (RemoteException ex) {
312                            remove(r.binder);
313                        }
314                    }
315                    if ((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
316                        try {
317                            r.callback.onOtaspChanged(mOtaspMode);
318                        } catch (RemoteException ex) {
319                            remove(r.binder);
320                        }
321                    }
322                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
323                        try {
324                            if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
325                            r.callback.onCellInfoChanged(mCellInfo);
326                        } catch (RemoteException ex) {
327                            remove(r.binder);
328                        }
329                    }
330                    if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) {
331                        try {
332                            r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
333                        } catch (RemoteException ex) {
334                            remove(r.binder);
335                        }
336                    }
337                    if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
338                        try {
339                            r.callback.onPreciseCallStateChanged(mPreciseCallState);
340                        } catch (RemoteException ex) {
341                            remove(r.binder);
342                        }
343                    }
344                    if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
345                        try {
346                            r.callback.onPreciseDataConnectionStateChanged(
347                                    mPreciseDataConnectionState);
348                        } catch (RemoteException ex) {
349                            remove(r.binder);
350                        }
351                    }
352                }
353            }
354        } else {
355            remove(callback.asBinder());
356        }
357    }
358
359    private void remove(IBinder binder) {
360        synchronized (mRecords) {
361            final int recordCount = mRecords.size();
362            for (int i = 0; i < recordCount; i++) {
363                if (mRecords.get(i).binder == binder) {
364                    mRecords.remove(i);
365                    return;
366                }
367            }
368        }
369    }
370
371    public void notifyCallState(int state, String incomingNumber) {
372        if (!checkNotifyPermission("notifyCallState()")) {
373            return;
374        }
375        synchronized (mRecords) {
376            mCallState = state;
377            mCallIncomingNumber = incomingNumber;
378            for (Record r : mRecords) {
379                if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
380                    try {
381                        r.callback.onCallStateChanged(state, incomingNumber);
382                    } catch (RemoteException ex) {
383                        mRemoveList.add(r.binder);
384                    }
385                }
386            }
387            handleRemoveListLocked();
388        }
389        broadcastCallStateChanged(state, incomingNumber);
390    }
391
392    public void notifyServiceState(ServiceState state) {
393        if (!checkNotifyPermission("notifyServiceState()")){
394            return;
395        }
396        long ident = Binder.clearCallingIdentity();
397        try {
398            mBatteryStats.notePhoneState(state.getState());
399        } catch (RemoteException re) {
400            // Can't do much
401        } finally {
402            Binder.restoreCallingIdentity(ident);
403        }
404        synchronized (mRecords) {
405            mServiceState = state;
406            for (Record r : mRecords) {
407                if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
408                    try {
409                        r.callback.onServiceStateChanged(new ServiceState(state));
410                    } catch (RemoteException ex) {
411                        mRemoveList.add(r.binder);
412                    }
413                }
414            }
415            handleRemoveListLocked();
416        }
417        broadcastServiceStateChanged(state);
418    }
419
420    public void notifySignalStrength(SignalStrength signalStrength) {
421        if (!checkNotifyPermission("notifySignalStrength()")) {
422            return;
423        }
424        synchronized (mRecords) {
425            mSignalStrength = signalStrength;
426            for (Record r : mRecords) {
427                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
428                    try {
429                        r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
430                    } catch (RemoteException ex) {
431                        mRemoveList.add(r.binder);
432                    }
433                }
434                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
435                    try {
436                        int gsmSignalStrength = signalStrength.getGsmSignalStrength();
437                        r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
438                                : gsmSignalStrength));
439                    } catch (RemoteException ex) {
440                        mRemoveList.add(r.binder);
441                    }
442                }
443            }
444            handleRemoveListLocked();
445        }
446        broadcastSignalStrengthChanged(signalStrength);
447    }
448
449    public void notifyCellInfo(List<CellInfo> cellInfo) {
450        if (!checkNotifyPermission("notifyCellInfo()")) {
451            return;
452        }
453
454        synchronized (mRecords) {
455            mCellInfo = cellInfo;
456            for (Record r : mRecords) {
457                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
458                    try {
459                        if (DBG_LOC) {
460                            Slog.d(TAG, "notifyCellInfo: mCellInfo=" + mCellInfo + " r=" + r);
461                        }
462                        r.callback.onCellInfoChanged(cellInfo);
463                    } catch (RemoteException ex) {
464                        mRemoveList.add(r.binder);
465                    }
466                }
467            }
468            handleRemoveListLocked();
469        }
470    }
471
472    public void notifyDataConnectionRealTimeInfo(DataConnectionRealTimeInfo dcRtInfo) {
473        if (!checkNotifyPermission("notifyDataConnectionRealTimeInfo()")) {
474            return;
475        }
476
477        synchronized (mRecords) {
478            mDcRtInfo = dcRtInfo;
479            for (Record r : mRecords) {
480                if (validateEventsAndUserLocked(r,
481                        PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO)) {
482                    try {
483                        if (DBG_LOC) {
484                            Slog.d(TAG, "notifyDataConnectionRealTimeInfo: mDcRtInfo="
485                                    + mDcRtInfo + " r=" + r);
486                        }
487                        r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
488                    } catch (RemoteException ex) {
489                        mRemoveList.add(r.binder);
490                    }
491                }
492            }
493            handleRemoveListLocked();
494        }
495    }
496
497    public void notifyMessageWaitingChanged(boolean mwi) {
498        if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
499            return;
500        }
501        synchronized (mRecords) {
502            mMessageWaiting = mwi;
503            for (Record r : mRecords) {
504                if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
505                    try {
506                        r.callback.onMessageWaitingIndicatorChanged(mwi);
507                    } catch (RemoteException ex) {
508                        mRemoveList.add(r.binder);
509                    }
510                }
511            }
512            handleRemoveListLocked();
513        }
514    }
515
516    public void notifyCallForwardingChanged(boolean cfi) {
517        if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
518            return;
519        }
520        synchronized (mRecords) {
521            mCallForwarding = cfi;
522            for (Record r : mRecords) {
523                if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
524                    try {
525                        r.callback.onCallForwardingIndicatorChanged(cfi);
526                    } catch (RemoteException ex) {
527                        mRemoveList.add(r.binder);
528                    }
529                }
530            }
531            handleRemoveListLocked();
532        }
533    }
534
535    public void notifyDataActivity(int state) {
536        if (!checkNotifyPermission("notifyDataActivity()" )) {
537            return;
538        }
539        synchronized (mRecords) {
540            mDataActivity = state;
541            for (Record r : mRecords) {
542                if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
543                    try {
544                        r.callback.onDataActivity(state);
545                    } catch (RemoteException ex) {
546                        mRemoveList.add(r.binder);
547                    }
548                }
549            }
550            handleRemoveListLocked();
551        }
552    }
553
554    public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
555            String reason, String apn, String apnType, LinkProperties linkProperties,
556            NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
557        if (!checkNotifyPermission("notifyDataConnection()" )) {
558            return;
559        }
560        if (DBG) {
561            Slog.i(TAG, "notifyDataConnection: state=" + state + " isDataConnectivityPossible="
562                + isDataConnectivityPossible + " reason='" + reason
563                + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
564                + " mRecords.size()=" + mRecords.size() + " mRecords=" + mRecords);
565        }
566        synchronized (mRecords) {
567            boolean modified = false;
568            if (state == TelephonyManager.DATA_CONNECTED) {
569                if (!mConnectedApns.contains(apnType)) {
570                    mConnectedApns.add(apnType);
571                    if (mDataConnectionState != state) {
572                        mDataConnectionState = state;
573                        modified = true;
574                    }
575                }
576            } else {
577                if (mConnectedApns.remove(apnType)) {
578                    if (mConnectedApns.isEmpty()) {
579                        mDataConnectionState = state;
580                        modified = true;
581                    } else {
582                        // leave mDataConnectionState as is and
583                        // send out the new status for the APN in question.
584                    }
585                }
586            }
587            mDataConnectionPossible = isDataConnectivityPossible;
588            mDataConnectionReason = reason;
589            mDataConnectionLinkProperties = linkProperties;
590            mDataConnectionNetworkCapabilities = networkCapabilities;
591            if (mDataConnectionNetworkType != networkType) {
592                mDataConnectionNetworkType = networkType;
593                // need to tell registered listeners about the new network type
594                modified = true;
595            }
596            if (modified) {
597                if (DBG) {
598                    Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState
599                        + ", " + mDataConnectionNetworkType + ")");
600                }
601                for (Record r : mRecords) {
602                    if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
603                        try {
604                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
605                                    mDataConnectionNetworkType);
606                        } catch (RemoteException ex) {
607                            mRemoveList.add(r.binder);
608                        }
609                    }
610                }
611                handleRemoveListLocked();
612            }
613            mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
614                    apnType, apn, reason, linkProperties, "");
615            for (Record r : mRecords) {
616                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
617                    try {
618                        r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
619                    } catch (RemoteException ex) {
620                        mRemoveList.add(r.binder);
621                    }
622                }
623            }
624            handleRemoveListLocked();
625        }
626        broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
627                apnType, linkProperties, networkCapabilities, roaming);
628        broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
629                linkProperties, "");
630    }
631
632    public void notifyDataConnectionFailed(String reason, String apnType) {
633        if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
634            return;
635        }
636        synchronized (mRecords) {
637            mPreciseDataConnectionState = new PreciseDataConnectionState(
638                    TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
639                    apnType, "", reason, null, "");
640            for (Record r : mRecords) {
641                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
642                    try {
643                        r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
644                    } catch (RemoteException ex) {
645                        mRemoveList.add(r.binder);
646                    }
647                }
648            }
649            handleRemoveListLocked();
650        }
651        broadcastDataConnectionFailed(reason, apnType);
652        broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
653                TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
654    }
655
656    public void notifyCellLocation(Bundle cellLocation) {
657        if (!checkNotifyPermission("notifyCellLocation()")) {
658            return;
659        }
660        synchronized (mRecords) {
661            mCellLocation = cellLocation;
662            for (Record r : mRecords) {
663                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
664                    try {
665                        if (DBG_LOC) {
666                            Slog.d(TAG, "notifyCellLocation: mCellLocation=" + mCellLocation
667                                    + " r=" + r);
668                        }
669                        r.callback.onCellLocationChanged(new Bundle(cellLocation));
670                    } catch (RemoteException ex) {
671                        mRemoveList.add(r.binder);
672                    }
673
674                }
675            }
676            handleRemoveListLocked();
677        }
678    }
679
680    public void notifyOtaspChanged(int otaspMode) {
681        if (!checkNotifyPermission("notifyOtaspChanged()" )) {
682            return;
683        }
684        synchronized (mRecords) {
685            mOtaspMode = otaspMode;
686            for (Record r : mRecords) {
687                if ((r.events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
688                    try {
689                        r.callback.onOtaspChanged(otaspMode);
690                    } catch (RemoteException ex) {
691                        mRemoveList.add(r.binder);
692                    }
693                }
694            }
695            handleRemoveListLocked();
696        }
697    }
698
699    public void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
700            int backgroundCallState) {
701        if (!checkNotifyPermission("notifyPreciseCallState()")) {
702            return;
703        }
704        synchronized (mRecords) {
705            mRingingCallState = ringingCallState;
706            mForegroundCallState = foregroundCallState;
707            mBackgroundCallState = backgroundCallState;
708            mPreciseCallState = new PreciseCallState(ringingCallState, foregroundCallState,
709                    backgroundCallState,
710                    DisconnectCause.NOT_VALID,
711                    PreciseDisconnectCause.NOT_VALID);
712            for (Record r : mRecords) {
713                if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
714                    try {
715                        r.callback.onPreciseCallStateChanged(mPreciseCallState);
716                    } catch (RemoteException ex) {
717                        mRemoveList.add(r.binder);
718                    }
719                }
720            }
721            handleRemoveListLocked();
722        }
723        broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, backgroundCallState,
724                DisconnectCause.NOT_VALID,
725                PreciseDisconnectCause.NOT_VALID);
726    }
727
728    public void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause) {
729        if (!checkNotifyPermission("notifyDisconnectCause()")) {
730            return;
731        }
732        synchronized (mRecords) {
733            mPreciseCallState = new PreciseCallState(mRingingCallState, mForegroundCallState,
734                    mBackgroundCallState, disconnectCause, preciseDisconnectCause);
735            for (Record r : mRecords) {
736                if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
737                    try {
738                        r.callback.onPreciseCallStateChanged(mPreciseCallState);
739                    } catch (RemoteException ex) {
740                        mRemoveList.add(r.binder);
741                    }
742                }
743            }
744            handleRemoveListLocked();
745        }
746        broadcastPreciseCallStateChanged(mRingingCallState, mForegroundCallState,
747                mBackgroundCallState, disconnectCause, preciseDisconnectCause);
748    }
749
750    public void notifyPreciseDataConnectionFailed(String reason, String apnType,
751            String apn, String failCause) {
752        if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
753            return;
754        }
755        synchronized (mRecords) {
756            mPreciseDataConnectionState = new PreciseDataConnectionState(
757                    TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN,
758                    apnType, apn, reason, null, failCause);
759            for (Record r : mRecords) {
760                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
761                    try {
762                        r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
763                    } catch (RemoteException ex) {
764                        mRemoveList.add(r.binder);
765                    }
766                }
767            }
768            handleRemoveListLocked();
769        }
770        broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
771                TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
772    }
773
774    @Override
775    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
776        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
777                != PackageManager.PERMISSION_GRANTED) {
778            pw.println("Permission Denial: can't dump telephony.registry from from pid="
779                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
780            return;
781        }
782        synchronized (mRecords) {
783            final int recordCount = mRecords.size();
784            pw.println("last known state:");
785            pw.println("  mCallState=" + mCallState);
786            pw.println("  mCallIncomingNumber=" + mCallIncomingNumber);
787            pw.println("  mServiceState=" + mServiceState);
788            pw.println("  mSignalStrength=" + mSignalStrength);
789            pw.println("  mMessageWaiting=" + mMessageWaiting);
790            pw.println("  mCallForwarding=" + mCallForwarding);
791            pw.println("  mDataActivity=" + mDataActivity);
792            pw.println("  mDataConnectionState=" + mDataConnectionState);
793            pw.println("  mDataConnectionPossible=" + mDataConnectionPossible);
794            pw.println("  mDataConnectionReason=" + mDataConnectionReason);
795            pw.println("  mDataConnectionApn=" + mDataConnectionApn);
796            pw.println("  mDataConnectionLinkProperties=" + mDataConnectionLinkProperties);
797            pw.println("  mDataConnectionNetworkCapabilities=" +
798                    mDataConnectionNetworkCapabilities);
799            pw.println("  mCellLocation=" + mCellLocation);
800            pw.println("  mCellInfo=" + mCellInfo);
801            pw.println("  mDcRtInfo=" + mDcRtInfo);
802            pw.println("registrations: count=" + recordCount);
803            for (Record r : mRecords) {
804                pw.println("  " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events));
805            }
806        }
807    }
808
809    //
810    // the legacy intent broadcasting
811    //
812
813    private void broadcastServiceStateChanged(ServiceState state) {
814        Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
815        Bundle data = new Bundle();
816        state.fillInNotifierBundle(data);
817        intent.putExtras(data);
818        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
819    }
820
821    private void broadcastSignalStrengthChanged(SignalStrength signalStrength) {
822        long ident = Binder.clearCallingIdentity();
823        try {
824            mBatteryStats.notePhoneSignalStrength(signalStrength);
825        } catch (RemoteException e) {
826            /* The remote entity disappeared, we can safely ignore the exception. */
827        } finally {
828            Binder.restoreCallingIdentity(ident);
829        }
830
831        Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
832        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
833        Bundle data = new Bundle();
834        signalStrength.fillInNotifierBundle(data);
835        intent.putExtras(data);
836        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
837    }
838
839    private void broadcastCallStateChanged(int state, String incomingNumber) {
840        long ident = Binder.clearCallingIdentity();
841        try {
842            if (state == TelephonyManager.CALL_STATE_IDLE) {
843                mBatteryStats.notePhoneOff();
844            } else {
845                mBatteryStats.notePhoneOn();
846            }
847        } catch (RemoteException e) {
848            /* The remote entity disappeared, we can safely ignore the exception. */
849        } finally {
850            Binder.restoreCallingIdentity(ident);
851        }
852
853        Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
854        intent.putExtra(PhoneConstants.STATE_KEY,
855                DefaultPhoneNotifier.convertCallState(state).toString());
856        if (!TextUtils.isEmpty(incomingNumber)) {
857            intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
858        }
859        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
860                android.Manifest.permission.READ_PHONE_STATE);
861    }
862
863    private void broadcastDataConnectionStateChanged(int state,
864            boolean isDataConnectivityPossible,
865            String reason, String apn, String apnType, LinkProperties linkProperties,
866            NetworkCapabilities networkCapabilities, boolean roaming) {
867        // Note: not reporting to the battery stats service here, because the
868        // status bar takes care of that after taking into account all of the
869        // required info.
870        Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
871        intent.putExtra(PhoneConstants.STATE_KEY,
872                DefaultPhoneNotifier.convertDataState(state).toString());
873        if (!isDataConnectivityPossible) {
874            intent.putExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, true);
875        }
876        if (reason != null) {
877            intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
878        }
879        if (linkProperties != null) {
880            intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
881            String iface = linkProperties.getInterfaceName();
882            if (iface != null) {
883                intent.putExtra(PhoneConstants.DATA_IFACE_NAME_KEY, iface);
884            }
885        }
886        if (networkCapabilities != null) {
887            intent.putExtra(PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY, networkCapabilities);
888        }
889        if (roaming) intent.putExtra(PhoneConstants.DATA_NETWORK_ROAMING_KEY, true);
890
891        intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
892        intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
893        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
894    }
895
896    private void broadcastDataConnectionFailed(String reason, String apnType) {
897        Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
898        intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
899        intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
900        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
901    }
902
903    private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState,
904            int backgroundCallState, int disconnectCause, int preciseDisconnectCause) {
905        Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
906        intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
907        intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
908        intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState);
909        intent.putExtra(TelephonyManager.EXTRA_DISCONNECT_CAUSE, disconnectCause);
910        intent.putExtra(TelephonyManager.EXTRA_PRECISE_DISCONNECT_CAUSE, preciseDisconnectCause);
911        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
912                android.Manifest.permission.READ_PRECISE_PHONE_STATE);
913    }
914
915    private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
916            String apnType, String apn, String reason, LinkProperties linkProperties, String failCause) {
917        Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
918        intent.putExtra(PhoneConstants.STATE_KEY, state);
919        intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
920        if (reason != null) intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
921        if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
922        if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
923        if (linkProperties != null) intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
924        if (failCause != null) intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);
925
926        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
927                android.Manifest.permission.READ_PRECISE_PHONE_STATE);
928    }
929
930    private boolean checkNotifyPermission(String method) {
931        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
932                == PackageManager.PERMISSION_GRANTED) {
933            return true;
934        }
935        String msg = "Modify Phone State Permission Denial: " + method + " from pid="
936                + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
937        if (DBG) Slog.w(TAG, msg);
938        return false;
939    }
940
941    private void checkListenerPermission(int events) {
942        if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
943            mContext.enforceCallingOrSelfPermission(
944                    android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
945
946        }
947
948        if ((events & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
949            mContext.enforceCallingOrSelfPermission(
950                    android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
951
952        }
953
954        if ((events & PHONE_STATE_PERMISSION_MASK) != 0) {
955            mContext.enforceCallingOrSelfPermission(
956                    android.Manifest.permission.READ_PHONE_STATE, null);
957        }
958
959        if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
960            mContext.enforceCallingOrSelfPermission(
961                    android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
962
963        }
964    }
965
966    private void handleRemoveListLocked() {
967        if (mRemoveList.size() > 0) {
968            for (IBinder b: mRemoveList) {
969                remove(b);
970            }
971            mRemoveList.clear();
972        }
973    }
974
975    private boolean validateEventsAndUserLocked(Record r, int events) {
976        int foregroundUser;
977        long callingIdentity = Binder.clearCallingIdentity();
978        boolean valid = false;
979        try {
980            foregroundUser = ActivityManager.getCurrentUser();
981            valid = r.callerUid ==  foregroundUser && (r.events & events) != 0;
982            if (DBG | DBG_LOC) {
983                Slog.d(TAG, "validateEventsAndUserLocked: valid=" + valid
984                        + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
985                        + " r.events=" + r.events + " events=" + events);
986            }
987        } finally {
988            Binder.restoreCallingIdentity(callingIdentity);
989        }
990        return valid;
991    }
992}
993