AdapterService.java revision 74ae04c73312403e89db0f8e9bd9601d403b4783
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.bluetooth.IBluetoothManager;
18import android.bluetooth.IBluetoothManagerCallback;
19import android.content.BroadcastReceiver;
20import android.content.ContentResolver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.os.Binder;
25import android.os.Bundle;
26import android.os.Handler;
27import android.os.IBinder;
28import android.os.Message;
29import android.os.ParcelFileDescriptor;
30import android.os.ParcelUuid;
31import android.os.RemoteException;
32import android.provider.Settings;
33import android.util.Log;
34import android.util.Pair;
35import com.android.bluetooth.a2dp.A2dpService;
36import com.android.bluetooth.hid.HidService;
37import com.android.bluetooth.hfp.HeadsetService;
38import com.android.bluetooth.hdp.HealthService;
39import com.android.bluetooth.pan.PanService;
40import com.android.bluetooth.Utils;
41import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
42import java.io.FileDescriptor;
43import java.io.IOException;
44import java.util.HashMap;
45import java.util.Set;
46import java.util.Map;
47import java.util.Iterator;
48import java.util.Map.Entry;
49import android.content.pm.PackageManager;
50import android.os.ServiceManager;
51
52public class AdapterService extends Service {
53    private static final String TAG = "BluetoothAdapterService";
54    private static final boolean DBG = true;
55    private static final boolean TRACE_REF = true;
56    //For Debugging only
57    private static int sRefCount=0;
58
59    /**
60     * List of profile services to support.Comment out to disable a profile
61     * Profiles started in order of appearance
62     */
63    @SuppressWarnings("rawtypes")
64    private static final Class[] SUPPORTED_PROFILE_SERVICES = {
65        HeadsetService.class,
66        A2dpService.class,
67        HidService.class,
68        HealthService.class,
69        PanService.class
70    };
71
72    public static final String ACTION_LOAD_ADAPTER_PROPERTIES="com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES";
73    public static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
74    public static final String EXTRA_ACTION="action";
75
76    static final String BLUETOOTH_ADMIN_PERM =
77        android.Manifest.permission.BLUETOOTH_ADMIN;
78    static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
79
80    private static final int ADAPTER_SERVICE_TYPE=Service.START_STICKY;
81
82    static {
83        classInitNative();
84    }
85
86    private static AdapterService sAdapterService;
87    public static synchronized AdapterService getAdapterService(){
88        if (sAdapterService != null && !sAdapterService.mCleaningUp) {
89            if (DBG) Log.d(TAG, "getAdapterService(): returning " + sAdapterService);
90            return sAdapterService;
91        }
92        if (DBG)  {
93            if (sAdapterService == null) {
94                Log.d(TAG, "getAdapterService(): service not available");
95            } else if (sAdapterService.mCleaningUp) {
96                Log.d(TAG,"getAdapterService(): service is cleaning up");
97            }
98        }
99        return null;
100    }
101
102    private static synchronized void setAdapterService(AdapterService instance) {
103        if (instance != null && !instance.mCleaningUp) {
104            if (DBG) Log.d(TAG, "setAdapterService(): set to: " + sAdapterService);
105            sAdapterService = instance;
106        } else {
107            if (DBG)  {
108                if (sAdapterService == null) {
109                    Log.d(TAG, "setAdapterService(): service not available");
110                } else if (sAdapterService.mCleaningUp) {
111                    Log.d(TAG,"setAdapterService(): service is cleaning up");
112                }
113            }
114        }
115    }
116
117    private static synchronized void clearAdapterService() {
118        sAdapterService = null;
119    }
120
121    private AdapterProperties mAdapterProperties;
122    private AdapterState mAdapterStateMachine;
123    private BondStateMachine mBondStateMachine;
124    private JniCallbacks mJniCallbacks;
125    private RemoteDevices mRemoteDevices;
126    private boolean mProfilesStarted;
127    private boolean mNativeAvailable;
128    private boolean mCleaningUp;
129    private HashMap<String,Integer> mProfileServicesState = new HashMap<String,Integer>();
130    private int mCurrentRequestId;
131
132    public AdapterService() {
133        super();
134        if (TRACE_REF) {
135            synchronized (AdapterService.class) {
136                sRefCount++;
137                Log.d(TAG, "REFCOUNT: CREATED. INSTANCE_COUNT" + sRefCount);
138            }
139        }
140    }
141
142    public void onProfileConnectionStateChanged(BluetoothDevice device, int profileId, int newState, int prevState) {
143        Message m = mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED);
144        m.obj = device;
145        m.arg1 = profileId;
146        m.arg2 = newState;
147        Bundle b = new Bundle(1);
148        b.putInt("prevState", prevState);
149        m.setData(b);
150        mHandler.sendMessage(m);
151    }
152
153    private void processProfileStateChanged(BluetoothDevice device, int profileId, int newState, int prevState) {
154        IBluetooth.Stub binder = mBinder;
155        if (binder != null) {
156            try {
157                binder.sendConnectionStateChange(device, profileId, newState,prevState);
158            } catch (RemoteException re) {
159                Log.e(TAG, "",re);
160            }
161        }
162    }
163
164    public void onProfileServiceStateChanged(String serviceName, int state) {
165        Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED);
166        m.obj=serviceName;
167        m.arg1 = state;
168        mHandler.sendMessage(m);
169    }
170
171    private void processProfileServiceStateChanged(String serviceName, int state) {
172        boolean doUpdate=false;
173        boolean isTurningOn;
174        boolean isTurningOff;
175
176        synchronized (mProfileServicesState) {
177            Integer prevState = mProfileServicesState.get(serviceName);
178            if (prevState != null && prevState != state) {
179                mProfileServicesState.put(serviceName,state);
180                doUpdate=true;
181            }
182        }
183        if (DBG) Log.d(TAG,"onProfileServiceStateChange: serviceName=" + serviceName + ", state = " + state +", doUpdate = " + doUpdate);
184
185        if (!doUpdate) {
186            return;
187        }
188
189        synchronized (mAdapterStateMachine) {
190            isTurningOff = mAdapterStateMachine.isTurningOff();
191            isTurningOn = mAdapterStateMachine.isTurningOn();
192        }
193
194        if (isTurningOff) {
195            //Process stop or disable pending
196            //Check if all services are stopped if so, do cleanup
197            //if (DBG) Log.d(TAG,"Checking if all profiles are stopped...");
198            synchronized (mProfileServicesState) {
199                Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator();
200                while (i.hasNext()) {
201                    Map.Entry<String,Integer> entry = i.next();
202                    if (BluetoothAdapter.STATE_OFF != entry.getValue()) {
203                        Log.d(TAG, "Profile still running: " + entry.getKey());
204                        return;
205                    }
206                }
207            }
208            if (DBG) Log.d(TAG, "All profile services stopped...");
209            //Send message to state machine
210            mProfilesStarted=false;
211            mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STOPPED));
212        } else if (isTurningOn) {
213            //Process start pending
214            //Check if all services are started if so, update state
215            //if (DBG) Log.d(TAG,"Checking if all profiles are running...");
216            synchronized (mProfileServicesState) {
217                Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator();
218                while (i.hasNext()) {
219                    Map.Entry<String,Integer> entry = i.next();
220                    if (BluetoothAdapter.STATE_ON != entry.getValue()) {
221                        Log.d(TAG, "Profile still not running:" + entry.getKey());
222                        return;
223                    }
224                }
225            }
226            if (DBG) Log.d(TAG, "All profile services started.");
227            mProfilesStarted=true;
228            //Send message to state machine
229            mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED));
230        }
231    }
232
233    @Override
234    public void onCreate() {
235        super.onCreate();
236        if (DBG) debugLog("onCreate");
237        mBinder = new AdapterServiceBinder(this);
238        mAdapterProperties = new AdapterProperties(this);
239        mAdapterStateMachine =  new AdapterState(this, mAdapterProperties);
240        mJniCallbacks =  new JniCallbacks(mAdapterStateMachine, mAdapterProperties);
241        initNative();
242        mNativeAvailable=true;
243        mAdapterStateMachine.start();
244
245        //Load the name and address
246        getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDADDR);
247        getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDNAME);
248
249    }
250
251    @Override
252    public IBinder onBind(Intent intent) {
253        if (DBG) debugLog("onBind");
254        return mBinder;
255    }
256    public boolean onUnbind(Intent intent) {
257        if (DBG) debugLog("onUnbind");
258        return super.onUnbind(intent);
259    }
260
261    public void onDestroy() {
262        debugLog("****onDestroy()********");
263        mHandler.removeMessages(MESSAGE_SHUTDOWN);
264        cleanup();
265    }
266
267    public int onStartCommand(Intent intent ,int flags, int startId) {
268        mCurrentRequestId = startId;
269        if (mCleaningUp) {
270            Log.e(TAG,"*************Received new request while service is cleaning up****************************");
271        }
272
273        if (DBG) debugLog("onStartCommand: flags = " + flags + ", startId = " + startId);
274        if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) {
275            Log.e(TAG, "Permission denied!");
276            return ADAPTER_SERVICE_TYPE;
277        }
278
279        //Check if we are restarting
280        if (intent == null) {
281            debugLog("Restarting AdapterService");
282            return ADAPTER_SERVICE_TYPE;
283        }
284
285        //Get action and check if valid. If invalid, ignore and return
286        String action  = intent.getStringExtra(EXTRA_ACTION);
287        debugLog("onStartCommand(): action = " + action);
288        if (!ACTION_SERVICE_STATE_CHANGED.equals(action)) {
289            Log.w(TAG,"Unknown action: " + action);
290            return ADAPTER_SERVICE_TYPE;
291        }
292
293        //Check state of request. If invalid, ignore and return
294        int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.ERROR);
295        debugLog("onStartCommand(): state = " + Utils.debugGetAdapterStateString(state));
296
297        //Cancel any pending shutdown requests
298        synchronized (mHandler) {
299            mHandler.removeMessages(MESSAGE_SHUTDOWN);
300        }
301
302        if (state == BluetoothAdapter.STATE_OFF) {
303            Message m = mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
304            m.arg1= startId;
305            mAdapterStateMachine.sendMessage(m);
306        } else if (state == BluetoothAdapter.STATE_ON) {
307            Message m = mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
308            m.arg1= startId;
309            mAdapterStateMachine.sendMessage(m);
310        } else {
311            Log.w(TAG,"Invalid state: " + action);
312            return ADAPTER_SERVICE_TYPE;
313        }
314        return ADAPTER_SERVICE_TYPE;
315    }
316
317    void processStart() {
318        if (DBG) debugLog("processStart()");
319
320        //Initialize data objects
321        for (int i=0; i < SUPPORTED_PROFILE_SERVICES.length;i++) {
322            mProfileServicesState.put(SUPPORTED_PROFILE_SERVICES[i].getName(),BluetoothAdapter.STATE_OFF);
323        }
324        mRemoteDevices = new RemoteDevices(this);
325        mBondStateMachine = new BondStateMachine(this, mAdapterProperties, mRemoteDevices);
326        mAdapterProperties.init(mRemoteDevices);
327        mJniCallbacks.init(mBondStateMachine,mRemoteDevices);
328
329        //Start Bond State Machine
330        if (DBG) {debugLog("processStart(): Starting Bond State Machine");}
331        mBondStateMachine.start();
332
333        //FIXME: Set static instance here???
334        setAdapterService(this);
335
336        //Start profile services
337        if (!mProfilesStarted && SUPPORTED_PROFILE_SERVICES.length >0) {
338            //Startup all profile services
339            setProfileServiceState(SUPPORTED_PROFILE_SERVICES,BluetoothAdapter.STATE_ON);
340        }else {
341            if (DBG) {debugLog("processStart(): Profile Services alreay started");}
342            mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED));
343        }
344    }
345
346    void startBluetoothDisable() {
347        mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BEGIN_DISABLE));
348    }
349
350    boolean stopProfileServices() {
351        if (mProfilesStarted && SUPPORTED_PROFILE_SERVICES.length>0) {
352            setProfileServiceState(SUPPORTED_PROFILE_SERVICES,BluetoothAdapter.STATE_OFF);
353            return true;
354        } else {
355            if (DBG) {debugLog("stopProfileServices(): No profiles services to stop or already stopped.");}
356            return false;
357        }
358    }
359
360    void startShutdown(int requestId) {
361        debugLog("startShutdown(): requestId = " + requestId + ", currentRequestId=" + mCurrentRequestId);
362        if (requestId <0) {
363            Log.w(TAG, "Ignoring shutdown request. Invalid requestId");
364            return;
365        }
366        Message m = mHandler.obtainMessage(MESSAGE_SHUTDOWN);
367        synchronized(mHandler) {
368            mHandler.sendMessageDelayed(m, SHUTDOWN_TIMEOUT);
369        }
370        stopSelfResult(requestId);
371    }
372
373    void cleanup () {
374        if (DBG)debugLog("cleanup()");
375        if (mCleaningUp) {
376            Log.w(TAG,"*************service already starting to cleanup... Ignoring cleanup request.........");
377            return;
378        }
379
380        mCleaningUp = true;
381
382        if (mAdapterStateMachine != null) {
383            mAdapterStateMachine.quit();
384            mAdapterStateMachine.cleanup();
385            mAdapterStateMachine = null;
386        }
387
388        if (mBondStateMachine != null) {
389            mBondStateMachine.quit();
390            mBondStateMachine.cleanup();
391            mBondStateMachine = null;
392        }
393
394        if (mRemoteDevices != null) {
395            mRemoteDevices.cleanup();
396            mRemoteDevices = null;
397        }
398
399        if (mNativeAvailable) {
400            Log.d(TAG, "Cleaning up adapter native....");
401            cleanupNative();
402            Log.d(TAG, "Done cleaning up adapter native....");
403            mNativeAvailable=false;
404        }
405
406        if (mAdapterProperties != null) {
407            mAdapterProperties.cleanup();
408            mAdapterProperties = null;
409        }
410
411        if (mJniCallbacks != null) {
412            mJniCallbacks.cleanup();
413            mJniCallbacks = null;
414        }
415
416        if (mProfileServicesState != null) {
417            mProfileServicesState.clear();
418            mProfileServicesState= null;
419        }
420
421        //FIXME: Set static instance here???
422        clearAdapterService();
423
424        if (mBinder != null) {
425            mBinder.cleanup();
426            mBinder = null;
427        }
428        if (DBG)debugLog("cleanup() done");
429    }
430
431    private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED =1;
432    private static final int MESSAGE_PROFILE_CONNECTION_STATE_CHANGED=20;
433    private static final int MESSAGE_SHUTDOWN= 100;
434    private static final int SHUTDOWN_TIMEOUT=2000;
435
436    private final Handler mHandler = new Handler() {
437        @Override
438        public void handleMessage(Message msg) {
439            if (DBG) debugLog("Message: " + msg.what);
440
441            switch (msg.what) {
442                case MESSAGE_SHUTDOWN: {
443                    if (DBG) Log.d(TAG,"***SHUTDOWN: TIMEOUT!!! Forcing shutdown...");
444                    stopSelf();
445                }
446                    break;
447                case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: {
448                    if(DBG) debugLog("MESSAGE_PROFILE_SERVICE_STATE_CHANGED");
449                    processProfileServiceStateChanged((String) msg.obj, msg.arg1);
450                }
451                    break;
452                case MESSAGE_PROFILE_CONNECTION_STATE_CHANGED: {
453                    if (DBG) debugLog( "MESSAGE_PROFILE_CONNECTION_STATE_CHANGED");
454                    processProfileStateChanged((BluetoothDevice) msg.obj, msg.arg1,msg.arg2, msg.getData().getInt("prevState",BluetoothAdapter.ERROR));
455                }
456                    break;
457            }
458        }
459    };
460
461    @SuppressWarnings("rawtypes")
462    private void setProfileServiceState(Class[] services, int state) {
463        if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) {
464            Log.w(TAG,"setProfileServiceState(): invalid state...Leaving...");
465            return;
466        }
467
468        int expectedCurrentState= BluetoothAdapter.STATE_OFF;
469        int pendingState = BluetoothAdapter.STATE_TURNING_ON;
470        if (state == BluetoothAdapter.STATE_OFF) {
471            expectedCurrentState= BluetoothAdapter.STATE_ON;
472            pendingState = BluetoothAdapter.STATE_TURNING_OFF;
473        }
474
475        for (int i=0; i <services.length;i++) {
476            String serviceName = services[i].getName();
477            Integer serviceState = mProfileServicesState.get(serviceName);
478            if(serviceState != null && serviceState != expectedCurrentState) {
479                Log.w(TAG, "Unable to " + (state == BluetoothAdapter.STATE_OFF? "start" : "stop" ) +" service " +
480                        serviceName+". Invalid state: " + serviceState);
481                continue;
482            }
483
484            if (DBG) {
485                Log.w(TAG, (state == BluetoothAdapter.STATE_OFF? "Stopping" : "Starting" ) +" service " +
486                        serviceName);
487            }
488
489            mProfileServicesState.put(serviceName,pendingState);
490            Intent intent = new Intent(this,services[i]);
491            intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
492            intent.putExtra(BluetoothAdapter.EXTRA_STATE,state);
493            startService(intent);
494        }
495    }
496
497    private boolean isAvailable() {
498        return !mCleaningUp;
499    }
500
501    /**
502     * Handlers for incoming service calls
503     */
504    private AdapterServiceBinder mBinder;
505
506    /**
507     * The Binder implementation must be declared to be a static class, with
508     * the AdapterService instance passed in the constructor. Furthermore,
509     * when the AdapterService shuts down, the reference to the AdapterService
510     * must be explicitly removed.
511     *
512     * Otherwise, a memory leak can occur from repeated starting/stopping the
513     * service...Please refer to android.os.Binder for further details on
514     * why an inner instance class should be avoided.
515     *
516     */
517    private static class AdapterServiceBinder extends IBluetooth.Stub {
518        private AdapterService mService;
519
520        public AdapterServiceBinder(AdapterService svc) {
521            mService = svc;
522        }
523        public boolean cleanup() {
524            mService = null;
525            return true;
526        }
527
528        public AdapterService getService() {
529            if (mService  != null && mService.isAvailable()) {
530                return mService;
531            }
532            return null;
533        }
534        public boolean isEnabled() {
535            AdapterService service = getService();
536            if (service == null) return false;
537            return service.isEnabled();
538        }
539
540        public int getState() {
541            AdapterService service = getService();
542            if (service == null) return  BluetoothAdapter.STATE_OFF;
543            return service.getState();
544        }
545
546        public boolean enable() {
547            AdapterService service = getService();
548            if (service == null) return false;
549            return service.enable();
550        }
551
552        public boolean disable(boolean persist) {
553            AdapterService service = getService();
554            if (service == null) return false;
555            return service.disable(persist);
556        }
557
558        public String getAddress() {
559            AdapterService service = getService();
560            if (service == null) return null;
561            return service.getAddress();
562        }
563
564        public ParcelUuid[] getUuids() {
565            AdapterService service = getService();
566            if (service == null) return new ParcelUuid[0];
567            return service.getUuids();
568        }
569
570        public String getName() {
571            AdapterService service = getService();
572            if (service == null) return null;
573            return service.getName();
574        }
575
576        public boolean setName(String name) {
577            AdapterService service = getService();
578            if (service == null) return false;
579            return service.setName(name);
580        }
581
582        public int getScanMode() {
583            AdapterService service = getService();
584            if (service == null) return BluetoothAdapter.SCAN_MODE_NONE;
585            return service.getScanMode();
586        }
587
588        public boolean setScanMode(int mode, int duration) {
589            AdapterService service = getService();
590            if (service == null) return false;
591            return service.setScanMode(mode,duration);
592        }
593
594        public int getDiscoverableTimeout() {
595            AdapterService service = getService();
596            if (service == null) return 0;
597            return service.getDiscoverableTimeout();
598        }
599
600        public boolean setDiscoverableTimeout(int timeout) {
601            AdapterService service = getService();
602            if (service == null) return false;
603            return service.setDiscoverableTimeout(timeout);
604        }
605
606        public boolean startDiscovery() {
607            AdapterService service = getService();
608            if (service == null) return false;
609            return service.startDiscovery();
610        }
611
612        public boolean cancelDiscovery() {
613            AdapterService service = getService();
614            if (service == null) return false;
615            return service.cancelDiscovery();
616        }
617        public boolean isDiscovering() {
618            AdapterService service = getService();
619            if (service == null) return false;
620            return service.isDiscovering();
621        }
622
623        public BluetoothDevice[] getBondedDevices() {
624            AdapterService service = getService();
625            if (service == null) return new BluetoothDevice[0];
626            return service.getBondedDevices();
627        }
628
629        public int getAdapterConnectionState() {
630            AdapterService service = getService();
631            if (service == null) return BluetoothAdapter.STATE_DISCONNECTED;
632            return service.getAdapterConnectionState();
633        }
634
635        public int getProfileConnectionState(int profile) {
636            AdapterService service = getService();
637            if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
638            return service.getProfileConnectionState(profile);
639        }
640
641        public boolean createBond(BluetoothDevice device) {
642            AdapterService service = getService();
643            if (service == null) return false;
644            return service.createBond(device);
645        }
646
647        public boolean cancelBondProcess(BluetoothDevice device) {
648            AdapterService service = getService();
649            if (service == null) return false;
650            return service.cancelBondProcess(device);
651        }
652
653        public boolean removeBond(BluetoothDevice device) {
654            AdapterService service = getService();
655            if (service == null) return false;
656            return service.removeBond(device);
657        }
658
659        public int getBondState(BluetoothDevice device) {
660            AdapterService service = getService();
661            if (service == null) return BluetoothDevice.BOND_NONE;
662            return service.getBondState(device);
663        }
664
665        public String getRemoteName(BluetoothDevice device) {
666            AdapterService service = getService();
667            if (service == null) return null;
668            return service.getRemoteName(device);
669        }
670
671        public String getRemoteAlias(BluetoothDevice device) {
672            AdapterService service = getService();
673            if (service == null) return null;
674            return service.getRemoteAlias(device);
675        }
676
677        public boolean setRemoteAlias(BluetoothDevice device, String name) {
678            AdapterService service = getService();
679            if (service == null) return false;
680            return service.setRemoteAlias(device, name);
681        }
682
683        public int getRemoteClass(BluetoothDevice device) {
684            AdapterService service = getService();
685            if (service == null) return 0;
686            return service.getRemoteClass(device);
687        }
688
689        public ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
690            AdapterService service = getService();
691            if (service == null) return null;
692            return service.getRemoteUuids(device);
693        }
694
695        public boolean fetchRemoteUuids(BluetoothDevice device) {
696            AdapterService service = getService();
697            if (service == null) return false;
698            return service.fetchRemoteUuids(device);
699        }
700
701        public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
702            AdapterService service = getService();
703            if (service == null) return false;
704            return service.setPin(device, accept, len, pinCode);
705        }
706
707        public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
708            AdapterService service = getService();
709            if (service == null) return false;
710            return service.setPasskey(device, accept, len, passkey);
711        }
712
713        public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
714            AdapterService service = getService();
715            if (service == null) return false;
716            return service.setPairingConfirmation(device, accept);
717        }
718
719        public void sendConnectionStateChange(BluetoothDevice
720                device, int profile, int state, int prevState) {
721            AdapterService service = getService();
722            if (service == null) return;
723            service.sendConnectionStateChange(device, profile, state, prevState);
724        }
725
726        public ParcelFileDescriptor connectSocket(BluetoothDevice device, int type,
727                                                  ParcelUuid uuid, int port, int flag) {
728            AdapterService service = getService();
729            if (service == null) return null;
730            return service.connectSocket(device, type, uuid, port, flag);
731        }
732
733        public ParcelFileDescriptor createSocketChannel(int type, String serviceName,
734                                                        ParcelUuid uuid, int port, int flag) {
735            AdapterService service = getService();
736            if (service == null) return null;
737            return service.createSocketChannel(type, serviceName, uuid, port, flag);
738        }
739    };
740
741
742    //----API Methods--------
743     boolean isEnabled() {
744        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
745        return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON;
746    }
747
748     int getState() {
749        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
750        debugLog("getState(): mAdapterProperties: " + mAdapterProperties);
751        return mAdapterProperties.getState();
752    }
753
754     boolean enable() {
755        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
756                "Need BLUETOOTH ADMIN permission");
757        if (DBG) debugLog("enable() called...");
758        Message m =
759                mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
760        m.arg1 = 1; //persist state
761        mAdapterStateMachine.sendMessage(m);
762        return true;
763    }
764
765     boolean disable(boolean persist) {
766        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
767                "Need BLUETOOTH ADMIN permission");
768        if (DBG) debugLog("disable() called...");
769        int val = (persist ? 1 : 0);
770        Message m =
771                mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
772        m.arg1 = val;
773        mAdapterStateMachine.sendMessage(m);
774        return true;
775    }
776
777     String getAddress() {
778        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
779        String addrString = null;
780        byte[] address = mAdapterProperties.getAddress();
781        return Utils.getAddressStringFromByte(address);
782    }
783
784     ParcelUuid[] getUuids() {
785        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
786        return mAdapterProperties.getUuids();
787    }
788
789     String getName() {
790        enforceCallingOrSelfPermission(BLUETOOTH_PERM,
791                "Need BLUETOOTH permission");
792        try {
793            return mAdapterProperties.getName();
794        } catch (Throwable t) {
795            Log.d(TAG, "Unexpected exception while calling getName()",t);
796        }
797        return null;
798    }
799
800     boolean setName(String name) {
801        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
802                "Need BLUETOOTH ADMIN permission");
803        return mAdapterProperties.setName(name);
804    }
805
806     int getScanMode() {
807        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
808        return mAdapterProperties.getScanMode();
809    }
810
811     boolean setScanMode(int mode, int duration) {
812        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
813        setDiscoverableTimeout(duration);
814
815        int newMode = convertScanModeToHal(mode);
816        return mAdapterProperties.setScanMode(newMode);
817    }
818
819     int getDiscoverableTimeout() {
820        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
821        return mAdapterProperties.getDiscoverableTimeout();
822    }
823
824     boolean setDiscoverableTimeout(int timeout) {
825        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
826        return mAdapterProperties.setDiscoverableTimeout(timeout);
827    }
828
829     boolean startDiscovery() {
830        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
831                "Need BLUETOOTH ADMIN permission");
832        return startDiscoveryNative();
833    }
834
835     boolean cancelDiscovery() {
836        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
837                "Need BLUETOOTH ADMIN permission");
838        return cancelDiscoveryNative();
839    }
840
841     boolean isDiscovering() {
842        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
843        return mAdapterProperties.isDiscovering();
844    }
845
846     BluetoothDevice[] getBondedDevices() {
847        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
848        debugLog("Get Bonded Devices being called");
849        return mAdapterProperties.getBondedDevices();
850    }
851
852     int getAdapterConnectionState() {
853        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
854        return mAdapterProperties.getConnectionState();
855    }
856
857     int getProfileConnectionState(int profile) {
858        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
859        return mAdapterProperties.getProfileConnectionState(profile);
860    }
861
862     boolean createBond(BluetoothDevice device) {
863        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
864            "Need BLUETOOTH ADMIN permission");
865        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
866        if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
867            return false;
868        }
869
870        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
871        msg.obj = device;
872        mBondStateMachine.sendMessage(msg);
873        return true;
874    }
875
876     boolean cancelBondProcess(BluetoothDevice device) {
877        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
878        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
879        return cancelBondNative(addr);
880    }
881
882     boolean removeBond(BluetoothDevice device) {
883        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
884        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
885        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) {
886            return false;
887        }
888        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND);
889        msg.obj = device;
890        mBondStateMachine.sendMessage(msg);
891        return true;
892    }
893
894     int getBondState(BluetoothDevice device) {
895        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
896        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
897        if (deviceProp == null) {
898            return BluetoothDevice.BOND_NONE;
899        }
900        return deviceProp.getBondState();
901    }
902
903     String getRemoteName(BluetoothDevice device) {
904        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
905        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
906        if (deviceProp == null) return null;
907        return deviceProp.getName();
908    }
909
910     String getRemoteAlias(BluetoothDevice device) {
911        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
912        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
913        if (deviceProp == null) return null;
914        return deviceProp.getAlias();
915    }
916
917     boolean setRemoteAlias(BluetoothDevice device, String name) {
918        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
919        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
920        if (deviceProp == null) return false;
921        deviceProp.setAlias(name);
922        return true;
923    }
924
925     int getRemoteClass(BluetoothDevice device) {
926        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
927        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
928        if (deviceProp == null) return 0;
929
930        return deviceProp.getBluetoothClass();
931    }
932
933     ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
934        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
935        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
936        if (deviceProp == null) return null;
937        return deviceProp.getUuids();
938    }
939
940     boolean fetchRemoteUuids(BluetoothDevice device) {
941        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
942        mRemoteDevices.fetchUuids(device);
943        return true;
944    }
945
946     boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
947        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
948        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
949        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
950            return false;
951        }
952
953        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
954        return pinReplyNative(addr, accept, len, pinCode);
955    }
956
957     boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
958        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
959        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
960        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
961            return false;
962        }
963
964        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
965        return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept,
966                Utils.byteArrayToInt(passkey));
967    }
968
969     boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
970        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
971        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
972        if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
973            return false;
974        }
975
976        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
977        return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION,
978                accept, 0);
979    }
980
981     void sendConnectionStateChange(BluetoothDevice
982            device, int profile, int state, int prevState) {
983        // TODO(BT) permission check?
984        // Since this is a binder call check if Bluetooth is on still
985        if (getState() == BluetoothAdapter.STATE_OFF) return;
986
987        mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState);
988
989    }
990
991     ParcelFileDescriptor connectSocket(BluetoothDevice device, int type,
992                                              ParcelUuid uuid, int port, int flag) {
993        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
994        int fd = connectSocketNative(Utils.getBytesFromAddress(device.getAddress()),
995                   type, Utils.uuidToByteArray(uuid), port, flag);
996        if (fd < 0) {
997            errorLog("Failed to connect socket");
998            return null;
999        }
1000        return ParcelFileDescriptor.adoptFd(fd);
1001    }
1002
1003     ParcelFileDescriptor createSocketChannel(int type, String serviceName,
1004                                                    ParcelUuid uuid, int port, int flag) {
1005        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1006        int fd =  createSocketChannelNative(type, serviceName,
1007                                 Utils.uuidToByteArray(uuid), port, flag);
1008        if (fd < 0) {
1009            errorLog("Failed to create socket channel");
1010            return null;
1011        }
1012        return ParcelFileDescriptor.adoptFd(fd);
1013    }
1014
1015    private static int convertScanModeToHal(int mode) {
1016        switch (mode) {
1017            case BluetoothAdapter.SCAN_MODE_NONE:
1018                return AbstractionLayer.BT_SCAN_MODE_NONE;
1019            case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
1020                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE;
1021            case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
1022                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1023        }
1024       // errorLog("Incorrect scan mode in convertScanModeToHal");
1025        return -1;
1026    }
1027
1028    static int convertScanModeFromHal(int mode) {
1029        switch (mode) {
1030            case AbstractionLayer.BT_SCAN_MODE_NONE:
1031                return BluetoothAdapter.SCAN_MODE_NONE;
1032            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE:
1033                return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1034            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
1035                return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1036        }
1037        //errorLog("Incorrect scan mode in convertScanModeFromHal");
1038        return -1;
1039    }
1040
1041    private void debugLog(String msg) {
1042        Log.d(TAG +"(" +hashCode()+")", msg);
1043    }
1044
1045    private void errorLog(String msg) {
1046        Log.e(TAG +"(" +hashCode()+")", msg);
1047    }
1048
1049    private native static void classInitNative();
1050    private native boolean initNative();
1051    private native void cleanupNative();
1052    /*package*/ native boolean enableNative();
1053    /*package*/ native boolean disableNative();
1054    /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val);
1055    /*package*/ native boolean getAdapterPropertiesNative();
1056    /*package*/ native boolean getAdapterPropertyNative(int type);
1057    /*package*/ native boolean setAdapterPropertyNative(int type);
1058    /*package*/ native boolean
1059        setDevicePropertyNative(byte[] address, int type, byte[] val);
1060    /*package*/ native boolean getDevicePropertyNative(byte[] address, int type);
1061
1062    /*package*/ native boolean createBondNative(byte[] address);
1063    /*package*/ native boolean removeBondNative(byte[] address);
1064    /*package*/ native boolean cancelBondNative(byte[] address);
1065
1066    private native boolean startDiscoveryNative();
1067    private native boolean cancelDiscoveryNative();
1068
1069    private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin);
1070    private native boolean sspReplyNative(byte[] address, int type, boolean
1071            accept, int passkey);
1072
1073    /*package*/ native boolean getRemoteServicesNative(byte[] address);
1074
1075    // TODO(BT) move this to ../btsock dir
1076    private native int connectSocketNative(byte[] address, int type,
1077                                           byte[] uuid, int port, int flag);
1078    private native int createSocketChannelNative(int type, String serviceName,
1079                                                 byte[] uuid, int port, int flag);
1080
1081    protected void finalize() {
1082        cleanup();
1083        if (TRACE_REF) {
1084            synchronized (AdapterService.class) {
1085                sRefCount--;
1086                Log.d(TAG, "REFCOUNT: FINALIZED. INSTANCE_COUNT= " + sRefCount);
1087            }
1088        }
1089    }
1090}
1091