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