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