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