BluetoothManagerService.java revision 5b614593e1a212e8ad9ac4a1e22a2954bb499233
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.BluetoothProfile; 22import android.bluetooth.IBluetooth; 23import android.bluetooth.IBluetoothGatt; 24import android.bluetooth.IBluetoothCallback; 25import android.bluetooth.IBluetoothHeadset; 26import android.bluetooth.IBluetoothManager; 27import android.bluetooth.IBluetoothManagerCallback; 28import android.bluetooth.IBluetoothProfileServiceConnection; 29import android.bluetooth.IBluetoothStateChangeCallback; 30import android.content.BroadcastReceiver; 31import android.content.ComponentName; 32import android.content.ContentResolver; 33import android.content.Context; 34import android.content.Intent; 35import android.content.IntentFilter; 36import android.content.ServiceConnection; 37import android.content.pm.PackageManager; 38import android.content.pm.UserInfo; 39import android.os.Binder; 40import android.os.Handler; 41import android.os.IBinder; 42import android.os.Looper; 43import android.os.Message; 44import android.os.Process; 45import android.os.RemoteCallbackList; 46import android.os.RemoteException; 47import android.os.SystemClock; 48import android.os.UserHandle; 49import android.os.UserManager; 50import android.provider.Settings; 51import android.util.Log; 52 53import java.io.FileDescriptor; 54import java.io.PrintWriter; 55 56import java.util.HashMap; 57import java.util.Map; 58import java.util.List; 59import java.util.Vector; 60 61class BluetoothManagerService extends IBluetoothManager.Stub { 62 private static final String TAG = "BluetoothManagerService"; 63 private static final boolean DBG = true; 64 65 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 66 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 67 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED"; 68 private static final String EXTRA_ACTION="action"; 69 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid"; 70 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address"; 71 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name"; 72 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind 73 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save 74 //Maximum msec to wait for service restart 75 private static final int SERVICE_RESTART_TIME_MS = 200; 76 //Maximum msec to wait for restart due to error 77 private static final int ERROR_RESTART_TIME_MS = 3000; 78 //Maximum msec to delay MESSAGE_USER_SWITCHED 79 private static final int USER_SWITCHED_TIME_MS = 200; 80 // Delay for the addProxy function in msec 81 private static final int ADD_PROXY_DELAY_MS = 100; 82 83 private static final int MESSAGE_ENABLE = 1; 84 private static final int MESSAGE_DISABLE = 2; 85 private static final int MESSAGE_REGISTER_ADAPTER = 20; 86 private static final int MESSAGE_UNREGISTER_ADAPTER = 21; 87 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; 88 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; 89 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; 90 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; 91 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42; 92 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60; 93 private static final int MESSAGE_TIMEOUT_BIND =100; 94 private static final int MESSAGE_TIMEOUT_UNBIND =101; 95 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200; 96 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201; 97 private static final int MESSAGE_USER_SWITCHED = 300; 98 private static final int MESSAGE_ADD_PROXY_DELAYED = 400; 99 private static final int MESSAGE_BIND_PROFILE_SERVICE = 401; 100 private static final int MAX_SAVE_RETRIES=3; 101 private static final int MAX_ERROR_RESTART_RETRIES=6; 102 103 // Bluetooth persisted setting is off 104 private static final int BLUETOOTH_OFF=0; 105 // Bluetooth persisted setting is on 106 // and Airplane mode won't affect Bluetooth state at start up 107 private static final int BLUETOOTH_ON_BLUETOOTH=1; 108 // Bluetooth persisted setting is on 109 // but Airplane mode will affect Bluetooth state at start up 110 // and Airplane mode will have higher priority. 111 private static final int BLUETOOTH_ON_AIRPLANE=2; 112 113 private static final int SERVICE_IBLUETOOTH = 1; 114 private static final int SERVICE_IBLUETOOTHGATT = 2; 115 116 private final Context mContext; 117 118 // Locks are not provided for mName and mAddress. 119 // They are accessed in handler or broadcast receiver, same thread context. 120 private String mAddress; 121 private String mName; 122 private final ContentResolver mContentResolver; 123 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; 124 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks; 125 private IBluetooth mBluetooth; 126 private IBluetoothGatt mBluetoothGatt; 127 private boolean mBinding; 128 private boolean mUnbinding; 129 // used inside handler thread 130 private boolean mQuietEnable = false; 131 // configuarion from external IBinder call which is used to 132 // synchronize with broadcast receiver. 133 private boolean mQuietEnableExternal; 134 // configuarion from external IBinder call which is used to 135 // synchronize with broadcast receiver. 136 private boolean mEnableExternal; 137 // used inside handler thread 138 private boolean mEnable; 139 private int mState; 140 private final BluetoothHandler mHandler; 141 private int mErrorRecoveryRetryCounter; 142 private final int mSystemUiUid; 143 144 // Save a ProfileServiceConnections object for each of the bound 145 // bluetooth profile services 146 private final Map <Integer, ProfileServiceConnections> mProfileServices = 147 new HashMap <Integer, ProfileServiceConnections>(); 148 149 private void registerForAirplaneMode(IntentFilter filter) { 150 final ContentResolver resolver = mContext.getContentResolver(); 151 final String airplaneModeRadios = Settings.Global.getString(resolver, 152 Settings.Global.AIRPLANE_MODE_RADIOS); 153 final String toggleableRadios = Settings.Global.getString(resolver, 154 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 155 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true : 156 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH); 157 if (mIsAirplaneSensitive) { 158 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 159 } 160 } 161 162 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { 163 @Override 164 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { 165 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState); 166 mHandler.sendMessage(msg); 167 } 168 }; 169 170 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 171 @Override 172 public void onReceive(Context context, Intent intent) { 173 String action = intent.getAction(); 174 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { 175 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); 176 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName); 177 if (newName != null) { 178 storeNameAndAddress(newName, null); 179 } 180 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { 181 synchronized(mReceiver) { 182 if (isBluetoothPersistedStateOn()) { 183 if (isAirplaneModeOn()) { 184 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE); 185 } else { 186 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); 187 } 188 } 189 if (isAirplaneModeOn()) { 190 // disable without persisting the setting 191 sendDisableMsg(); 192 } else if (mEnableExternal) { 193 // enable without persisting the setting 194 sendEnableMsg(mQuietEnableExternal); 195 } 196 } 197 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { 198 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED, 199 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); 200 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { 201 synchronized(mReceiver) { 202 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) { 203 //Enable 204 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth."); 205 sendEnableMsg(mQuietEnableExternal); 206 } 207 } 208 209 if (!isNameAndAddressSet()) { 210 //Sync the Bluetooth name and address from the Bluetooth Adapter 211 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address..."); 212 getNameAndAddress(); 213 } 214 } 215 } 216 }; 217 218 BluetoothManagerService(Context context) { 219 mHandler = new BluetoothHandler(IoThread.get().getLooper()); 220 221 mContext = context; 222 mBluetooth = null; 223 mBinding = false; 224 mUnbinding = false; 225 mEnable = false; 226 mState = BluetoothAdapter.STATE_OFF; 227 mQuietEnableExternal = false; 228 mEnableExternal = false; 229 mAddress = null; 230 mName = null; 231 mErrorRecoveryRetryCounter = 0; 232 mContentResolver = context.getContentResolver(); 233 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); 234 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>(); 235 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); 236 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 237 filter.addAction(Intent.ACTION_USER_SWITCHED); 238 registerForAirplaneMode(filter); 239 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 240 mContext.registerReceiver(mReceiver, filter); 241 loadStoredNameAndAddress(); 242 if (isBluetoothPersistedStateOn()) { 243 mEnableExternal = true; 244 } 245 246 int sysUiUid = -1; 247 try { 248 sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui", 249 UserHandle.USER_OWNER); 250 } catch (PackageManager.NameNotFoundException e) { 251 Log.wtf(TAG, "Unable to resolve SystemUI's UID.", e); 252 } 253 mSystemUiUid = sysUiUid; 254 } 255 256 /** 257 * Returns true if airplane mode is currently on 258 */ 259 private final boolean isAirplaneModeOn() { 260 return Settings.Global.getInt(mContext.getContentResolver(), 261 Settings.Global.AIRPLANE_MODE_ON, 0) == 1; 262 } 263 264 /** 265 * Returns true if the Bluetooth saved state is "on" 266 */ 267 private final boolean isBluetoothPersistedStateOn() { 268 return Settings.Global.getInt(mContentResolver, 269 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF; 270 } 271 272 /** 273 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH 274 */ 275 private final boolean isBluetoothPersistedStateOnBluetooth() { 276 return Settings.Global.getInt(mContentResolver, 277 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH; 278 } 279 280 /** 281 * Save the Bluetooth on/off state 282 * 283 */ 284 private void persistBluetoothSetting(int value) { 285 Settings.Global.putInt(mContext.getContentResolver(), 286 Settings.Global.BLUETOOTH_ON, 287 value); 288 } 289 290 /** 291 * Returns true if the Bluetooth Adapter's name and address is 292 * locally cached 293 * @return 294 */ 295 private boolean isNameAndAddressSet() { 296 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0; 297 } 298 299 /** 300 * Retrieve the Bluetooth Adapter's name and address and save it in 301 * in the local cache 302 */ 303 private void loadStoredNameAndAddress() { 304 if (DBG) Log.d(TAG, "Loading stored name and address"); 305 if (mContext.getResources().getBoolean 306 (com.android.internal.R.bool.config_bluetooth_address_validation) && 307 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) { 308 // if the valid flag is not set, don't load the address and name 309 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored"); 310 return; 311 } 312 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME); 313 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS); 314 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress); 315 } 316 317 /** 318 * Save the Bluetooth name and address in the persistent store. 319 * Only non-null values will be saved. 320 * @param name 321 * @param address 322 */ 323 private void storeNameAndAddress(String name, String address) { 324 if (name != null) { 325 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name); 326 mName = name; 327 if (DBG) Log.d(TAG,"Stored Bluetooth name: " + 328 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME)); 329 } 330 331 if (address != null) { 332 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address); 333 mAddress=address; 334 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " + 335 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS)); 336 } 337 338 if ((name != null) && (address != null)) { 339 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1); 340 } 341 } 342 343 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){ 344 if (callback == null) { 345 Log.w(TAG, "Callback is null in registerAdapter"); 346 return null; 347 } 348 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); 349 msg.obj = callback; 350 mHandler.sendMessage(msg); 351 synchronized(mConnection) { 352 return mBluetooth; 353 } 354 } 355 356 public void unregisterAdapter(IBluetoothManagerCallback callback) { 357 if (callback == null) { 358 Log.w(TAG, "Callback is null in unregisterAdapter"); 359 return; 360 } 361 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 362 "Need BLUETOOTH permission"); 363 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); 364 msg.obj = callback; 365 mHandler.sendMessage(msg); 366 } 367 368 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { 369 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 370 "Need BLUETOOTH permission"); 371 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); 372 msg.obj = callback; 373 mHandler.sendMessage(msg); 374 } 375 376 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { 377 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 378 "Need BLUETOOTH permission"); 379 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); 380 msg.obj = callback; 381 mHandler.sendMessage(msg); 382 } 383 384 public boolean isEnabled() { 385 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 386 (!checkIfCallerIsForegroundUser())) { 387 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user"); 388 return false; 389 } 390 391 synchronized(mConnection) { 392 try { 393 return (mBluetooth != null && mBluetooth.isEnabled()); 394 } catch (RemoteException e) { 395 Log.e(TAG, "isEnabled()", e); 396 } 397 } 398 return false; 399 } 400 401 public void getNameAndAddress() { 402 if (DBG) { 403 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth + 404 " mBinding = " + mBinding); 405 } 406 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 407 mHandler.sendMessage(msg); 408 } 409 public boolean enableNoAutoConnect() 410 { 411 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 412 "Need BLUETOOTH ADMIN permission"); 413 414 if (DBG) { 415 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + 416 " mBinding = " + mBinding); 417 } 418 int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); 419 420 if (callingAppId != Process.NFC_UID) { 421 throw new SecurityException("no permission to enable Bluetooth quietly"); 422 } 423 424 synchronized(mReceiver) { 425 mQuietEnableExternal = true; 426 mEnableExternal = true; 427 sendEnableMsg(true); 428 } 429 return true; 430 431 } 432 public boolean enable() { 433 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 434 (!checkIfCallerIsForegroundUser())) { 435 Log.w(TAG,"enable(): not allowed for non-active and non system user"); 436 return false; 437 } 438 439 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 440 "Need BLUETOOTH ADMIN permission"); 441 if (DBG) { 442 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth + 443 " mBinding = " + mBinding); 444 } 445 446 synchronized(mReceiver) { 447 mQuietEnableExternal = false; 448 mEnableExternal = true; 449 // waive WRITE_SECURE_SETTINGS permission check 450 long callingIdentity = Binder.clearCallingIdentity(); 451 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); 452 Binder.restoreCallingIdentity(callingIdentity); 453 sendEnableMsg(false); 454 } 455 return true; 456 } 457 458 public boolean disable(boolean persist) { 459 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 460 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); 461 462 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 463 (!checkIfCallerIsForegroundUser())) { 464 Log.w(TAG,"disable(): not allowed for non-active and non system user"); 465 return false; 466 } 467 468 if (DBG) { 469 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth + 470 " mBinding = " + mBinding); 471 } 472 473 synchronized(mReceiver) { 474 if (persist) { 475 // waive WRITE_SECURE_SETTINGS permission check 476 long callingIdentity = Binder.clearCallingIdentity(); 477 persistBluetoothSetting(BLUETOOTH_OFF); 478 Binder.restoreCallingIdentity(callingIdentity); 479 } 480 mEnableExternal = false; 481 sendDisableMsg(); 482 } 483 return true; 484 } 485 486 public void unbindAndFinish() { 487 if (DBG) { 488 Log.d(TAG,"unbindAndFinish(): " + mBluetooth + 489 " mBinding = " + mBinding); 490 } 491 492 synchronized (mConnection) { 493 if (mUnbinding) return; 494 mUnbinding = true; 495 if (mBluetooth != null) { 496 if (!mConnection.isGetNameAddressOnly()) { 497 //Unregister callback object 498 try { 499 mBluetooth.unregisterCallback(mBluetoothCallback); 500 } catch (RemoteException re) { 501 Log.e(TAG, "Unable to unregister BluetoothCallback",re); 502 } 503 } 504 if (DBG) Log.d(TAG, "Sending unbind request."); 505 mBluetooth = null; 506 //Unbind 507 mContext.unbindService(mConnection); 508 mUnbinding = false; 509 mBinding = false; 510 } else { 511 mUnbinding=false; 512 } 513 } 514 } 515 516 public IBluetoothGatt getBluetoothGatt() { 517 // sync protection 518 return mBluetoothGatt; 519 } 520 521 @Override 522 public boolean bindBluetoothProfileService(int bluetoothProfile, 523 IBluetoothProfileServiceConnection proxy) { 524 if (!mEnable) { 525 if (DBG) { 526 Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile + 527 ", while Bluetooth was disabled"); 528 } 529 return false; 530 } 531 synchronized (mProfileServices) { 532 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); 533 if (psc == null) { 534 if (DBG) { 535 Log.d(TAG, "Creating new ProfileServiceConnections object for" 536 + " profile: " + bluetoothProfile); 537 } 538 539 if (bluetoothProfile != BluetoothProfile.HEADSET) return false; 540 541 Intent intent = new Intent(IBluetoothHeadset.class.getName()); 542 psc = new ProfileServiceConnections(intent); 543 if (!psc.bindService()) return false; 544 545 mProfileServices.put(new Integer(bluetoothProfile), psc); 546 } 547 } 548 549 // Introducing a delay to give the client app time to prepare 550 Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED); 551 addProxyMsg.arg1 = bluetoothProfile; 552 addProxyMsg.obj = proxy; 553 mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS); 554 return true; 555 } 556 557 @Override 558 public void unbindBluetoothProfileService(int bluetoothProfile, 559 IBluetoothProfileServiceConnection proxy) { 560 synchronized (mProfileServices) { 561 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); 562 if (psc == null) { 563 return; 564 } 565 psc.removeProxy(proxy); 566 } 567 } 568 569 private void unbindAllBluetoothProfileServices() { 570 synchronized (mProfileServices) { 571 for (Integer i : mProfileServices.keySet()) { 572 ProfileServiceConnections psc = mProfileServices.get(i); 573 try { 574 mContext.unbindService(psc); 575 } catch (IllegalArgumentException e) { 576 Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e); 577 } 578 psc.removeAllProxies(); 579 } 580 mProfileServices.clear(); 581 } 582 } 583 584 /** 585 * This class manages the clients connected to a given ProfileService 586 * and maintains the connection with that service. 587 */ 588 final private class ProfileServiceConnections implements ServiceConnection, 589 IBinder.DeathRecipient { 590 final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies = 591 new RemoteCallbackList <IBluetoothProfileServiceConnection>(); 592 IBinder mService; 593 ComponentName mClassName; 594 Intent mIntent; 595 596 ProfileServiceConnections(Intent intent) { 597 mService = null; 598 mClassName = null; 599 mIntent = intent; 600 } 601 602 private boolean bindService() { 603 if (mIntent != null && mService == null && 604 doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) { 605 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); 606 msg.obj = this; 607 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); 608 return true; 609 } 610 Log.w(TAG, "Unable to bind with intent: " + mIntent); 611 return false; 612 } 613 614 private void addProxy(IBluetoothProfileServiceConnection proxy) { 615 mProxies.register(proxy); 616 if (mService != null) { 617 try{ 618 proxy.onServiceConnected(mClassName, mService); 619 } catch (RemoteException e) { 620 Log.e(TAG, "Unable to connect to proxy", e); 621 } 622 } else { 623 if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) { 624 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); 625 msg.obj = this; 626 mHandler.sendMessage(msg); 627 } 628 } 629 } 630 631 private void removeProxy(IBluetoothProfileServiceConnection proxy) { 632 if (proxy != null) { 633 if (mProxies.unregister(proxy)) { 634 try { 635 proxy.onServiceDisconnected(mClassName); 636 } catch (RemoteException e) { 637 Log.e(TAG, "Unable to disconnect proxy", e); 638 } 639 } 640 } else { 641 Log.w(TAG, "Trying to remove a null proxy"); 642 } 643 } 644 645 private void removeAllProxies() { 646 onServiceDisconnected(mClassName); 647 mProxies.kill(); 648 } 649 650 @Override 651 public void onServiceConnected(ComponentName className, IBinder service) { 652 // remove timeout message 653 mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this); 654 mService = service; 655 mClassName = className; 656 try { 657 mService.linkToDeath(this, 0); 658 } catch (RemoteException e) { 659 Log.e(TAG, "Unable to linkToDeath", e); 660 } 661 int n = mProxies.beginBroadcast(); 662 for (int i = 0; i < n; i++) { 663 try { 664 mProxies.getBroadcastItem(i).onServiceConnected(className, service); 665 } catch (RemoteException e) { 666 Log.e(TAG, "Unable to connect to proxy", e); 667 } 668 } 669 mProxies.finishBroadcast(); 670 } 671 672 @Override 673 public void onServiceDisconnected(ComponentName className) { 674 if (mService == null) { 675 return; 676 } 677 mService.unlinkToDeath(this, 0); 678 mService = null; 679 mClassName = null; 680 int n = mProxies.beginBroadcast(); 681 for (int i = 0; i < n; i++) { 682 try { 683 mProxies.getBroadcastItem(i).onServiceDisconnected(className); 684 } catch (RemoteException e) { 685 Log.e(TAG, "Unable to disconnect from proxy", e); 686 } 687 } 688 mProxies.finishBroadcast(); 689 } 690 691 @Override 692 public void binderDied() { 693 if (DBG) { 694 Log.w(TAG, "Profile service for profile: " + mClassName 695 + " died."); 696 } 697 onServiceDisconnected(mClassName); 698 // Trigger rebind 699 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); 700 msg.obj = this; 701 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); 702 } 703 } 704 705 private void sendBluetoothStateCallback(boolean isUp) { 706 int n = mStateChangeCallbacks.beginBroadcast(); 707 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); 708 for (int i=0; i <n;i++) { 709 try { 710 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); 711 } catch (RemoteException e) { 712 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e); 713 } 714 } 715 mStateChangeCallbacks.finishBroadcast(); 716 } 717 718 /** 719 * Inform BluetoothAdapter instances that Adapter service is up 720 */ 721 private void sendBluetoothServiceUpCallback() { 722 if (!mConnection.isGetNameAddressOnly()) { 723 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks"); 724 int n = mCallbacks.beginBroadcast(); 725 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); 726 for (int i=0; i <n;i++) { 727 try { 728 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); 729 } catch (RemoteException e) { 730 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); 731 } 732 } 733 mCallbacks.finishBroadcast(); 734 } 735 } 736 /** 737 * Inform BluetoothAdapter instances that Adapter service is down 738 */ 739 private void sendBluetoothServiceDownCallback() { 740 if (!mConnection.isGetNameAddressOnly()) { 741 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks"); 742 int n = mCallbacks.beginBroadcast(); 743 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers."); 744 for (int i=0; i <n;i++) { 745 try { 746 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); 747 } catch (RemoteException e) { 748 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); 749 } 750 } 751 mCallbacks.finishBroadcast(); 752 } 753 } 754 public String getAddress() { 755 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 756 "Need BLUETOOTH permission"); 757 758 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 759 (!checkIfCallerIsForegroundUser())) { 760 Log.w(TAG,"getAddress(): not allowed for non-active and non system user"); 761 return null; 762 } 763 764 synchronized(mConnection) { 765 if (mBluetooth != null) { 766 try { 767 return mBluetooth.getAddress(); 768 } catch (RemoteException e) { 769 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e); 770 } 771 } 772 } 773 // mAddress is accessed from outside. 774 // It is alright without a lock. Here, bluetooth is off, no other thread is 775 // changing mAddress 776 return mAddress; 777 } 778 779 public String getName() { 780 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 781 "Need BLUETOOTH permission"); 782 783 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 784 (!checkIfCallerIsForegroundUser())) { 785 Log.w(TAG,"getName(): not allowed for non-active and non system user"); 786 return null; 787 } 788 789 synchronized(mConnection) { 790 if (mBluetooth != null) { 791 try { 792 return mBluetooth.getName(); 793 } catch (RemoteException e) { 794 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e); 795 } 796 } 797 } 798 // mName is accessed from outside. 799 // It alright without a lock. Here, bluetooth is off, no other thread is 800 // changing mName 801 return mName; 802 } 803 804 private class BluetoothServiceConnection implements ServiceConnection { 805 806 private boolean mGetNameAddressOnly; 807 808 public void setGetNameAddressOnly(boolean getOnly) { 809 mGetNameAddressOnly = getOnly; 810 } 811 812 public boolean isGetNameAddressOnly() { 813 return mGetNameAddressOnly; 814 } 815 816 public void onServiceConnected(ComponentName className, IBinder service) { 817 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName()); 818 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); 819 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) { 820 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) { 821 msg.arg1 = SERVICE_IBLUETOOTH; 822 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) { 823 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) { 824 msg.arg1 = SERVICE_IBLUETOOTHGATT; 825 } else { 826 Log.e(TAG, "Unknown service connected: " + className.getClassName()); 827 return; 828 } 829 msg.obj = service; 830 mHandler.sendMessage(msg); 831 } 832 833 public void onServiceDisconnected(ComponentName className) { 834 // Called if we unexpected disconnected. 835 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " + 836 className.getClassName()); 837 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); 838 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) { 839 msg.arg1 = SERVICE_IBLUETOOTH; 840 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) { 841 msg.arg1 = SERVICE_IBLUETOOTHGATT; 842 } else { 843 Log.e(TAG, "Unknown service disconnected: " + className.getClassName()); 844 return; 845 } 846 mHandler.sendMessage(msg); 847 } 848 } 849 850 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); 851 852 private class BluetoothHandler extends Handler { 853 public BluetoothHandler(Looper looper) { 854 super(looper); 855 } 856 857 @Override 858 public void handleMessage(Message msg) { 859 if (DBG) Log.d (TAG, "Message: " + msg.what); 860 switch (msg.what) { 861 case MESSAGE_GET_NAME_AND_ADDRESS: { 862 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS"); 863 synchronized(mConnection) { 864 //Start bind request 865 if ((mBluetooth == null) && (!mBinding)) { 866 if (DBG) Log.d(TAG, "Binding to service to get name and address"); 867 mConnection.setGetNameAddressOnly(true); 868 //Start bind timeout and bind 869 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 870 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 871 Intent i = new Intent(IBluetooth.class.getName()); 872 if (!doBind(i, mConnection, 873 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, 874 UserHandle.CURRENT)) { 875 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 876 } else { 877 mBinding = true; 878 } 879 } 880 else { 881 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 882 saveMsg.arg1 = 0; 883 if (mBluetooth != null) { 884 mHandler.sendMessage(saveMsg); 885 } else { 886 // if enable is also called to bind the service 887 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED 888 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS); 889 } 890 } 891 } 892 break; 893 } 894 case MESSAGE_SAVE_NAME_AND_ADDRESS: { 895 boolean unbind = false; 896 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS"); 897 synchronized(mConnection) { 898 if (!mEnable && mBluetooth != null) { 899 try { 900 mBluetooth.enable(); 901 } catch (RemoteException e) { 902 Log.e(TAG,"Unable to call enable()",e); 903 } 904 } 905 } 906 if (mBluetooth != null) waitForOnOff(true, false); 907 synchronized(mConnection) { 908 if (mBluetooth != null) { 909 String name = null; 910 String address = null; 911 try { 912 name = mBluetooth.getName(); 913 address = mBluetooth.getAddress(); 914 } catch (RemoteException re) { 915 Log.e(TAG,"",re); 916 } 917 918 if (name != null && address != null) { 919 storeNameAndAddress(name,address); 920 if (mConnection.isGetNameAddressOnly()) { 921 unbind = true; 922 } 923 } else { 924 if (msg.arg1 < MAX_SAVE_RETRIES) { 925 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 926 retryMsg.arg1= 1+msg.arg1; 927 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1); 928 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS); 929 } else { 930 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded"); 931 if (mConnection.isGetNameAddressOnly()) { 932 unbind = true; 933 } 934 } 935 } 936 if (!mEnable) { 937 try { 938 mBluetooth.disable(); 939 } catch (RemoteException e) { 940 Log.e(TAG,"Unable to call disable()",e); 941 } 942 } 943 } else { 944 // rebind service by Request GET NAME AND ADDRESS 945 // if service is unbinded by disable or 946 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received 947 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 948 mHandler.sendMessage(getMsg); 949 } 950 } 951 if (!mEnable && mBluetooth != null) waitForOnOff(false, true); 952 if (unbind) { 953 unbindAndFinish(); 954 } 955 break; 956 } 957 case MESSAGE_ENABLE: 958 if (DBG) { 959 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth); 960 } 961 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 962 mEnable = true; 963 handleEnable(msg.arg1 == 1); 964 break; 965 966 case MESSAGE_DISABLE: 967 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 968 if (mEnable && mBluetooth != null) { 969 waitForOnOff(true, false); 970 mEnable = false; 971 handleDisable(); 972 waitForOnOff(false, false); 973 } else { 974 mEnable = false; 975 handleDisable(); 976 } 977 break; 978 979 case MESSAGE_REGISTER_ADAPTER: 980 { 981 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 982 boolean added = mCallbacks.register(callback); 983 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added ); 984 } 985 break; 986 case MESSAGE_UNREGISTER_ADAPTER: 987 { 988 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 989 boolean removed = mCallbacks.unregister(callback); 990 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed); 991 break; 992 } 993 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: 994 { 995 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 996 if (callback != null) { 997 mStateChangeCallbacks.register(callback); 998 } 999 break; 1000 } 1001 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: 1002 { 1003 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 1004 if (callback != null) { 1005 mStateChangeCallbacks.unregister(callback); 1006 } 1007 break; 1008 } 1009 case MESSAGE_ADD_PROXY_DELAYED: 1010 { 1011 ProfileServiceConnections psc = mProfileServices.get( 1012 new Integer(msg.arg1)); 1013 if (psc == null) { 1014 break; 1015 } 1016 IBluetoothProfileServiceConnection proxy = 1017 (IBluetoothProfileServiceConnection) msg.obj; 1018 psc.addProxy(proxy); 1019 break; 1020 } 1021 case MESSAGE_BIND_PROFILE_SERVICE: 1022 { 1023 ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj; 1024 removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj); 1025 if (psc == null) { 1026 break; 1027 } 1028 psc.bindService(); 1029 break; 1030 } 1031 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: 1032 { 1033 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); 1034 1035 IBinder service = (IBinder) msg.obj; 1036 synchronized(mConnection) { 1037 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { 1038 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service); 1039 break; 1040 } // else must be SERVICE_IBLUETOOTH 1041 1042 //Remove timeout 1043 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 1044 1045 mBinding = false; 1046 mBluetooth = IBluetooth.Stub.asInterface(service); 1047 1048 try { 1049 boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver, 1050 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1); 1051 if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) { 1052 Log.e(TAG,"IBluetooth.configHciSnoopLog return false"); 1053 } 1054 } catch (RemoteException e) { 1055 Log.e(TAG,"Unable to call configHciSnoopLog", e); 1056 } 1057 1058 if (mConnection.isGetNameAddressOnly()) { 1059 //Request GET NAME AND ADDRESS 1060 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 1061 mHandler.sendMessage(getMsg); 1062 if (!mEnable) return; 1063 } 1064 1065 mConnection.setGetNameAddressOnly(false); 1066 //Register callback object 1067 try { 1068 mBluetooth.registerCallback(mBluetoothCallback); 1069 } catch (RemoteException re) { 1070 Log.e(TAG, "Unable to register BluetoothCallback",re); 1071 } 1072 //Inform BluetoothAdapter instances that service is up 1073 sendBluetoothServiceUpCallback(); 1074 1075 //Do enable request 1076 try { 1077 if (mQuietEnable == false) { 1078 if(!mBluetooth.enable()) { 1079 Log.e(TAG,"IBluetooth.enable() returned false"); 1080 } 1081 } 1082 else 1083 { 1084 if(!mBluetooth.enableNoAutoConnect()) { 1085 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 1086 } 1087 } 1088 } catch (RemoteException e) { 1089 Log.e(TAG,"Unable to call enable()",e); 1090 } 1091 } 1092 1093 if (!mEnable) { 1094 waitForOnOff(true, false); 1095 handleDisable(); 1096 waitForOnOff(false, false); 1097 } 1098 break; 1099 } 1100 case MESSAGE_TIMEOUT_BIND: { 1101 Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); 1102 synchronized(mConnection) { 1103 mBinding = false; 1104 } 1105 break; 1106 } 1107 case MESSAGE_BLUETOOTH_STATE_CHANGE: 1108 { 1109 int prevState = msg.arg1; 1110 int newState = msg.arg2; 1111 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); 1112 mState = newState; 1113 bluetoothStateChangeHandler(prevState, newState); 1114 // handle error state transition case from TURNING_ON to OFF 1115 // unbind and rebind bluetooth service and enable bluetooth 1116 if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && 1117 (newState == BluetoothAdapter.STATE_OFF) && 1118 (mBluetooth != null) && mEnable) { 1119 recoverBluetoothServiceFromError(); 1120 } 1121 if (newState == BluetoothAdapter.STATE_ON) { 1122 // bluetooth is working, reset the counter 1123 if (mErrorRecoveryRetryCounter != 0) { 1124 Log.w(TAG, "bluetooth is recovered from error"); 1125 mErrorRecoveryRetryCounter = 0; 1126 } 1127 } 1128 break; 1129 } 1130 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: 1131 { 1132 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1); 1133 synchronized(mConnection) { 1134 if (msg.arg1 == SERVICE_IBLUETOOTH) { 1135 // if service is unbinded already, do nothing and return 1136 if (mBluetooth == null) break; 1137 mBluetooth = null; 1138 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { 1139 mBluetoothGatt = null; 1140 break; 1141 } else { 1142 Log.e(TAG, "Bad msg.arg1: " + msg.arg1); 1143 break; 1144 } 1145 } 1146 1147 if (mEnable) { 1148 mEnable = false; 1149 // Send a Bluetooth Restart message 1150 Message restartMsg = mHandler.obtainMessage( 1151 MESSAGE_RESTART_BLUETOOTH_SERVICE); 1152 mHandler.sendMessageDelayed(restartMsg, 1153 SERVICE_RESTART_TIME_MS); 1154 } 1155 1156 if (!mConnection.isGetNameAddressOnly()) { 1157 sendBluetoothServiceDownCallback(); 1158 1159 // Send BT state broadcast to update 1160 // the BT icon correctly 1161 if ((mState == BluetoothAdapter.STATE_TURNING_ON) || 1162 (mState == BluetoothAdapter.STATE_ON)) { 1163 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 1164 BluetoothAdapter.STATE_TURNING_OFF); 1165 mState = BluetoothAdapter.STATE_TURNING_OFF; 1166 } 1167 if (mState == BluetoothAdapter.STATE_TURNING_OFF) { 1168 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, 1169 BluetoothAdapter.STATE_OFF); 1170 } 1171 1172 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1173 mState = BluetoothAdapter.STATE_OFF; 1174 } 1175 break; 1176 } 1177 case MESSAGE_RESTART_BLUETOOTH_SERVICE: 1178 { 1179 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:" 1180 +" Restart IBluetooth service"); 1181 /* Enable without persisting the setting as 1182 it doesnt change when IBluetooth 1183 service restarts */ 1184 mEnable = true; 1185 handleEnable(mQuietEnable); 1186 break; 1187 } 1188 1189 case MESSAGE_TIMEOUT_UNBIND: 1190 { 1191 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); 1192 synchronized(mConnection) { 1193 mUnbinding = false; 1194 } 1195 break; 1196 } 1197 1198 case MESSAGE_USER_SWITCHED: 1199 { 1200 if (DBG) { 1201 Log.d(TAG, "MESSAGE_USER_SWITCHED"); 1202 } 1203 mHandler.removeMessages(MESSAGE_USER_SWITCHED); 1204 /* disable and enable BT when detect a user switch */ 1205 if (mEnable && mBluetooth != null) { 1206 synchronized (mConnection) { 1207 if (mBluetooth != null) { 1208 //Unregister callback object 1209 try { 1210 mBluetooth.unregisterCallback(mBluetoothCallback); 1211 } catch (RemoteException re) { 1212 Log.e(TAG, "Unable to unregister",re); 1213 } 1214 } 1215 } 1216 1217 if (mState == BluetoothAdapter.STATE_TURNING_OFF) { 1218 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE 1219 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF); 1220 mState = BluetoothAdapter.STATE_OFF; 1221 } 1222 if (mState == BluetoothAdapter.STATE_OFF) { 1223 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON); 1224 mState = BluetoothAdapter.STATE_TURNING_ON; 1225 } 1226 1227 waitForOnOff(true, false); 1228 1229 if (mState == BluetoothAdapter.STATE_TURNING_ON) { 1230 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); 1231 } 1232 1233 unbindAllBluetoothProfileServices(); 1234 // disable 1235 handleDisable(); 1236 // Pbap service need receive STATE_TURNING_OFF intent to close 1237 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 1238 BluetoothAdapter.STATE_TURNING_OFF); 1239 1240 waitForOnOff(false, true); 1241 1242 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, 1243 BluetoothAdapter.STATE_OFF); 1244 sendBluetoothServiceDownCallback(); 1245 synchronized (mConnection) { 1246 if (mBluetooth != null) { 1247 mBluetooth = null; 1248 //Unbind 1249 mContext.unbindService(mConnection); 1250 } 1251 } 1252 SystemClock.sleep(100); 1253 1254 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1255 mState = BluetoothAdapter.STATE_OFF; 1256 // enable 1257 handleEnable(mQuietEnable); 1258 } else if (mBinding || mBluetooth != null) { 1259 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); 1260 userMsg.arg2 = 1 + msg.arg2; 1261 // if user is switched when service is being binding 1262 // delay sending MESSAGE_USER_SWITCHED 1263 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS); 1264 if (DBG) { 1265 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2); 1266 } 1267 } 1268 break; 1269 } 1270 } 1271 } 1272 } 1273 1274 private void handleEnable(boolean quietMode) { 1275 mQuietEnable = quietMode; 1276 1277 synchronized(mConnection) { 1278 if ((mBluetooth == null) && (!mBinding)) { 1279 //Start bind timeout and bind 1280 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 1281 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 1282 mConnection.setGetNameAddressOnly(false); 1283 Intent i = new Intent(IBluetooth.class.getName()); 1284 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, 1285 UserHandle.CURRENT)) { 1286 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 1287 } else { 1288 mBinding = true; 1289 } 1290 } else if (mBluetooth != null) { 1291 if (mConnection.isGetNameAddressOnly()) { 1292 // if GetNameAddressOnly is set, we can clear this flag, 1293 // so the service won't be unbind 1294 // after name and address are saved 1295 mConnection.setGetNameAddressOnly(false); 1296 //Register callback object 1297 try { 1298 mBluetooth.registerCallback(mBluetoothCallback); 1299 } catch (RemoteException re) { 1300 Log.e(TAG, "Unable to register BluetoothCallback",re); 1301 } 1302 //Inform BluetoothAdapter instances that service is up 1303 sendBluetoothServiceUpCallback(); 1304 } 1305 1306 //Enable bluetooth 1307 try { 1308 if (!mQuietEnable) { 1309 if(!mBluetooth.enable()) { 1310 Log.e(TAG,"IBluetooth.enable() returned false"); 1311 } 1312 } 1313 else { 1314 if(!mBluetooth.enableNoAutoConnect()) { 1315 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 1316 } 1317 } 1318 } catch (RemoteException e) { 1319 Log.e(TAG,"Unable to call enable()",e); 1320 } 1321 } 1322 } 1323 } 1324 1325 boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) { 1326 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); 1327 intent.setComponent(comp); 1328 if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) { 1329 Log.e(TAG, "Fail to bind to: " + intent); 1330 return false; 1331 } 1332 return true; 1333 } 1334 1335 private void handleDisable() { 1336 synchronized(mConnection) { 1337 // don't need to disable if GetNameAddressOnly is set, 1338 // service will be unbinded after Name and Address are saved 1339 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) { 1340 if (DBG) Log.d(TAG,"Sending off request."); 1341 1342 try { 1343 if(!mBluetooth.disable()) { 1344 Log.e(TAG,"IBluetooth.disable() returned false"); 1345 } 1346 } catch (RemoteException e) { 1347 Log.e(TAG,"Unable to call disable()",e); 1348 } 1349 } 1350 } 1351 } 1352 1353 private boolean checkIfCallerIsForegroundUser() { 1354 int foregroundUser; 1355 int callingUser = UserHandle.getCallingUserId(); 1356 int callingUid = Binder.getCallingUid(); 1357 long callingIdentity = Binder.clearCallingIdentity(); 1358 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 1359 UserInfo ui = um.getProfileParent(callingUser); 1360 int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL; 1361 int callingAppId = UserHandle.getAppId(callingUid); 1362 boolean valid = false; 1363 try { 1364 foregroundUser = ActivityManager.getCurrentUser(); 1365 valid = (callingUser == foregroundUser) || 1366 parentUser == foregroundUser || 1367 callingAppId == Process.NFC_UID || 1368 callingAppId == mSystemUiUid; 1369 if (DBG) { 1370 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid 1371 + " callingUser=" + callingUser 1372 + " parentUser=" + parentUser 1373 + " foregroundUser=" + foregroundUser); 1374 } 1375 } finally { 1376 Binder.restoreCallingIdentity(callingIdentity); 1377 } 1378 return valid; 1379 } 1380 1381 private void bluetoothStateChangeHandler(int prevState, int newState) { 1382 if (prevState != newState) { 1383 //Notify all proxy objects first of adapter state change 1384 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { 1385 boolean isUp = (newState==BluetoothAdapter.STATE_ON); 1386 sendBluetoothStateCallback(isUp); 1387 1388 if (isUp) { 1389 // connect to GattService 1390 if (mContext.getPackageManager().hasSystemFeature( 1391 PackageManager.FEATURE_BLUETOOTH_LE)) { 1392 Intent i = new Intent(IBluetoothGatt.class.getName()); 1393 doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, 1394 UserHandle.CURRENT); 1395 } 1396 } else { 1397 //If Bluetooth is off, send service down event to proxy objects, and unbind 1398 if (!isUp && canUnbindBluetoothService()) { 1399 unbindAllBluetoothProfileServices(); 1400 sendBluetoothServiceDownCallback(); 1401 unbindAndFinish(); 1402 } 1403 } 1404 } 1405 1406 //Send broadcast message to everyone else 1407 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 1408 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 1409 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 1410 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1411 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); 1412 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 1413 BLUETOOTH_PERM); 1414 } 1415 } 1416 1417 /** 1418 * if on is true, wait for state become ON 1419 * if off is true, wait for state become OFF 1420 * if both on and off are false, wait for state not ON 1421 */ 1422 private boolean waitForOnOff(boolean on, boolean off) { 1423 int i = 0; 1424 while (i < 10) { 1425 synchronized(mConnection) { 1426 try { 1427 if (mBluetooth == null) break; 1428 if (on) { 1429 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true; 1430 } else if (off) { 1431 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true; 1432 } else { 1433 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true; 1434 } 1435 } catch (RemoteException e) { 1436 Log.e(TAG, "getState()", e); 1437 break; 1438 } 1439 } 1440 if (on || off) { 1441 SystemClock.sleep(300); 1442 } else { 1443 SystemClock.sleep(50); 1444 } 1445 i++; 1446 } 1447 Log.e(TAG,"waitForOnOff time out"); 1448 return false; 1449 } 1450 1451 private void sendDisableMsg() { 1452 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE)); 1453 } 1454 1455 private void sendEnableMsg(boolean quietMode) { 1456 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, 1457 quietMode ? 1 : 0, 0)); 1458 } 1459 1460 private boolean canUnbindBluetoothService() { 1461 synchronized(mConnection) { 1462 //Only unbind with mEnable flag not set 1463 //For race condition: disable and enable back-to-back 1464 //Avoid unbind right after enable due to callback from disable 1465 //Only unbind with Bluetooth at OFF state 1466 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message 1467 try { 1468 if (mEnable || (mBluetooth == null)) return false; 1469 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false; 1470 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF); 1471 } catch (RemoteException e) { 1472 Log.e(TAG, "getState()", e); 1473 } 1474 } 1475 return false; 1476 } 1477 1478 private void recoverBluetoothServiceFromError() { 1479 Log.e(TAG,"recoverBluetoothServiceFromError"); 1480 synchronized (mConnection) { 1481 if (mBluetooth != null) { 1482 //Unregister callback object 1483 try { 1484 mBluetooth.unregisterCallback(mBluetoothCallback); 1485 } catch (RemoteException re) { 1486 Log.e(TAG, "Unable to unregister",re); 1487 } 1488 } 1489 } 1490 1491 SystemClock.sleep(500); 1492 1493 // disable 1494 handleDisable(); 1495 1496 waitForOnOff(false, true); 1497 1498 sendBluetoothServiceDownCallback(); 1499 synchronized (mConnection) { 1500 if (mBluetooth != null) { 1501 mBluetooth = null; 1502 //Unbind 1503 mContext.unbindService(mConnection); 1504 } 1505 } 1506 1507 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1508 mState = BluetoothAdapter.STATE_OFF; 1509 1510 mEnable = false; 1511 1512 if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) { 1513 // Send a Bluetooth Restart message to reenable bluetooth 1514 Message restartMsg = mHandler.obtainMessage( 1515 MESSAGE_RESTART_BLUETOOTH_SERVICE); 1516 mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS); 1517 } else { 1518 // todo: notify user to power down and power up phone to make bluetooth work. 1519 } 1520 } 1521 1522 @Override 1523 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 1524 writer.println("enabled: " + mEnable); 1525 writer.println("state: " + mState); 1526 writer.println("address: " + mAddress); 1527 writer.println("name: " + mName); 1528 if (mBluetooth == null) { 1529 writer.println("Bluetooth Service not connected"); 1530 } else { 1531 try { 1532 writer.println(mBluetooth.dump()); 1533 } catch (RemoteException re) { 1534 writer.println("RemoteException while calling Bluetooth Service"); 1535 } 1536 } 1537 } 1538} 1539