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