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