1/* 2 * Copyright (C) 2012 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.bluetooth.BluetoothAdapter; 21import android.bluetooth.IBluetooth; 22import android.bluetooth.IBluetoothCallback; 23import android.bluetooth.IBluetoothManager; 24import android.bluetooth.IBluetoothManagerCallback; 25import android.bluetooth.IBluetoothStateChangeCallback; 26import android.content.BroadcastReceiver; 27import android.content.ComponentName; 28import android.content.ContentResolver; 29import android.content.Context; 30import android.content.Intent; 31import android.content.IntentFilter; 32import android.content.ServiceConnection; 33import android.os.Binder; 34import android.os.Handler; 35import android.os.HandlerThread; 36import android.os.IBinder; 37import android.os.Looper; 38import android.os.Message; 39import android.os.Process; 40import android.os.RemoteCallbackList; 41import android.os.RemoteException; 42import android.os.SystemClock; 43import android.os.UserHandle; 44import android.provider.Settings; 45import android.util.Log; 46class BluetoothManagerService extends IBluetoothManager.Stub { 47 private static final String TAG = "BluetoothManagerService"; 48 private static final boolean DBG = true; 49 50 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 51 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 52 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED"; 53 private static final String EXTRA_ACTION="action"; 54 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid"; 55 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address"; 56 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name"; 57 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind 58 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save 59 //Maximum msec to wait for service restart 60 private static final int SERVICE_RESTART_TIME_MS = 200; 61 //Maximum msec to delay MESSAGE_USER_SWITCHED 62 private static final int USER_SWITCHED_TIME_MS = 200; 63 64 private static final int MESSAGE_ENABLE = 1; 65 private static final int MESSAGE_DISABLE = 2; 66 private static final int MESSAGE_REGISTER_ADAPTER = 20; 67 private static final int MESSAGE_UNREGISTER_ADAPTER = 21; 68 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; 69 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; 70 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; 71 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; 72 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42; 73 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60; 74 private static final int MESSAGE_TIMEOUT_BIND =100; 75 private static final int MESSAGE_TIMEOUT_UNBIND =101; 76 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200; 77 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201; 78 private static final int MESSAGE_USER_SWITCHED = 300; 79 private static final int MAX_SAVE_RETRIES=3; 80 // Bluetooth persisted setting is off 81 private static final int BLUETOOTH_OFF=0; 82 // Bluetooth persisted setting is on 83 // and Airplane mode won't affect Bluetooth state at start up 84 private static final int BLUETOOTH_ON_BLUETOOTH=1; 85 // Bluetooth persisted setting is on 86 // but Airplane mode will affect Bluetooth state at start up 87 // and Airplane mode will have higher priority. 88 private static final int BLUETOOTH_ON_AIRPLANE=2; 89 90 private final Context mContext; 91 92 // Locks are not provided for mName and mAddress. 93 // They are accessed in handler or broadcast receiver, same thread context. 94 private String mAddress; 95 private String mName; 96 private final ContentResolver mContentResolver; 97 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; 98 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks; 99 private IBluetooth mBluetooth; 100 private boolean mBinding; 101 private boolean mUnbinding; 102 // used inside handler thread 103 private boolean mQuietEnable = false; 104 // configuarion from external IBinder call which is used to 105 // synchronize with broadcast receiver. 106 private boolean mQuietEnableExternal; 107 // configuarion from external IBinder call which is used to 108 // synchronize with broadcast receiver. 109 private boolean mEnableExternal; 110 // used inside handler thread 111 private boolean mEnable; 112 private int mState; 113 private HandlerThread mThread; 114 private final BluetoothHandler mHandler; 115 116 private void registerForAirplaneMode(IntentFilter filter) { 117 final ContentResolver resolver = mContext.getContentResolver(); 118 final String airplaneModeRadios = Settings.Global.getString(resolver, 119 Settings.Global.AIRPLANE_MODE_RADIOS); 120 final String toggleableRadios = Settings.Global.getString(resolver, 121 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 122 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true : 123 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH); 124 if (mIsAirplaneSensitive) { 125 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 126 } 127 } 128 129 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { 130 @Override 131 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { 132 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState); 133 mHandler.sendMessage(msg); 134 } 135 }; 136 137 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 138 @Override 139 public void onReceive(Context context, Intent intent) { 140 String action = intent.getAction(); 141 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { 142 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); 143 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName); 144 if (newName != null) { 145 storeNameAndAddress(newName, null); 146 } 147 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { 148 synchronized(mReceiver) { 149 if (isBluetoothPersistedStateOn()) { 150 if (isAirplaneModeOn()) { 151 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE); 152 } else { 153 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); 154 } 155 } 156 if (isAirplaneModeOn()) { 157 // disable without persisting the setting 158 sendDisableMsg(); 159 } else if (mEnableExternal) { 160 // enable without persisting the setting 161 sendEnableMsg(mQuietEnableExternal); 162 } 163 } 164 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { 165 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED, 166 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); 167 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { 168 synchronized(mReceiver) { 169 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) { 170 //Enable 171 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth."); 172 sendEnableMsg(mQuietEnableExternal); 173 } 174 } 175 176 if (!isNameAndAddressSet()) { 177 //Sync the Bluetooth name and address from the Bluetooth Adapter 178 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address..."); 179 getNameAndAddress(); 180 } 181 } 182 } 183 }; 184 185 BluetoothManagerService(Context context) { 186 mThread = new HandlerThread("BluetoothManager"); 187 mThread.start(); 188 mHandler = new BluetoothHandler(mThread.getLooper()); 189 190 mContext = context; 191 mBluetooth = null; 192 mBinding = false; 193 mUnbinding = false; 194 mEnable = false; 195 mState = BluetoothAdapter.STATE_OFF; 196 mQuietEnableExternal = false; 197 mEnableExternal = false; 198 mAddress = null; 199 mName = null; 200 mContentResolver = context.getContentResolver(); 201 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); 202 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>(); 203 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); 204 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 205 filter.addAction(Intent.ACTION_USER_SWITCHED); 206 registerForAirplaneMode(filter); 207 mContext.registerReceiver(mReceiver, filter); 208 loadStoredNameAndAddress(); 209 if (isBluetoothPersistedStateOn()) { 210 mEnableExternal = true; 211 } 212 } 213 214 /** 215 * Returns true if airplane mode is currently on 216 */ 217 private final boolean isAirplaneModeOn() { 218 return Settings.Global.getInt(mContext.getContentResolver(), 219 Settings.Global.AIRPLANE_MODE_ON, 0) == 1; 220 } 221 222 /** 223 * Returns true if the Bluetooth saved state is "on" 224 */ 225 private final boolean isBluetoothPersistedStateOn() { 226 return Settings.Global.getInt(mContentResolver, 227 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF; 228 } 229 230 /** 231 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH 232 */ 233 private final boolean isBluetoothPersistedStateOnBluetooth() { 234 return Settings.Global.getInt(mContentResolver, 235 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH; 236 } 237 238 /** 239 * Save the Bluetooth on/off state 240 * 241 */ 242 private void persistBluetoothSetting(int value) { 243 Settings.Global.putInt(mContext.getContentResolver(), 244 Settings.Global.BLUETOOTH_ON, 245 value); 246 } 247 248 /** 249 * Returns true if the Bluetooth Adapter's name and address is 250 * locally cached 251 * @return 252 */ 253 private boolean isNameAndAddressSet() { 254 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0; 255 } 256 257 /** 258 * Retrieve the Bluetooth Adapter's name and address and save it in 259 * in the local cache 260 */ 261 private void loadStoredNameAndAddress() { 262 if (DBG) Log.d(TAG, "Loading stored name and address"); 263 if (mContext.getResources().getBoolean 264 (com.android.internal.R.bool.config_bluetooth_address_validation) && 265 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) { 266 // if the valid flag is not set, don't load the address and name 267 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored"); 268 return; 269 } 270 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME); 271 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS); 272 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress); 273 } 274 275 /** 276 * Save the Bluetooth name and address in the persistent store. 277 * Only non-null values will be saved. 278 * @param name 279 * @param address 280 */ 281 private void storeNameAndAddress(String name, String address) { 282 if (name != null) { 283 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name); 284 mName = name; 285 if (DBG) Log.d(TAG,"Stored Bluetooth name: " + 286 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME)); 287 } 288 289 if (address != null) { 290 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address); 291 mAddress=address; 292 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " + 293 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS)); 294 } 295 296 if ((name != null) && (address != null)) { 297 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1); 298 } 299 } 300 301 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){ 302 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); 303 msg.obj = callback; 304 mHandler.sendMessage(msg); 305 synchronized(mConnection) { 306 return mBluetooth; 307 } 308 } 309 310 public void unregisterAdapter(IBluetoothManagerCallback callback) { 311 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 312 "Need BLUETOOTH permission"); 313 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); 314 msg.obj = callback; 315 mHandler.sendMessage(msg); 316 } 317 318 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { 319 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 320 "Need BLUETOOTH permission"); 321 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); 322 msg.obj = callback; 323 mHandler.sendMessage(msg); 324 } 325 326 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { 327 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 328 "Need BLUETOOTH permission"); 329 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); 330 msg.obj = callback; 331 mHandler.sendMessage(msg); 332 } 333 334 public boolean isEnabled() { 335 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 336 (!checkIfCallerIsForegroundUser())) { 337 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user"); 338 return false; 339 } 340 341 synchronized(mConnection) { 342 try { 343 return (mBluetooth != null && mBluetooth.isEnabled()); 344 } catch (RemoteException e) { 345 Log.e(TAG, "isEnabled()", e); 346 } 347 } 348 return false; 349 } 350 351 public void getNameAndAddress() { 352 if (DBG) { 353 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth + 354 " mBinding = " + mBinding); 355 } 356 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 357 mHandler.sendMessage(msg); 358 } 359 public boolean enableNoAutoConnect() 360 { 361 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 362 "Need BLUETOOTH ADMIN permission"); 363 364 if (DBG) { 365 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + 366 " mBinding = " + mBinding); 367 } 368 int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); 369 370 if (callingAppId != Process.NFC_UID) { 371 throw new SecurityException("no permission to enable Bluetooth quietly"); 372 } 373 374 synchronized(mReceiver) { 375 mQuietEnableExternal = true; 376 mEnableExternal = true; 377 sendEnableMsg(true); 378 } 379 return true; 380 381 } 382 public boolean enable() { 383 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 384 (!checkIfCallerIsForegroundUser())) { 385 Log.w(TAG,"enable(): not allowed for non-active and non system user"); 386 return false; 387 } 388 389 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 390 "Need BLUETOOTH ADMIN permission"); 391 if (DBG) { 392 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth + 393 " mBinding = " + mBinding); 394 } 395 396 synchronized(mReceiver) { 397 mQuietEnableExternal = false; 398 mEnableExternal = true; 399 // waive WRITE_SECURE_SETTINGS permission check 400 long callingIdentity = Binder.clearCallingIdentity(); 401 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); 402 Binder.restoreCallingIdentity(callingIdentity); 403 sendEnableMsg(false); 404 } 405 return true; 406 } 407 408 public boolean disable(boolean persist) { 409 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 410 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); 411 412 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 413 (!checkIfCallerIsForegroundUser())) { 414 Log.w(TAG,"disable(): not allowed for non-active and non system user"); 415 return false; 416 } 417 418 if (DBG) { 419 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth + 420 " mBinding = " + mBinding); 421 } 422 423 synchronized(mReceiver) { 424 if (persist) { 425 // waive WRITE_SECURE_SETTINGS permission check 426 long callingIdentity = Binder.clearCallingIdentity(); 427 persistBluetoothSetting(BLUETOOTH_OFF); 428 Binder.restoreCallingIdentity(callingIdentity); 429 } 430 mEnableExternal = false; 431 sendDisableMsg(); 432 } 433 return true; 434 } 435 436 public void unbindAndFinish() { 437 if (DBG) { 438 Log.d(TAG,"unbindAndFinish(): " + mBluetooth + 439 " mBinding = " + mBinding); 440 } 441 442 synchronized (mConnection) { 443 if (mUnbinding) return; 444 mUnbinding = true; 445 if (mBluetooth != null) { 446 if (!mConnection.isGetNameAddressOnly()) { 447 //Unregister callback object 448 try { 449 mBluetooth.unregisterCallback(mBluetoothCallback); 450 } catch (RemoteException re) { 451 Log.e(TAG, "Unable to unregister BluetoothCallback",re); 452 } 453 } 454 if (DBG) Log.d(TAG, "Sending unbind request."); 455 mBluetooth = null; 456 //Unbind 457 mContext.unbindService(mConnection); 458 mUnbinding = false; 459 mBinding = false; 460 } else { 461 mUnbinding=false; 462 } 463 } 464 } 465 466 private void sendBluetoothStateCallback(boolean isUp) { 467 int n = mStateChangeCallbacks.beginBroadcast(); 468 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); 469 for (int i=0; i <n;i++) { 470 try { 471 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); 472 } catch (RemoteException e) { 473 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e); 474 } 475 } 476 mStateChangeCallbacks.finishBroadcast(); 477 } 478 479 /** 480 * Inform BluetoothAdapter instances that Adapter service is up 481 */ 482 private void sendBluetoothServiceUpCallback() { 483 if (!mConnection.isGetNameAddressOnly()) { 484 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks"); 485 int n = mCallbacks.beginBroadcast(); 486 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); 487 for (int i=0; i <n;i++) { 488 try { 489 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); 490 } catch (RemoteException e) { 491 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); 492 } 493 } 494 mCallbacks.finishBroadcast(); 495 } 496 } 497 /** 498 * Inform BluetoothAdapter instances that Adapter service is down 499 */ 500 private void sendBluetoothServiceDownCallback() { 501 if (!mConnection.isGetNameAddressOnly()) { 502 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks"); 503 int n = mCallbacks.beginBroadcast(); 504 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers."); 505 for (int i=0; i <n;i++) { 506 try { 507 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); 508 } catch (RemoteException e) { 509 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); 510 } 511 } 512 mCallbacks.finishBroadcast(); 513 } 514 } 515 public String getAddress() { 516 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 517 "Need BLUETOOTH permission"); 518 519 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 520 (!checkIfCallerIsForegroundUser())) { 521 Log.w(TAG,"getAddress(): not allowed for non-active and non system user"); 522 return null; 523 } 524 525 synchronized(mConnection) { 526 if (mBluetooth != null) { 527 try { 528 return mBluetooth.getAddress(); 529 } catch (RemoteException e) { 530 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e); 531 } 532 } 533 } 534 // mAddress is accessed from outside. 535 // It is alright without a lock. Here, bluetooth is off, no other thread is 536 // changing mAddress 537 return mAddress; 538 } 539 540 public String getName() { 541 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 542 "Need BLUETOOTH permission"); 543 544 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 545 (!checkIfCallerIsForegroundUser())) { 546 Log.w(TAG,"getName(): not allowed for non-active and non system user"); 547 return null; 548 } 549 550 synchronized(mConnection) { 551 if (mBluetooth != null) { 552 try { 553 return mBluetooth.getName(); 554 } catch (RemoteException e) { 555 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e); 556 } 557 } 558 } 559 // mName is accessed from outside. 560 // It alright without a lock. Here, bluetooth is off, no other thread is 561 // changing mName 562 return mName; 563 } 564 565 private class BluetoothServiceConnection implements ServiceConnection { 566 567 private boolean mGetNameAddressOnly; 568 569 public void setGetNameAddressOnly(boolean getOnly) { 570 mGetNameAddressOnly = getOnly; 571 } 572 573 public boolean isGetNameAddressOnly() { 574 return mGetNameAddressOnly; 575 } 576 577 public void onServiceConnected(ComponentName className, IBinder service) { 578 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService"); 579 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); 580 msg.obj = service; 581 mHandler.sendMessage(msg); 582 } 583 584 public void onServiceDisconnected(ComponentName className) { 585 // Called if we unexpected disconnected. 586 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService"); 587 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); 588 mHandler.sendMessage(msg); 589 } 590 } 591 592 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); 593 594 private class BluetoothHandler extends Handler { 595 public BluetoothHandler(Looper looper) { 596 super(looper); 597 } 598 599 @Override 600 public void handleMessage(Message msg) { 601 if (DBG) Log.d (TAG, "Message: " + msg.what); 602 switch (msg.what) { 603 case MESSAGE_GET_NAME_AND_ADDRESS: { 604 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS"); 605 synchronized(mConnection) { 606 //Start bind request 607 if ((mBluetooth == null) && (!mBinding)) { 608 if (DBG) Log.d(TAG, "Binding to service to get name and address"); 609 mConnection.setGetNameAddressOnly(true); 610 //Start bind timeout and bind 611 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 612 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 613 Intent i = new Intent(IBluetooth.class.getName()); 614 if (!mContext.bindService(i, mConnection, 615 Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) { 616 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 617 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName()); 618 } else { 619 mBinding = true; 620 } 621 } 622 else { 623 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 624 saveMsg.arg1 = 0; 625 if (mBluetooth != null) { 626 mHandler.sendMessage(saveMsg); 627 } else { 628 // if enable is also called to bind the service 629 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED 630 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS); 631 } 632 } 633 } 634 break; 635 } 636 case MESSAGE_SAVE_NAME_AND_ADDRESS: { 637 boolean unbind = false; 638 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS"); 639 synchronized(mConnection) { 640 if (!mEnable && mBluetooth != null) { 641 try { 642 mBluetooth.enable(); 643 } catch (RemoteException e) { 644 Log.e(TAG,"Unable to call enable()",e); 645 } 646 } 647 } 648 if (mBluetooth != null) waitForOnOff(true, false); 649 synchronized(mConnection) { 650 if (mBluetooth != null) { 651 String name = null; 652 String address = null; 653 try { 654 name = mBluetooth.getName(); 655 address = mBluetooth.getAddress(); 656 } catch (RemoteException re) { 657 Log.e(TAG,"",re); 658 } 659 660 if (name != null && address != null) { 661 storeNameAndAddress(name,address); 662 if (mConnection.isGetNameAddressOnly()) { 663 unbind = true; 664 } 665 } else { 666 if (msg.arg1 < MAX_SAVE_RETRIES) { 667 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 668 retryMsg.arg1= 1+msg.arg1; 669 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1); 670 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS); 671 } else { 672 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded"); 673 if (mConnection.isGetNameAddressOnly()) { 674 unbind = true; 675 } 676 } 677 } 678 if (!mEnable) { 679 try { 680 mBluetooth.disable(); 681 } catch (RemoteException e) { 682 Log.e(TAG,"Unable to call disable()",e); 683 } 684 } 685 } else { 686 // rebind service by Request GET NAME AND ADDRESS 687 // if service is unbinded by disable or 688 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received 689 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 690 mHandler.sendMessage(getMsg); 691 } 692 } 693 if (!mEnable && mBluetooth != null) waitForOnOff(false, true); 694 if (unbind) { 695 unbindAndFinish(); 696 } 697 break; 698 } 699 case MESSAGE_ENABLE: 700 if (DBG) { 701 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth); 702 } 703 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 704 mEnable = true; 705 handleEnable(msg.arg1 == 1); 706 break; 707 708 case MESSAGE_DISABLE: 709 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 710 if (mEnable && mBluetooth != null) { 711 waitForOnOff(true, false); 712 mEnable = false; 713 handleDisable(); 714 waitForOnOff(false, false); 715 } else { 716 mEnable = false; 717 handleDisable(); 718 } 719 break; 720 721 case MESSAGE_REGISTER_ADAPTER: 722 { 723 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 724 boolean added = mCallbacks.register(callback); 725 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added ); 726 } 727 break; 728 case MESSAGE_UNREGISTER_ADAPTER: 729 { 730 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 731 boolean removed = mCallbacks.unregister(callback); 732 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed); 733 break; 734 } 735 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: 736 { 737 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 738 mStateChangeCallbacks.register(callback); 739 break; 740 } 741 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: 742 { 743 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 744 mStateChangeCallbacks.unregister(callback); 745 break; 746 } 747 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: 748 { 749 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED"); 750 751 //Remove timeout 752 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 753 754 IBinder service = (IBinder) msg.obj; 755 synchronized(mConnection) { 756 mBinding = false; 757 mBluetooth = IBluetooth.Stub.asInterface(service); 758 759 if (mConnection.isGetNameAddressOnly()) { 760 //Request GET NAME AND ADDRESS 761 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 762 mHandler.sendMessage(getMsg); 763 if (!mEnable) return; 764 } 765 766 mConnection.setGetNameAddressOnly(false); 767 //Register callback object 768 try { 769 mBluetooth.registerCallback(mBluetoothCallback); 770 } catch (RemoteException re) { 771 Log.e(TAG, "Unable to register BluetoothCallback",re); 772 } 773 //Inform BluetoothAdapter instances that service is up 774 sendBluetoothServiceUpCallback(); 775 776 //Do enable request 777 try { 778 if (mQuietEnable == false) { 779 if(!mBluetooth.enable()) { 780 Log.e(TAG,"IBluetooth.enable() returned false"); 781 } 782 } 783 else 784 { 785 if(!mBluetooth.enableNoAutoConnect()) { 786 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 787 } 788 } 789 } catch (RemoteException e) { 790 Log.e(TAG,"Unable to call enable()",e); 791 } 792 } 793 794 if (!mEnable) { 795 waitForOnOff(true, false); 796 handleDisable(); 797 waitForOnOff(false, false); 798 } 799 break; 800 } 801 case MESSAGE_TIMEOUT_BIND: { 802 Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); 803 synchronized(mConnection) { 804 mBinding = false; 805 } 806 break; 807 } 808 case MESSAGE_BLUETOOTH_STATE_CHANGE: 809 { 810 int prevState = msg.arg1; 811 int newState = msg.arg2; 812 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); 813 mState = newState; 814 bluetoothStateChangeHandler(prevState, newState); 815 break; 816 } 817 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: 818 { 819 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); 820 synchronized(mConnection) { 821 // if service is unbinded already, do nothing and return 822 if (mBluetooth == null) return; 823 mBluetooth = null; 824 } 825 826 if (mEnable) { 827 mEnable = false; 828 // Send a Bluetooth Restart message 829 Message restartMsg = mHandler.obtainMessage( 830 MESSAGE_RESTART_BLUETOOTH_SERVICE); 831 mHandler.sendMessageDelayed(restartMsg, 832 SERVICE_RESTART_TIME_MS); 833 } 834 835 if (!mConnection.isGetNameAddressOnly()) { 836 sendBluetoothServiceDownCallback(); 837 838 // Send BT state broadcast to update 839 // the BT icon correctly 840 if ((mState == BluetoothAdapter.STATE_TURNING_ON) || 841 (mState == BluetoothAdapter.STATE_ON)) { 842 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 843 BluetoothAdapter.STATE_TURNING_OFF); 844 mState = BluetoothAdapter.STATE_TURNING_OFF; 845 } 846 if (mState == BluetoothAdapter.STATE_TURNING_OFF) { 847 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, 848 BluetoothAdapter.STATE_OFF); 849 } 850 851 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 852 mState = BluetoothAdapter.STATE_OFF; 853 } 854 break; 855 } 856 case MESSAGE_RESTART_BLUETOOTH_SERVICE: 857 { 858 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:" 859 +" Restart IBluetooth service"); 860 /* Enable without persisting the setting as 861 it doesnt change when IBluetooth 862 service restarts */ 863 mEnable = true; 864 handleEnable(mQuietEnable); 865 break; 866 } 867 868 case MESSAGE_TIMEOUT_UNBIND: 869 { 870 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); 871 synchronized(mConnection) { 872 mUnbinding = false; 873 } 874 break; 875 } 876 877 case MESSAGE_USER_SWITCHED: 878 { 879 if (DBG) { 880 Log.d(TAG, "MESSAGE_USER_SWITCHED"); 881 } 882 mHandler.removeMessages(MESSAGE_USER_SWITCHED); 883 /* disable and enable BT when detect a user switch */ 884 if (mEnable && mBluetooth != null) { 885 synchronized (mConnection) { 886 if (mBluetooth != null) { 887 //Unregister callback object 888 try { 889 mBluetooth.unregisterCallback(mBluetoothCallback); 890 } catch (RemoteException re) { 891 Log.e(TAG, "Unable to unregister",re); 892 } 893 } 894 } 895 896 if (mState == BluetoothAdapter.STATE_TURNING_OFF) { 897 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE 898 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF); 899 mState = BluetoothAdapter.STATE_OFF; 900 } 901 if (mState == BluetoothAdapter.STATE_OFF) { 902 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON); 903 mState = BluetoothAdapter.STATE_TURNING_ON; 904 } 905 906 waitForOnOff(true, false); 907 908 if (mState == BluetoothAdapter.STATE_TURNING_ON) { 909 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); 910 } 911 912 // disable 913 handleDisable(); 914 // Pbap service need receive STATE_TURNING_OFF intent to close 915 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 916 BluetoothAdapter.STATE_TURNING_OFF); 917 918 waitForOnOff(false, true); 919 920 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, 921 BluetoothAdapter.STATE_OFF); 922 sendBluetoothServiceDownCallback(); 923 synchronized (mConnection) { 924 if (mBluetooth != null) { 925 mBluetooth = null; 926 //Unbind 927 mContext.unbindService(mConnection); 928 } 929 } 930 SystemClock.sleep(100); 931 932 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 933 mState = BluetoothAdapter.STATE_OFF; 934 // enable 935 handleEnable(mQuietEnable); 936 } else if (mBinding || mBluetooth != null) { 937 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); 938 userMsg.arg2 = 1 + msg.arg2; 939 // if user is switched when service is being binding 940 // delay sending MESSAGE_USER_SWITCHED 941 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS); 942 if (DBG) { 943 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2); 944 } 945 } 946 break; 947 } 948 } 949 } 950 } 951 952 private void handleEnable(boolean quietMode) { 953 mQuietEnable = quietMode; 954 955 synchronized(mConnection) { 956 if ((mBluetooth == null) && (!mBinding)) { 957 //Start bind timeout and bind 958 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 959 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 960 mConnection.setGetNameAddressOnly(false); 961 Intent i = new Intent(IBluetooth.class.getName()); 962 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE, 963 UserHandle.USER_CURRENT)) { 964 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 965 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName()); 966 } else { 967 mBinding = true; 968 } 969 } else if (mBluetooth != null) { 970 if (mConnection.isGetNameAddressOnly()) { 971 // if GetNameAddressOnly is set, we can clear this flag, 972 // so the service won't be unbind 973 // after name and address are saved 974 mConnection.setGetNameAddressOnly(false); 975 //Register callback object 976 try { 977 mBluetooth.registerCallback(mBluetoothCallback); 978 } catch (RemoteException re) { 979 Log.e(TAG, "Unable to register BluetoothCallback",re); 980 } 981 //Inform BluetoothAdapter instances that service is up 982 sendBluetoothServiceUpCallback(); 983 } 984 985 //Enable bluetooth 986 try { 987 if (!mQuietEnable) { 988 if(!mBluetooth.enable()) { 989 Log.e(TAG,"IBluetooth.enable() returned false"); 990 } 991 } 992 else { 993 if(!mBluetooth.enableNoAutoConnect()) { 994 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 995 } 996 } 997 } catch (RemoteException e) { 998 Log.e(TAG,"Unable to call enable()",e); 999 } 1000 } 1001 } 1002 } 1003 1004 private void handleDisable() { 1005 synchronized(mConnection) { 1006 // don't need to disable if GetNameAddressOnly is set, 1007 // service will be unbinded after Name and Address are saved 1008 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) { 1009 if (DBG) Log.d(TAG,"Sending off request."); 1010 1011 try { 1012 if(!mBluetooth.disable()) { 1013 Log.e(TAG,"IBluetooth.disable() returned false"); 1014 } 1015 } catch (RemoteException e) { 1016 Log.e(TAG,"Unable to call disable()",e); 1017 } 1018 } 1019 } 1020 } 1021 1022 private boolean checkIfCallerIsForegroundUser() { 1023 int foregroundUser; 1024 int callingUser = UserHandle.getCallingUserId(); 1025 int callingUid = Binder.getCallingUid(); 1026 long callingIdentity = Binder.clearCallingIdentity(); 1027 int callingAppId = UserHandle.getAppId(callingUid); 1028 boolean valid = false; 1029 try { 1030 foregroundUser = ActivityManager.getCurrentUser(); 1031 valid = (callingUser == foregroundUser) || 1032 callingAppId == Process.NFC_UID; 1033 if (DBG) { 1034 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid 1035 + " callingUser=" + callingUser 1036 + " foregroundUser=" + foregroundUser); 1037 } 1038 } finally { 1039 Binder.restoreCallingIdentity(callingIdentity); 1040 } 1041 return valid; 1042 } 1043 1044 private void bluetoothStateChangeHandler(int prevState, int newState) { 1045 if (prevState != newState) { 1046 //Notify all proxy objects first of adapter state change 1047 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { 1048 boolean isUp = (newState==BluetoothAdapter.STATE_ON); 1049 sendBluetoothStateCallback(isUp); 1050 1051 //If Bluetooth is off, send service down event to proxy objects, and unbind 1052 if (!isUp && canUnbindBluetoothService()) { 1053 sendBluetoothServiceDownCallback(); 1054 unbindAndFinish(); 1055 } 1056 } 1057 1058 //Send broadcast message to everyone else 1059 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 1060 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 1061 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 1062 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1063 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); 1064 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 1065 BLUETOOTH_PERM); 1066 } 1067 } 1068 1069 /** 1070 * if on is true, wait for state become ON 1071 * if off is true, wait for state become OFF 1072 * if both on and off are false, wait for state not ON 1073 */ 1074 private boolean waitForOnOff(boolean on, boolean off) { 1075 int i = 0; 1076 while (i < 10) { 1077 synchronized(mConnection) { 1078 try { 1079 if (mBluetooth == null) break; 1080 if (on) { 1081 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true; 1082 } else if (off) { 1083 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true; 1084 } else { 1085 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true; 1086 } 1087 } catch (RemoteException e) { 1088 Log.e(TAG, "getState()", e); 1089 break; 1090 } 1091 } 1092 if (on || off) { 1093 SystemClock.sleep(300); 1094 } else { 1095 SystemClock.sleep(50); 1096 } 1097 i++; 1098 } 1099 Log.e(TAG,"waitForOnOff time out"); 1100 return false; 1101 } 1102 1103 private void sendDisableMsg() { 1104 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE)); 1105 } 1106 1107 private void sendEnableMsg(boolean quietMode) { 1108 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, 1109 quietMode ? 1 : 0, 0)); 1110 } 1111 1112 private boolean canUnbindBluetoothService() { 1113 synchronized(mConnection) { 1114 //Only unbind with mEnable flag not set 1115 //For race condition: disable and enable back-to-back 1116 //Avoid unbind right after enable due to callback from disable 1117 //Only unbind with Bluetooth at OFF state 1118 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message 1119 try { 1120 if (mEnable || (mBluetooth == null)) return false; 1121 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false; 1122 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF); 1123 } catch (RemoteException e) { 1124 Log.e(TAG, "getState()", e); 1125 } 1126 } 1127 return false; 1128 } 1129} 1130