BluetoothManagerService.java revision e8b98925d08f720c4d22b626d0650de536840a9a
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 Intent intent = null; 539 if (bluetoothProfile == BluetoothProfile.HEADSET) { 540 intent = new Intent(IBluetoothHeadset.class.getName()); 541 } else { 542 return false; 543 } 544 psc = new ProfileServiceConnections(intent); 545 mProfileServices.put(new Integer(bluetoothProfile), psc); 546 psc.bindService(); 547 } 548 } 549 550 // Introducing a delay to give the client app time to prepare 551 Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED); 552 addProxyMsg.arg1 = bluetoothProfile; 553 addProxyMsg.obj = proxy; 554 mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS); 555 return true; 556 } 557 558 @Override 559 public void unbindBluetoothProfileService(int bluetoothProfile, 560 IBluetoothProfileServiceConnection proxy) { 561 synchronized (mProfileServices) { 562 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); 563 if (psc == null) { 564 return; 565 } 566 psc.removeProxy(proxy); 567 } 568 } 569 570 private void unbindAllBluetoothProfileServices() { 571 synchronized (mProfileServices) { 572 for (Integer i : mProfileServices.keySet()) { 573 ProfileServiceConnections psc = mProfileServices.get(i); 574 mContext.unbindService(psc); 575 psc.removeAllProxies(); 576 } 577 mProfileServices.clear(); 578 } 579 } 580 581 /** 582 * This class manages the clients connected to a given ProfileService 583 * and maintains the connection with that service. 584 */ 585 final private class ProfileServiceConnections implements ServiceConnection, 586 IBinder.DeathRecipient { 587 final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies = 588 new RemoteCallbackList <IBluetoothProfileServiceConnection>(); 589 IBinder mService; 590 ComponentName mClassName; 591 Intent mIntent; 592 593 ProfileServiceConnections(Intent intent) { 594 mService = null; 595 mClassName = null; 596 mIntent = intent; 597 } 598 599 private void bindService() { 600 if (mIntent != null && mService == null) { 601 if (!doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) { 602 Log.w(TAG, "Unable to bind with intent: " + mIntent 603 + ". Triggering retry."); 604 } 605 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); 606 msg.obj = this; 607 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); 608 } 609 } 610 611 private void addProxy(IBluetoothProfileServiceConnection proxy) { 612 mProxies.register(proxy); 613 if (mService != null) { 614 try{ 615 proxy.onServiceConnected(mClassName, mService); 616 } catch (RemoteException e) { 617 Log.e(TAG, "Unable to connect to proxy", e); 618 } 619 } else { 620 if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) { 621 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); 622 msg.obj = this; 623 mHandler.sendMessage(msg); 624 } 625 } 626 } 627 628 private void removeProxy(IBluetoothProfileServiceConnection proxy) { 629 if (proxy != null) { 630 if (mProxies.unregister(proxy)) { 631 try { 632 proxy.onServiceDisconnected(mClassName); 633 } catch (RemoteException e) { 634 Log.e(TAG, "Unable to disconnect proxy", e); 635 } 636 } 637 } else { 638 Log.w(TAG, "Trying to remove a null proxy"); 639 } 640 } 641 642 private void removeAllProxies() { 643 onServiceDisconnected(mClassName); 644 mProxies.kill(); 645 } 646 647 @Override 648 public void onServiceConnected(ComponentName className, IBinder service) { 649 // remove timeout message 650 mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this); 651 mService = service; 652 mClassName = className; 653 try { 654 mService.linkToDeath(this, 0); 655 } catch (RemoteException e) { 656 Log.e(TAG, "Unable to linkToDeath", e); 657 } 658 int n = mProxies.beginBroadcast(); 659 for (int i = 0; i < n; i++) { 660 try { 661 mProxies.getBroadcastItem(i).onServiceConnected(className, service); 662 } catch (RemoteException e) { 663 Log.e(TAG, "Unable to connect to proxy", e); 664 } 665 } 666 mProxies.finishBroadcast(); 667 } 668 669 @Override 670 public void onServiceDisconnected(ComponentName className) { 671 if (mService == null) { 672 return; 673 } 674 mService.unlinkToDeath(this, 0); 675 mService = null; 676 mClassName = null; 677 int n = mProxies.beginBroadcast(); 678 for (int i = 0; i < n; i++) { 679 try { 680 mProxies.getBroadcastItem(i).onServiceDisconnected(className); 681 } catch (RemoteException e) { 682 Log.e(TAG, "Unable to disconnect from proxy", e); 683 } 684 } 685 mProxies.finishBroadcast(); 686 } 687 688 @Override 689 public void binderDied() { 690 if (DBG) { 691 Log.w(TAG, "Profile service for profile: " + mClassName 692 + " died."); 693 } 694 onServiceDisconnected(mClassName); 695 // Trigger rebind 696 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); 697 msg.obj = this; 698 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); 699 } 700 } 701 702 private void sendBluetoothStateCallback(boolean isUp) { 703 int n = mStateChangeCallbacks.beginBroadcast(); 704 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); 705 for (int i=0; i <n;i++) { 706 try { 707 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); 708 } catch (RemoteException e) { 709 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e); 710 } 711 } 712 mStateChangeCallbacks.finishBroadcast(); 713 } 714 715 /** 716 * Inform BluetoothAdapter instances that Adapter service is up 717 */ 718 private void sendBluetoothServiceUpCallback() { 719 if (!mConnection.isGetNameAddressOnly()) { 720 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks"); 721 int n = mCallbacks.beginBroadcast(); 722 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); 723 for (int i=0; i <n;i++) { 724 try { 725 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); 726 } catch (RemoteException e) { 727 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); 728 } 729 } 730 mCallbacks.finishBroadcast(); 731 } 732 } 733 /** 734 * Inform BluetoothAdapter instances that Adapter service is down 735 */ 736 private void sendBluetoothServiceDownCallback() { 737 if (!mConnection.isGetNameAddressOnly()) { 738 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks"); 739 int n = mCallbacks.beginBroadcast(); 740 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers."); 741 for (int i=0; i <n;i++) { 742 try { 743 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); 744 } catch (RemoteException e) { 745 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); 746 } 747 } 748 mCallbacks.finishBroadcast(); 749 } 750 } 751 public String getAddress() { 752 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 753 "Need BLUETOOTH permission"); 754 755 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 756 (!checkIfCallerIsForegroundUser())) { 757 Log.w(TAG,"getAddress(): not allowed for non-active and non system user"); 758 return null; 759 } 760 761 synchronized(mConnection) { 762 if (mBluetooth != null) { 763 try { 764 return mBluetooth.getAddress(); 765 } catch (RemoteException e) { 766 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e); 767 } 768 } 769 } 770 // mAddress is accessed from outside. 771 // It is alright without a lock. Here, bluetooth is off, no other thread is 772 // changing mAddress 773 return mAddress; 774 } 775 776 public String getName() { 777 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 778 "Need BLUETOOTH permission"); 779 780 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 781 (!checkIfCallerIsForegroundUser())) { 782 Log.w(TAG,"getName(): not allowed for non-active and non system user"); 783 return null; 784 } 785 786 synchronized(mConnection) { 787 if (mBluetooth != null) { 788 try { 789 return mBluetooth.getName(); 790 } catch (RemoteException e) { 791 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e); 792 } 793 } 794 } 795 // mName is accessed from outside. 796 // It alright without a lock. Here, bluetooth is off, no other thread is 797 // changing mName 798 return mName; 799 } 800 801 private class BluetoothServiceConnection implements ServiceConnection { 802 803 private boolean mGetNameAddressOnly; 804 805 public void setGetNameAddressOnly(boolean getOnly) { 806 mGetNameAddressOnly = getOnly; 807 } 808 809 public boolean isGetNameAddressOnly() { 810 return mGetNameAddressOnly; 811 } 812 813 public void onServiceConnected(ComponentName className, IBinder service) { 814 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName()); 815 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); 816 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) { 817 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) { 818 msg.arg1 = SERVICE_IBLUETOOTH; 819 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) { 820 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) { 821 msg.arg1 = SERVICE_IBLUETOOTHGATT; 822 } else { 823 Log.e(TAG, "Unknown service connected: " + className.getClassName()); 824 return; 825 } 826 msg.obj = service; 827 mHandler.sendMessage(msg); 828 } 829 830 public void onServiceDisconnected(ComponentName className) { 831 // Called if we unexpected disconnected. 832 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " + 833 className.getClassName()); 834 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); 835 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) { 836 msg.arg1 = SERVICE_IBLUETOOTH; 837 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) { 838 msg.arg1 = SERVICE_IBLUETOOTHGATT; 839 } else { 840 Log.e(TAG, "Unknown service disconnected: " + className.getClassName()); 841 return; 842 } 843 mHandler.sendMessage(msg); 844 } 845 } 846 847 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); 848 849 private class BluetoothHandler extends Handler { 850 public BluetoothHandler(Looper looper) { 851 super(looper); 852 } 853 854 @Override 855 public void handleMessage(Message msg) { 856 if (DBG) Log.d (TAG, "Message: " + msg.what); 857 switch (msg.what) { 858 case MESSAGE_GET_NAME_AND_ADDRESS: { 859 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS"); 860 synchronized(mConnection) { 861 //Start bind request 862 if ((mBluetooth == null) && (!mBinding)) { 863 if (DBG) Log.d(TAG, "Binding to service to get name and address"); 864 mConnection.setGetNameAddressOnly(true); 865 //Start bind timeout and bind 866 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 867 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 868 Intent i = new Intent(IBluetooth.class.getName()); 869 if (!doBind(i, mConnection, 870 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, 871 UserHandle.CURRENT)) { 872 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 873 } else { 874 mBinding = true; 875 } 876 } 877 else { 878 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 879 saveMsg.arg1 = 0; 880 if (mBluetooth != null) { 881 mHandler.sendMessage(saveMsg); 882 } else { 883 // if enable is also called to bind the service 884 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED 885 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS); 886 } 887 } 888 } 889 break; 890 } 891 case MESSAGE_SAVE_NAME_AND_ADDRESS: { 892 boolean unbind = false; 893 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS"); 894 synchronized(mConnection) { 895 if (!mEnable && mBluetooth != null) { 896 try { 897 mBluetooth.enable(); 898 } catch (RemoteException e) { 899 Log.e(TAG,"Unable to call enable()",e); 900 } 901 } 902 } 903 if (mBluetooth != null) waitForOnOff(true, false); 904 synchronized(mConnection) { 905 if (mBluetooth != null) { 906 String name = null; 907 String address = null; 908 try { 909 name = mBluetooth.getName(); 910 address = mBluetooth.getAddress(); 911 } catch (RemoteException re) { 912 Log.e(TAG,"",re); 913 } 914 915 if (name != null && address != null) { 916 storeNameAndAddress(name,address); 917 if (mConnection.isGetNameAddressOnly()) { 918 unbind = true; 919 } 920 } else { 921 if (msg.arg1 < MAX_SAVE_RETRIES) { 922 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 923 retryMsg.arg1= 1+msg.arg1; 924 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1); 925 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS); 926 } else { 927 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded"); 928 if (mConnection.isGetNameAddressOnly()) { 929 unbind = true; 930 } 931 } 932 } 933 if (!mEnable) { 934 try { 935 mBluetooth.disable(); 936 } catch (RemoteException e) { 937 Log.e(TAG,"Unable to call disable()",e); 938 } 939 } 940 } else { 941 // rebind service by Request GET NAME AND ADDRESS 942 // if service is unbinded by disable or 943 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received 944 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 945 mHandler.sendMessage(getMsg); 946 } 947 } 948 if (!mEnable && mBluetooth != null) waitForOnOff(false, true); 949 if (unbind) { 950 unbindAndFinish(); 951 } 952 break; 953 } 954 case MESSAGE_ENABLE: 955 if (DBG) { 956 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth); 957 } 958 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 959 mEnable = true; 960 handleEnable(msg.arg1 == 1); 961 break; 962 963 case MESSAGE_DISABLE: 964 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 965 if (mEnable && mBluetooth != null) { 966 waitForOnOff(true, false); 967 mEnable = false; 968 handleDisable(); 969 waitForOnOff(false, false); 970 } else { 971 mEnable = false; 972 handleDisable(); 973 } 974 break; 975 976 case MESSAGE_REGISTER_ADAPTER: 977 { 978 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 979 boolean added = mCallbacks.register(callback); 980 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added ); 981 } 982 break; 983 case MESSAGE_UNREGISTER_ADAPTER: 984 { 985 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 986 boolean removed = mCallbacks.unregister(callback); 987 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed); 988 break; 989 } 990 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: 991 { 992 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 993 if (callback != null) { 994 mStateChangeCallbacks.register(callback); 995 } 996 break; 997 } 998 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: 999 { 1000 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 1001 if (callback != null) { 1002 mStateChangeCallbacks.unregister(callback); 1003 } 1004 break; 1005 } 1006 case MESSAGE_ADD_PROXY_DELAYED: 1007 { 1008 ProfileServiceConnections psc = mProfileServices.get( 1009 new Integer(msg.arg1)); 1010 if (psc == null) { 1011 break; 1012 } 1013 IBluetoothProfileServiceConnection proxy = 1014 (IBluetoothProfileServiceConnection) msg.obj; 1015 psc.addProxy(proxy); 1016 break; 1017 } 1018 case MESSAGE_BIND_PROFILE_SERVICE: 1019 { 1020 ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj; 1021 removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj); 1022 if (psc == null) { 1023 break; 1024 } 1025 psc.bindService(); 1026 break; 1027 } 1028 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: 1029 { 1030 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); 1031 1032 IBinder service = (IBinder) msg.obj; 1033 synchronized(mConnection) { 1034 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { 1035 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service); 1036 break; 1037 } // else must be SERVICE_IBLUETOOTH 1038 1039 //Remove timeout 1040 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 1041 1042 mBinding = false; 1043 mBluetooth = IBluetooth.Stub.asInterface(service); 1044 1045 try { 1046 boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver, 1047 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1); 1048 if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) { 1049 Log.e(TAG,"IBluetooth.configHciSnoopLog return false"); 1050 } 1051 } catch (RemoteException e) { 1052 Log.e(TAG,"Unable to call configHciSnoopLog", e); 1053 } 1054 1055 if (mConnection.isGetNameAddressOnly()) { 1056 //Request GET NAME AND ADDRESS 1057 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 1058 mHandler.sendMessage(getMsg); 1059 if (!mEnable) return; 1060 } 1061 1062 mConnection.setGetNameAddressOnly(false); 1063 //Register callback object 1064 try { 1065 mBluetooth.registerCallback(mBluetoothCallback); 1066 } catch (RemoteException re) { 1067 Log.e(TAG, "Unable to register BluetoothCallback",re); 1068 } 1069 //Inform BluetoothAdapter instances that service is up 1070 sendBluetoothServiceUpCallback(); 1071 1072 //Do enable request 1073 try { 1074 if (mQuietEnable == false) { 1075 if(!mBluetooth.enable()) { 1076 Log.e(TAG,"IBluetooth.enable() returned false"); 1077 } 1078 } 1079 else 1080 { 1081 if(!mBluetooth.enableNoAutoConnect()) { 1082 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 1083 } 1084 } 1085 } catch (RemoteException e) { 1086 Log.e(TAG,"Unable to call enable()",e); 1087 } 1088 } 1089 1090 if (!mEnable) { 1091 waitForOnOff(true, false); 1092 handleDisable(); 1093 waitForOnOff(false, false); 1094 } 1095 break; 1096 } 1097 case MESSAGE_TIMEOUT_BIND: { 1098 Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); 1099 synchronized(mConnection) { 1100 mBinding = false; 1101 } 1102 break; 1103 } 1104 case MESSAGE_BLUETOOTH_STATE_CHANGE: 1105 { 1106 int prevState = msg.arg1; 1107 int newState = msg.arg2; 1108 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); 1109 mState = newState; 1110 bluetoothStateChangeHandler(prevState, newState); 1111 // handle error state transition case from TURNING_ON to OFF 1112 // unbind and rebind bluetooth service and enable bluetooth 1113 if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && 1114 (newState == BluetoothAdapter.STATE_OFF) && 1115 (mBluetooth != null) && mEnable) { 1116 recoverBluetoothServiceFromError(); 1117 } 1118 if (newState == BluetoothAdapter.STATE_ON) { 1119 // bluetooth is working, reset the counter 1120 if (mErrorRecoveryRetryCounter != 0) { 1121 Log.w(TAG, "bluetooth is recovered from error"); 1122 mErrorRecoveryRetryCounter = 0; 1123 } 1124 } 1125 break; 1126 } 1127 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: 1128 { 1129 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1); 1130 synchronized(mConnection) { 1131 if (msg.arg1 == SERVICE_IBLUETOOTH) { 1132 // if service is unbinded already, do nothing and return 1133 if (mBluetooth == null) break; 1134 mBluetooth = null; 1135 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { 1136 mBluetoothGatt = null; 1137 break; 1138 } else { 1139 Log.e(TAG, "Bad msg.arg1: " + msg.arg1); 1140 break; 1141 } 1142 } 1143 1144 if (mEnable) { 1145 mEnable = false; 1146 // Send a Bluetooth Restart message 1147 Message restartMsg = mHandler.obtainMessage( 1148 MESSAGE_RESTART_BLUETOOTH_SERVICE); 1149 mHandler.sendMessageDelayed(restartMsg, 1150 SERVICE_RESTART_TIME_MS); 1151 } 1152 1153 if (!mConnection.isGetNameAddressOnly()) { 1154 sendBluetoothServiceDownCallback(); 1155 1156 // Send BT state broadcast to update 1157 // the BT icon correctly 1158 if ((mState == BluetoothAdapter.STATE_TURNING_ON) || 1159 (mState == BluetoothAdapter.STATE_ON)) { 1160 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 1161 BluetoothAdapter.STATE_TURNING_OFF); 1162 mState = BluetoothAdapter.STATE_TURNING_OFF; 1163 } 1164 if (mState == BluetoothAdapter.STATE_TURNING_OFF) { 1165 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, 1166 BluetoothAdapter.STATE_OFF); 1167 } 1168 1169 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1170 mState = BluetoothAdapter.STATE_OFF; 1171 } 1172 break; 1173 } 1174 case MESSAGE_RESTART_BLUETOOTH_SERVICE: 1175 { 1176 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:" 1177 +" Restart IBluetooth service"); 1178 /* Enable without persisting the setting as 1179 it doesnt change when IBluetooth 1180 service restarts */ 1181 mEnable = true; 1182 handleEnable(mQuietEnable); 1183 break; 1184 } 1185 1186 case MESSAGE_TIMEOUT_UNBIND: 1187 { 1188 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); 1189 synchronized(mConnection) { 1190 mUnbinding = false; 1191 } 1192 break; 1193 } 1194 1195 case MESSAGE_USER_SWITCHED: 1196 { 1197 if (DBG) { 1198 Log.d(TAG, "MESSAGE_USER_SWITCHED"); 1199 } 1200 mHandler.removeMessages(MESSAGE_USER_SWITCHED); 1201 /* disable and enable BT when detect a user switch */ 1202 if (mEnable && mBluetooth != null) { 1203 synchronized (mConnection) { 1204 if (mBluetooth != null) { 1205 //Unregister callback object 1206 try { 1207 mBluetooth.unregisterCallback(mBluetoothCallback); 1208 } catch (RemoteException re) { 1209 Log.e(TAG, "Unable to unregister",re); 1210 } 1211 } 1212 } 1213 1214 if (mState == BluetoothAdapter.STATE_TURNING_OFF) { 1215 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE 1216 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF); 1217 mState = BluetoothAdapter.STATE_OFF; 1218 } 1219 if (mState == BluetoothAdapter.STATE_OFF) { 1220 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON); 1221 mState = BluetoothAdapter.STATE_TURNING_ON; 1222 } 1223 1224 waitForOnOff(true, false); 1225 1226 if (mState == BluetoothAdapter.STATE_TURNING_ON) { 1227 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); 1228 } 1229 1230 unbindAllBluetoothProfileServices(); 1231 // disable 1232 handleDisable(); 1233 // Pbap service need receive STATE_TURNING_OFF intent to close 1234 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 1235 BluetoothAdapter.STATE_TURNING_OFF); 1236 1237 waitForOnOff(false, true); 1238 1239 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, 1240 BluetoothAdapter.STATE_OFF); 1241 sendBluetoothServiceDownCallback(); 1242 synchronized (mConnection) { 1243 if (mBluetooth != null) { 1244 mBluetooth = null; 1245 //Unbind 1246 mContext.unbindService(mConnection); 1247 } 1248 } 1249 SystemClock.sleep(100); 1250 1251 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1252 mState = BluetoothAdapter.STATE_OFF; 1253 // enable 1254 handleEnable(mQuietEnable); 1255 } else if (mBinding || mBluetooth != null) { 1256 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); 1257 userMsg.arg2 = 1 + msg.arg2; 1258 // if user is switched when service is being binding 1259 // delay sending MESSAGE_USER_SWITCHED 1260 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS); 1261 if (DBG) { 1262 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2); 1263 } 1264 } 1265 break; 1266 } 1267 } 1268 } 1269 } 1270 1271 private void handleEnable(boolean quietMode) { 1272 mQuietEnable = quietMode; 1273 1274 synchronized(mConnection) { 1275 if ((mBluetooth == null) && (!mBinding)) { 1276 //Start bind timeout and bind 1277 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 1278 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 1279 mConnection.setGetNameAddressOnly(false); 1280 Intent i = new Intent(IBluetooth.class.getName()); 1281 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, 1282 UserHandle.CURRENT)) { 1283 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 1284 } else { 1285 mBinding = true; 1286 } 1287 } else if (mBluetooth != null) { 1288 if (mConnection.isGetNameAddressOnly()) { 1289 // if GetNameAddressOnly is set, we can clear this flag, 1290 // so the service won't be unbind 1291 // after name and address are saved 1292 mConnection.setGetNameAddressOnly(false); 1293 //Register callback object 1294 try { 1295 mBluetooth.registerCallback(mBluetoothCallback); 1296 } catch (RemoteException re) { 1297 Log.e(TAG, "Unable to register BluetoothCallback",re); 1298 } 1299 //Inform BluetoothAdapter instances that service is up 1300 sendBluetoothServiceUpCallback(); 1301 } 1302 1303 //Enable bluetooth 1304 try { 1305 if (!mQuietEnable) { 1306 if(!mBluetooth.enable()) { 1307 Log.e(TAG,"IBluetooth.enable() returned false"); 1308 } 1309 } 1310 else { 1311 if(!mBluetooth.enableNoAutoConnect()) { 1312 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 1313 } 1314 } 1315 } catch (RemoteException e) { 1316 Log.e(TAG,"Unable to call enable()",e); 1317 } 1318 } 1319 } 1320 } 1321 1322 boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) { 1323 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); 1324 intent.setComponent(comp); 1325 if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) { 1326 Log.e(TAG, "Fail to bind to: " + intent); 1327 return false; 1328 } 1329 return true; 1330 } 1331 1332 private void handleDisable() { 1333 synchronized(mConnection) { 1334 // don't need to disable if GetNameAddressOnly is set, 1335 // service will be unbinded after Name and Address are saved 1336 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) { 1337 if (DBG) Log.d(TAG,"Sending off request."); 1338 1339 try { 1340 if(!mBluetooth.disable()) { 1341 Log.e(TAG,"IBluetooth.disable() returned false"); 1342 } 1343 } catch (RemoteException e) { 1344 Log.e(TAG,"Unable to call disable()",e); 1345 } 1346 } 1347 } 1348 } 1349 1350 private boolean checkIfCallerIsForegroundUser() { 1351 int foregroundUser; 1352 int callingUser = UserHandle.getCallingUserId(); 1353 int callingUid = Binder.getCallingUid(); 1354 long callingIdentity = Binder.clearCallingIdentity(); 1355 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 1356 UserInfo ui = um.getProfileParent(callingUser); 1357 int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL; 1358 int callingAppId = UserHandle.getAppId(callingUid); 1359 boolean valid = false; 1360 try { 1361 foregroundUser = ActivityManager.getCurrentUser(); 1362 valid = (callingUser == foregroundUser) || 1363 parentUser == foregroundUser || 1364 callingAppId == Process.NFC_UID || 1365 callingAppId == mSystemUiUid; 1366 if (DBG) { 1367 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid 1368 + " callingUser=" + callingUser 1369 + " parentUser=" + parentUser 1370 + " foregroundUser=" + foregroundUser); 1371 } 1372 } finally { 1373 Binder.restoreCallingIdentity(callingIdentity); 1374 } 1375 return valid; 1376 } 1377 1378 private void bluetoothStateChangeHandler(int prevState, int newState) { 1379 if (prevState != newState) { 1380 //Notify all proxy objects first of adapter state change 1381 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { 1382 boolean isUp = (newState==BluetoothAdapter.STATE_ON); 1383 sendBluetoothStateCallback(isUp); 1384 1385 if (isUp) { 1386 // connect to GattService 1387 if (mContext.getPackageManager().hasSystemFeature( 1388 PackageManager.FEATURE_BLUETOOTH_LE)) { 1389 Intent i = new Intent(IBluetoothGatt.class.getName()); 1390 doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, 1391 UserHandle.CURRENT); 1392 } 1393 } else { 1394 //If Bluetooth is off, send service down event to proxy objects, and unbind 1395 if (!isUp && canUnbindBluetoothService()) { 1396 unbindAllBluetoothProfileServices(); 1397 sendBluetoothServiceDownCallback(); 1398 unbindAndFinish(); 1399 } 1400 } 1401 } 1402 1403 //Send broadcast message to everyone else 1404 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 1405 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 1406 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 1407 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1408 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); 1409 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 1410 BLUETOOTH_PERM); 1411 } 1412 } 1413 1414 /** 1415 * if on is true, wait for state become ON 1416 * if off is true, wait for state become OFF 1417 * if both on and off are false, wait for state not ON 1418 */ 1419 private boolean waitForOnOff(boolean on, boolean off) { 1420 int i = 0; 1421 while (i < 10) { 1422 synchronized(mConnection) { 1423 try { 1424 if (mBluetooth == null) break; 1425 if (on) { 1426 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true; 1427 } else if (off) { 1428 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true; 1429 } else { 1430 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true; 1431 } 1432 } catch (RemoteException e) { 1433 Log.e(TAG, "getState()", e); 1434 break; 1435 } 1436 } 1437 if (on || off) { 1438 SystemClock.sleep(300); 1439 } else { 1440 SystemClock.sleep(50); 1441 } 1442 i++; 1443 } 1444 Log.e(TAG,"waitForOnOff time out"); 1445 return false; 1446 } 1447 1448 private void sendDisableMsg() { 1449 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE)); 1450 } 1451 1452 private void sendEnableMsg(boolean quietMode) { 1453 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, 1454 quietMode ? 1 : 0, 0)); 1455 } 1456 1457 private boolean canUnbindBluetoothService() { 1458 synchronized(mConnection) { 1459 //Only unbind with mEnable flag not set 1460 //For race condition: disable and enable back-to-back 1461 //Avoid unbind right after enable due to callback from disable 1462 //Only unbind with Bluetooth at OFF state 1463 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message 1464 try { 1465 if (mEnable || (mBluetooth == null)) return false; 1466 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false; 1467 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF); 1468 } catch (RemoteException e) { 1469 Log.e(TAG, "getState()", e); 1470 } 1471 } 1472 return false; 1473 } 1474 1475 private void recoverBluetoothServiceFromError() { 1476 Log.e(TAG,"recoverBluetoothServiceFromError"); 1477 synchronized (mConnection) { 1478 if (mBluetooth != null) { 1479 //Unregister callback object 1480 try { 1481 mBluetooth.unregisterCallback(mBluetoothCallback); 1482 } catch (RemoteException re) { 1483 Log.e(TAG, "Unable to unregister",re); 1484 } 1485 } 1486 } 1487 1488 SystemClock.sleep(500); 1489 1490 // disable 1491 handleDisable(); 1492 1493 waitForOnOff(false, true); 1494 1495 sendBluetoothServiceDownCallback(); 1496 synchronized (mConnection) { 1497 if (mBluetooth != null) { 1498 mBluetooth = null; 1499 //Unbind 1500 mContext.unbindService(mConnection); 1501 } 1502 } 1503 1504 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1505 mState = BluetoothAdapter.STATE_OFF; 1506 1507 mEnable = false; 1508 1509 if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) { 1510 // Send a Bluetooth Restart message to reenable bluetooth 1511 Message restartMsg = mHandler.obtainMessage( 1512 MESSAGE_RESTART_BLUETOOTH_SERVICE); 1513 mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS); 1514 } else { 1515 // todo: notify user to power down and power up phone to make bluetooth work. 1516 } 1517 } 1518 1519 @Override 1520 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 1521 writer.println("enabled: " + mEnable); 1522 writer.println("state: " + mState); 1523 writer.println("address: " + mAddress); 1524 writer.println("name: " + mName); 1525 if (mBluetooth == null) { 1526 writer.println("Bluetooth Service not connected"); 1527 } else { 1528 try { 1529 writer.println(mBluetooth.dump()); 1530 } catch (RemoteException re) { 1531 writer.println("RemoteException while calling Bluetooth Service"); 1532 } 1533 } 1534 } 1535} 1536