AdapterService.java revision 0708fe3087b690439dd9745b2cf1a96f29f570b0
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5/** 6 * @hide 7 */ 8 9package com.android.bluetooth.btservice; 10 11import android.app.Application; 12import android.app.Service; 13import android.bluetooth.BluetoothAdapter; 14import android.bluetooth.BluetoothDevice; 15import android.bluetooth.BluetoothProfile; 16import android.bluetooth.IBluetooth; 17import android.content.BroadcastReceiver; 18import android.content.ContentResolver; 19import android.content.Context; 20import android.content.Intent; 21import android.content.IntentFilter; 22import android.os.Binder; 23import android.os.IBinder; 24import android.os.Message; 25import android.os.ParcelFileDescriptor; 26import android.os.ParcelUuid; 27import android.os.RemoteException; 28import android.os.ServiceManager; 29import android.provider.Settings; 30import android.util.Log; 31import android.util.Pair; 32 33import com.android.bluetooth.a2dp.A2dpService; 34import com.android.bluetooth.hid.HidService; 35import com.android.bluetooth.hfp.HeadsetService; 36import com.android.bluetooth.hdp.HealthService; 37import com.android.bluetooth.Utils; 38import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 39 40import java.io.FileDescriptor; 41import java.io.IOException; 42import java.util.HashMap; 43import java.util.Set; 44 45public class AdapterService extends Application { 46 private static final String TAG = "BluetoothAdapterService"; 47 private static final boolean DBG = true; 48 49 static final String BLUETOOTH_ADMIN_PERM = 50 android.Manifest.permission.BLUETOOTH_ADMIN; 51 static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 52 53 private AdapterProperties mAdapterProperties; 54 private int mAdapterState; 55 private Context mContext; 56 private boolean mIsAirplaneSensitive; 57 private boolean mIsAirplaneToggleable; 58 private static AdapterService sAdapterService; 59 60 private BluetoothAdapter mAdapter; 61 private AdapterState mAdapterStateMachine; 62 private BondStateMachine mBondStateMachine; 63 private JniCallbacks mJniCallbacks; 64 65 66 private RemoteDevices mRemoteDevices; 67 static { 68 System.loadLibrary("bluetooth_jni"); 69 classInitNative(); 70 } 71 72 @Override 73 public void onCreate() { 74 super.onCreate(); 75 ServiceManager.addService(Context.BLUETOOTH_SERVICE, mBinder); 76 77 mAdapter = BluetoothAdapter.getDefaultAdapter(); 78 mContext = this; 79 sAdapterService = this; 80 81 IntentFilter filter = new IntentFilter(); 82 filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 83 registerForAirplaneMode(filter); 84 registerReceiver(mReceiver, filter); 85 86 mRemoteDevices = RemoteDevices.getInstance(this, mContext); 87 mAdapterProperties = AdapterProperties.getInstance(this, mContext); 88 mAdapterStateMachine = new AdapterState(this, mContext, mAdapterProperties); 89 mBondStateMachine = new BondStateMachine(this, mContext, mAdapterProperties); 90 mJniCallbacks = JniCallbacks.getInstance(mRemoteDevices, mAdapterProperties, 91 mAdapterStateMachine, mBondStateMachine); 92 93 94 initNative(); 95 mAdapterStateMachine.start(); 96 mBondStateMachine.start(); 97 //TODO(BT): Remove this when BT is no longer a persitent process. 98 int bluetoothOn = Settings.Secure.getInt(mContext.getContentResolver(), 99 Settings.Secure.BLUETOOTH_ON, 0); 100 if (!isAirplaneModeOn() && bluetoothOn != 0) mAdapter.enable(); 101 startService(new Intent(this, HeadsetService.class)); 102 startService(new Intent(this, A2dpService.class)); 103 startService(new Intent(this, HidService.class)); 104 startService(new Intent(this, HealthService.class)); 105 } 106 107 @Override 108 protected void finalize() throws Throwable { 109 mContext.unregisterReceiver(mReceiver); 110 try { 111 cleanupNative(); 112 } finally { 113 super.finalize(); 114 } 115 } 116 117 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 118 @Override 119 public void onReceive(Context context, Intent intent) { 120 if (intent == null) return; 121 122 String action = intent.getAction(); 123 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 124 ContentResolver resolver = context.getContentResolver(); 125 // Query the airplane mode from Settings.System just to make sure that 126 // some random app is not sending this intent and disabling bluetooth 127 if (isAirplaneModeOn()) { 128 mAdapterStateMachine.sendMessage(AdapterState.AIRPLANE_MODE_ON); 129 } else { 130 mAdapterStateMachine.sendMessage(AdapterState.AIRPLANE_MODE_OFF); 131 } 132 } 133 } 134 }; 135 136 137 138 private void registerForAirplaneMode(IntentFilter filter) { 139 final ContentResolver resolver = mContext.getContentResolver(); 140 final String airplaneModeRadios = Settings.System.getString(resolver, 141 Settings.System.AIRPLANE_MODE_RADIOS); 142 final String toggleableRadios = Settings.System.getString(resolver, 143 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 144 145 mIsAirplaneSensitive = airplaneModeRadios == null ? true : 146 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 147 mIsAirplaneToggleable = toggleableRadios == null ? false : 148 toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH); 149 150 if (mIsAirplaneSensitive) { 151 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 152 } 153 } 154 155 /* Returns true if airplane mode is currently on */ 156 private final boolean isAirplaneModeOn() { 157 return Settings.System.getInt(mContext.getContentResolver(), 158 Settings.System.AIRPLANE_MODE_ON, 0) == 1; 159 } 160 161 /** 162 * Handlers for incoming service calls 163 */ 164 private final IBluetooth.Stub mBinder = new IBluetooth.Stub() { 165 public boolean isEnabled() { 166 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 167 return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON; 168 } 169 170 public int getState() { 171 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 172 return mAdapterProperties.getState(); 173 } 174 175 public boolean enable() { 176 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 177 "Need BLUETOOTH ADMIN permission"); 178 // Persist the setting 179 Message m = 180 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON); 181 m.arg1 = 1; 182 mAdapterStateMachine.sendMessage(m); 183 return true; 184 } 185 186 public boolean disable(boolean persist) { 187 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 188 "Need BLUETOOTH ADMIN permission"); 189 int val = (persist ? 1 : 0); 190 Message m = 191 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF); 192 m.arg1 = val; 193 mAdapterStateMachine.sendMessage(m); 194 return true; 195 } 196 197 public String getAddress() { 198 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 199 String addrString = null; 200 byte[] address = mAdapterProperties.getAddress(); 201 return Utils.getAddressStringFromByte(address); 202 } 203 204 public ParcelUuid[] getUuids() { 205 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 206 return mAdapterProperties.getUuids(); 207 } 208 209 public String getName() { 210 enforceCallingOrSelfPermission(BLUETOOTH_PERM, 211 "Need BLUETOOTH permission"); 212 return mAdapterProperties.getName(); 213 } 214 215 public boolean setName(String name) { 216 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 217 "Need BLUETOOTH ADMIN permission"); 218 return mAdapterProperties.setName(name); 219 } 220 221 public int getScanMode() { 222 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 223 return mAdapterProperties.getScanMode(); 224 } 225 226 public boolean setScanMode(int mode, int duration) { 227 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 228 setDiscoverableTimeout(duration); 229 230 int newMode = convertScanModeToHal(mode); 231 return mAdapterProperties.setScanMode(newMode); 232 } 233 234 public int getDiscoverableTimeout() { 235 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 236 return mAdapterProperties.getDiscoverableTimeout(); 237 } 238 239 public boolean setDiscoverableTimeout(int timeout) { 240 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 241 return mAdapterProperties.setDiscoverableTimeout(timeout); 242 } 243 244 public boolean startDiscovery() { 245 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 246 "Need BLUETOOTH ADMIN permission"); 247 return startDiscoveryNative(); 248 } 249 250 public boolean cancelDiscovery() { 251 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 252 "Need BLUETOOTH ADMIN permission"); 253 return cancelDiscoveryNative(); 254 } 255 256 public boolean isDiscovering() { 257 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 258 return mAdapterProperties.isDiscovering(); 259 } 260 261 public BluetoothDevice[] getBondedDevices() { 262 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 263 debugLog("Get Bonded Devices being called"); 264 return mAdapterProperties.getBondedDevices(); 265 } 266 267 public int getAdapterConnectionState() { 268 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 269 return mAdapterProperties.getConnectionState(); 270 } 271 272 public int getProfileConnectionState(int profile) { 273 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 274 return mAdapterProperties.getProfileConnectionState(profile); 275 } 276 277 public boolean createBond(BluetoothDevice device) { 278 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 279 "Need BLUETOOTH ADMIN permission"); 280 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 281 if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) { 282 return false; 283 } 284 285 Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND); 286 msg.obj = device; 287 mBondStateMachine.sendMessage(msg); 288 return true; 289 } 290 291 public boolean cancelBondProcess(BluetoothDevice device) { 292 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 293 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 294 return cancelBondNative(addr); 295 } 296 297 public boolean removeBond(BluetoothDevice device) { 298 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 299 "Need BLUETOOTH ADMIN permission"); 300 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 301 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) { 302 return false; 303 } 304 Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND); 305 msg.obj = device; 306 mBondStateMachine.sendMessage(msg); 307 return true; 308 } 309 310 public int getBondState(BluetoothDevice device) { 311 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 312 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 313 if (deviceProp == null) { 314 return BluetoothDevice.BOND_NONE; 315 } 316 return deviceProp.getBondState(); 317 } 318 319 public String getRemoteName(BluetoothDevice device) { 320 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 321 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 322 if (deviceProp == null) return null; 323 return deviceProp.getName(); 324 } 325 326 public String getRemoteAlias(BluetoothDevice device) { 327 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 328 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 329 if (deviceProp == null) return null; 330 return deviceProp.getAlias(); 331 } 332 333 public boolean setRemoteAlias(BluetoothDevice device, String name) { 334 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 335 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 336 if (deviceProp == null) return false; 337 deviceProp.setAlias(name); 338 return true; 339 } 340 341 public int getRemoteClass(BluetoothDevice device) { 342 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 343 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 344 if (deviceProp == null) return 0; 345 346 return deviceProp.getBluetoothClass(); 347 } 348 349 public ParcelUuid[] getRemoteUuids(BluetoothDevice device) { 350 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 351 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 352 if (deviceProp == null) return null; 353 return deviceProp.getUuids(); 354 } 355 356 public boolean fetchRemoteUuids(BluetoothDevice device) { 357 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 358 mRemoteDevices.performSdp(device); 359 return true; 360 } 361 362 public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) { 363 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 364 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 365 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 366 return false; 367 } 368 369 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 370 return pinReplyNative(addr, accept, len, pinCode); 371 } 372 373 public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) { 374 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 375 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 376 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 377 return false; 378 } 379 380 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 381 return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept, 382 Utils.byteArrayToInt(passkey)); 383 } 384 385 public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) { 386 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 387 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 388 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 389 return false; 390 } 391 392 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 393 return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION, 394 accept, 0); 395 } 396 397 public void sendConnectionStateChange(BluetoothDevice 398 device, int profile, int state, int prevState) { 399 // TODO(BT) permission check? 400 // Since this is a binder call check if Bluetooth is on still 401 if (getState() == BluetoothAdapter.STATE_OFF) return; 402 403 mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState); 404 405 } 406 407 public ParcelFileDescriptor connectSocket(BluetoothDevice device, int type, 408 ParcelUuid uuid, int port, int flag) { 409 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 410 int fd = connectSocketNative(Utils.getBytesFromAddress(device.getAddress()), 411 type, Utils.uuidToByteArray(uuid), port, flag); 412 if (fd < 0) { 413 errorLog("Failed to connect socket"); 414 return null; 415 } 416 return ParcelFileDescriptor.adoptFd(fd); 417 } 418 419 public ParcelFileDescriptor createSocketChannel(int type, String serviceName, 420 ParcelUuid uuid, int port, int flag) { 421 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 422 int fd = createSocketChannelNative(type, serviceName, 423 Utils.uuidToByteArray(uuid), port, flag); 424 if (fd < 0) { 425 errorLog("Failed to create socket channel"); 426 return null; 427 } 428 return ParcelFileDescriptor.adoptFd(fd); 429 } 430 }; 431 432 private int convertScanModeToHal(int mode) { 433 switch (mode) { 434 case BluetoothAdapter.SCAN_MODE_NONE: 435 return AbstractionLayer.BT_SCAN_MODE_NONE; 436 case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 437 return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE; 438 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 439 return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE; 440 } 441 errorLog("Incorrect scan mode in convertScanModeToHal"); 442 return -1; 443 } 444 445 int convertScanModeFromHal(int mode) { 446 switch (mode) { 447 case AbstractionLayer.BT_SCAN_MODE_NONE: 448 return BluetoothAdapter.SCAN_MODE_NONE; 449 case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE: 450 return BluetoothAdapter.SCAN_MODE_CONNECTABLE; 451 case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE: 452 return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; 453 } 454 errorLog("Incorrect scan mode in convertScanModeFromHal"); 455 return -1; 456 } 457 458 private static void debugLog(String msg) { 459 Log.d(TAG, msg); 460 } 461 462 private static void errorLog(String msg) { 463 Log.e(TAG, msg); 464 } 465 466 void persistBluetoothSetting(boolean setOn) { 467 long origCallerIdentityToken = Binder.clearCallingIdentity(); 468 Settings.Secure.putInt(mContext.getContentResolver(), 469 Settings.Secure.BLUETOOTH_ON, 470 setOn ? 1 : 0); 471 Binder.restoreCallingIdentity(origCallerIdentityToken); 472 } 473 474 boolean getBluetoothPersistedSetting() { 475 ContentResolver contentResolver = mContext.getContentResolver(); 476 return (Settings.Secure.getInt(contentResolver, 477 Settings.Secure.BLUETOOTH_ON, 0) > 0); 478 } 479 480 private native static void classInitNative(); 481 private native boolean initNative(); 482 private native void cleanupNative(); 483 /*package*/ native boolean enableNative(); 484 /*package*/ native boolean disableNative(); 485 /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val); 486 /*package*/ native boolean getAdapterPropertiesNative(); 487 /*package*/ native boolean getAdapterPropertyNative(int type); 488 /*package*/ native boolean setAdapterPropertyNative(int type); 489 /*package*/ native boolean 490 setDevicePropertyNative(byte[] address, int type, byte[] val); 491 /*package*/ native boolean getDevicePropertyNative(byte[] address, int type); 492 493 /*package*/ native boolean createBondNative(byte[] address); 494 /*package*/ native boolean removeBondNative(byte[] address); 495 /*package*/ native boolean cancelBondNative(byte[] address); 496 497 private native boolean startDiscoveryNative(); 498 private native boolean cancelDiscoveryNative(); 499 500 private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin); 501 private native boolean sspReplyNative(byte[] address, int type, boolean 502 accept, int passkey); 503 // TODO(BT) move this to ../btsock dir 504 private native int connectSocketNative(byte[] address, int type, 505 byte[] uuid, int port, int flag); 506 private native int createSocketChannelNative(int type, String serviceName, 507 byte[] uuid, int port, int flag); 508} 509