2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server;
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;
36 import java.util.ArrayList;
37 import java.io.FileDescriptor;
38 import java.io.PrintWriter;
39 import java.net.NetworkInterface;
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;
51 * Since phone process can be restarted, this class provides a centralized place
52 * that applications can register and be called back from.
54 class TelephonyRegistry extends ITelephonyRegistry.Stub {
55 private static final String TAG = "TelephonyRegistry";
57 private static class Record {
62 IPhoneStateListener callback;
67 private final Context mContext;
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>();
73 private final IBatteryStats mBatteryStats;
75 private int mCallState = TelephonyManager.CALL_STATE_IDLE;
77 private String mCallIncomingNumber = "";
79 private ServiceState mServiceState = new ServiceState();
81 private SignalStrength mSignalStrength = new SignalStrength();
83 private boolean mMessageWaiting = false;
85 private boolean mCallForwarding = false;
87 private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
89 private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN;
91 private boolean mDataConnectionPossible = false;
93 private String mDataConnectionReason = "";
95 private String mDataConnectionApn = "";
97 private ArrayList<String> mConnectedApns;
99 private LinkProperties mDataConnectionLinkProperties;
101 private LinkCapabilities mDataConnectionLinkCapabilities;
103 private Bundle mCellLocation = new Bundle();
105 private int mDataConnectionNetworkType;
107 private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
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;
116 // we keep a copy of all of the state so we can send it out when folks
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.
123 TelephonyRegistry(Context context) {
124 CellLocation location = CellLocation.getEmpty();
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);
132 mBatteryStats = BatteryStatsService.getService();
133 mConnectedApns = new ArrayList<String>();
136 public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
138 // Slog.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" +
139 // Integer.toHexString(events));
141 /* Checks permission and throws Security exception */
142 checkListenerPermission(events);
144 synchronized (mRecords) {
148 IBinder b = callback.asBinder();
149 final int N = mRecords.size();
150 for (int i = 0; i < N; i++) {
158 r.callback = callback;
159 r.pkgForDebug = pkgForDebug;
162 int send = events & (events ^ r.events);
165 if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
167 r.callback.onServiceStateChanged(new ServiceState(mServiceState));
168 } catch (RemoteException ex) {
172 if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
174 int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
175 r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
176 : gsmSignalStrength));
177 } catch (RemoteException ex) {
181 if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
183 r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
184 } catch (RemoteException ex) {
188 if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
190 r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
191 } catch (RemoteException ex) {
195 if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
197 r.callback.onCellLocationChanged(new Bundle(mCellLocation));
198 } catch (RemoteException ex) {
202 if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
204 r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
205 } catch (RemoteException ex) {
209 if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
211 r.callback.onDataConnectionStateChanged(mDataConnectionState,
212 mDataConnectionNetworkType);
213 } catch (RemoteException ex) {
217 if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
219 r.callback.onDataActivity(mDataActivity);
220 } catch (RemoteException ex) {
224 if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
226 r.callback.onSignalStrengthsChanged(mSignalStrength);
227 } catch (RemoteException ex) {
231 if ((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
233 r.callback.onOtaspChanged(mOtaspMode);
234 } catch (RemoteException ex) {
241 remove(callback.asBinder());
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) {
257 public void notifyCallState(int state, String incomingNumber) {
258 if (!checkNotifyPermission("notifyCallState()")) {
261 synchronized (mRecords) {
263 mCallIncomingNumber = incomingNumber;
264 for (Record r : mRecords) {
265 if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
267 r.callback.onCallStateChanged(state, incomingNumber);
268 } catch (RemoteException ex) {
269 mRemoveList.add(r.binder);
273 handleRemoveListLocked();
275 broadcastCallStateChanged(state, incomingNumber);
278 public void notifyServiceState(ServiceState state) {
279 if (!checkNotifyPermission("notifyServiceState()")){
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) {
288 r.callback.onServiceStateChanged(new ServiceState(state));
289 } catch (RemoteException ex) {
290 mRemoveList.add(r.binder);
294 handleRemoveListLocked();
296 broadcastServiceStateChanged(state);
299 public void notifySignalStrength(SignalStrength signalStrength) {
300 if (!checkNotifyPermission("notifySignalStrength()")) {
303 synchronized (mRecords) {
304 mSignalStrength = signalStrength;
305 for (Record r : mRecords) {
306 if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
308 r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
309 } catch (RemoteException ex) {
310 mRemoveList.add(r.binder);
313 if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
315 int gsmSignalStrength = signalStrength.getGsmSignalStrength();
316 r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
317 : gsmSignalStrength));
318 } catch (RemoteException ex) {
319 mRemoveList.add(r.binder);
323 handleRemoveListLocked();
325 broadcastSignalStrengthChanged(signalStrength);
328 public void notifyMessageWaitingChanged(boolean mwi) {
329 if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
332 synchronized (mRecords) {
333 mMessageWaiting = mwi;
334 for (Record r : mRecords) {
335 if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
337 r.callback.onMessageWaitingIndicatorChanged(mwi);
338 } catch (RemoteException ex) {
339 mRemoveList.add(r.binder);
343 handleRemoveListLocked();
347 public void notifyCallForwardingChanged(boolean cfi) {
348 if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
351 synchronized (mRecords) {
352 mCallForwarding = cfi;
353 for (Record r : mRecords) {
354 if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
356 r.callback.onCallForwardingIndicatorChanged(cfi);
357 } catch (RemoteException ex) {
358 mRemoveList.add(r.binder);
362 handleRemoveListLocked();
366 public void notifyDataActivity(int state) {
367 if (!checkNotifyPermission("notifyDataActivity()" )) {
370 synchronized (mRecords) {
371 mDataActivity = state;
372 for (Record r : mRecords) {
373 if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
375 r.callback.onDataActivity(state);
376 } catch (RemoteException ex) {
377 mRemoveList.add(r.binder);
381 handleRemoveListLocked();
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()" )) {
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;
405 if (mConnectedApns.remove(apnType)) {
406 if (mConnectedApns.isEmpty()) {
407 mDataConnectionState = state;
410 // leave mDataConnectionState as is and
411 // send out the new status for the APN in question.
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
425 Slog.d(TAG, "onDataConnectionStateChanged(" + state + ", " + networkType + ")");
426 for (Record r : mRecords) {
427 if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
429 r.callback.onDataConnectionStateChanged(state, networkType);
430 } catch (RemoteException ex) {
431 mRemoveList.add(r.binder);
435 handleRemoveListLocked();
438 broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
439 apnType, linkProperties, linkCapabilities);
442 public void notifyDataConnectionFailed(String reason, String apnType) {
443 if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
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) {
460 broadcastDataConnectionFailed(reason, apnType);
463 public void notifyCellLocation(Bundle cellLocation) {
464 if (!checkNotifyPermission("notifyCellLocation()")) {
467 synchronized (mRecords) {
468 mCellLocation = cellLocation;
469 for (Record r : mRecords) {
470 if ((r.events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
472 r.callback.onCellLocationChanged(new Bundle(cellLocation));
473 } catch (RemoteException ex) {
474 mRemoveList.add(r.binder);
479 handleRemoveListLocked();
483 public void notifyOtaspChanged(int otaspMode) {
484 if (!checkNotifyPermission("notifyOtaspChanged()" )) {
487 synchronized (mRecords) {
488 mOtaspMode = otaspMode;
489 for (Record r : mRecords) {
490 if ((r.events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
492 r.callback.onOtaspChanged(otaspMode);
493 } catch (RemoteException ex) {
494 mRemoveList.add(r.binder);
498 handleRemoveListLocked();
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());
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));
535 // the legacy intent broadcasting
538 private void broadcastServiceStateChanged(ServiceState state) {
539 long ident = Binder.clearCallingIdentity();
541 mBatteryStats.notePhoneState(state.getState());
542 } catch (RemoteException re) {
545 Binder.restoreCallingIdentity(ident);
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);
555 private void broadcastSignalStrengthChanged(SignalStrength signalStrength) {
556 long ident = Binder.clearCallingIdentity();
558 mBatteryStats.notePhoneSignalStrength(signalStrength);
559 } catch (RemoteException e) {
560 /* The remote entity disappeared, we can safely ignore the exception. */
562 Binder.restoreCallingIdentity(ident);
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);
573 private void broadcastCallStateChanged(int state, String incomingNumber) {
574 long ident = Binder.clearCallingIdentity();
576 if (state == TelephonyManager.CALL_STATE_IDLE) {
577 mBatteryStats.notePhoneOff();
579 mBatteryStats.notePhoneOn();
581 } catch (RemoteException e) {
582 /* The remote entity disappeared, we can safely ignore the exception. */
584 Binder.restoreCallingIdentity(ident);
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);
592 mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE);
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
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);
607 if (reason != null) {
608 intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason);
610 if (linkProperties != null) {
611 intent.putExtra(Phone.DATA_LINK_PROPERTIES_KEY, linkProperties);
612 String iface = linkProperties.getInterfaceName();
614 intent.putExtra(Phone.DATA_IFACE_NAME_KEY, iface);
617 if (linkCapabilities != null) {
618 intent.putExtra(Phone.DATA_LINK_CAPABILITIES_KEY, linkCapabilities);
620 intent.putExtra(Phone.DATA_APN_KEY, apn);
621 intent.putExtra(Phone.DATA_APN_TYPE_KEY, apnType);
622 mContext.sendStickyBroadcast(intent);
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);
632 private boolean checkNotifyPermission(String method) {
633 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
634 == PackageManager.PERMISSION_GRANTED) {
637 String msg = "Modify Phone State Permission Denial: " + method + " from pid="
638 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
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);
650 if ((events & PHONE_STATE_PERMISSION_MASK) != 0) {
651 mContext.enforceCallingOrSelfPermission(
652 android.Manifest.permission.READ_PHONE_STATE, null);
656 private void handleRemoveListLocked() {
657 if (mRemoveList.size() > 0) {
658 for (IBinder b: mRemoveList) {