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