Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /**
     18  * TODO: Move this to
     19  * java/services/com/android/server/BluetoothService.java
     20  * and make the contructor package private again.
     21  *
     22  * @hide
     23  */
     24 
     25 package android.server;
     26 
     27 import android.bluetooth.BluetoothAdapter;
     28 import android.bluetooth.BluetoothClass;
     29 import android.bluetooth.BluetoothDevice;
     30 import android.bluetooth.BluetoothDeviceProfileState;
     31 import android.bluetooth.BluetoothHeadset;
     32 import android.bluetooth.BluetoothHealthAppConfiguration;
     33 import android.bluetooth.BluetoothInputDevice;
     34 import android.bluetooth.BluetoothPan;
     35 import android.bluetooth.BluetoothProfile;
     36 import android.bluetooth.BluetoothProfileState;
     37 import android.bluetooth.BluetoothSocket;
     38 import android.bluetooth.BluetoothUuid;
     39 import android.bluetooth.IBluetooth;
     40 import android.bluetooth.IBluetoothCallback;
     41 import android.bluetooth.IBluetoothHealthCallback;
     42 import android.bluetooth.IBluetoothStateChangeCallback;
     43 import android.content.BroadcastReceiver;
     44 import android.content.ContentResolver;
     45 import android.content.Context;
     46 import android.content.Intent;
     47 import android.content.IntentFilter;
     48 import android.content.SharedPreferences;
     49 import android.os.Binder;
     50 import android.os.Handler;
     51 import android.os.IBinder;
     52 import android.os.Message;
     53 import android.os.ParcelFileDescriptor;
     54 import android.os.ParcelUuid;
     55 import android.os.RemoteException;
     56 import android.os.ServiceManager;
     57 import android.provider.Settings;
     58 import android.util.Log;
     59 import android.util.Pair;
     60 
     61 import com.android.internal.app.IBatteryStats;
     62 
     63 import java.io.BufferedInputStream;
     64 import java.io.BufferedReader;
     65 import java.io.BufferedWriter;
     66 import java.io.DataInputStream;
     67 import java.io.File;
     68 import java.io.FileDescriptor;
     69 import java.io.FileInputStream;
     70 import java.io.FileNotFoundException;
     71 import java.io.FileWriter;
     72 import java.io.IOException;
     73 import java.io.InputStreamReader;
     74 import java.io.PrintWriter;
     75 import java.io.RandomAccessFile;
     76 import java.io.UnsupportedEncodingException;
     77 import java.util.ArrayList;
     78 import java.util.Arrays;
     79 import java.util.Collection;
     80 import java.util.Collections;
     81 import java.util.HashMap;
     82 import java.util.Iterator;
     83 import java.util.List;
     84 import java.util.Map;
     85 
     86 public class BluetoothService extends IBluetooth.Stub {
     87     private static final String TAG = "BluetoothService";
     88     private static final boolean DBG = true;
     89 
     90     private int mNativeData;
     91     private BluetoothEventLoop mEventLoop;
     92     private BluetoothHeadset mBluetoothHeadset;
     93     private BluetoothInputDevice mInputDevice;
     94     private BluetoothPan mPan;
     95     private boolean mIsAirplaneSensitive;
     96     private boolean mIsAirplaneToggleable;
     97     private BluetoothAdapterStateMachine mBluetoothState;
     98     private int[] mAdapterSdpHandles;
     99     private ParcelUuid[] mAdapterUuids;
    100 
    101     private BluetoothAdapter mAdapter;  // constant after init()
    102     private final BluetoothBondState mBondState;  // local cache of bondings
    103     private final IBatteryStats mBatteryStats;
    104     private final Context mContext;
    105     private Map<Integer, IBluetoothStateChangeCallback> mStateChangeTracker =
    106         Collections.synchronizedMap(new HashMap<Integer, IBluetoothStateChangeCallback>());
    107 
    108     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
    109     static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
    110 
    111     private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr";
    112     private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin";
    113 
    114     private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address";
    115     private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings";
    116 
    117     private static final int MESSAGE_UUID_INTENT = 1;
    118     private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 2;
    119     private static final int MESSAGE_REMOVE_SERVICE_RECORD = 3;
    120 
    121     private static final int RFCOMM_RECORD_REAPER = 10;
    122     private static final int STATE_CHANGE_REAPER = 11;
    123 
    124     // The time (in millisecs) to delay the pairing attempt after the first
    125     // auto pairing attempt fails. We use an exponential delay with
    126     // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
    127     // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
    128     private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
    129     private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
    130 
    131     // The timeout used to sent the UUIDs Intent
    132     // This timeout should be greater than the page timeout
    133     private static final int UUID_INTENT_DELAY = 6000;
    134 
    135     /** Always retrieve RFCOMM channel for these SDP UUIDs */
    136     private static final ParcelUuid[] RFCOMM_UUIDS = {
    137             BluetoothUuid.Handsfree,
    138             BluetoothUuid.HSP,
    139             BluetoothUuid.ObexObjectPush };
    140 
    141     private final BluetoothAdapterProperties mAdapterProperties;
    142     private final BluetoothDeviceProperties mDeviceProperties;
    143 
    144     private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
    145     private final ArrayList<String> mUuidIntentTracker;
    146     private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
    147 
    148     private final HashMap<Integer, Pair<Integer, IBinder>> mServiceRecordToPid;
    149 
    150     private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState;
    151     private final BluetoothProfileState mA2dpProfileState;
    152     private final BluetoothProfileState mHfpProfileState;
    153 
    154     private BluetoothA2dpService mA2dpService;
    155     private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData;
    156 
    157     private int mProfilesConnected = 0, mProfilesConnecting = 0, mProfilesDisconnecting = 0;
    158 
    159     private static String mDockAddress;
    160     private String mDockPin;
    161 
    162     private int mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
    163     private BluetoothPanProfileHandler mBluetoothPanProfileHandler;
    164     private BluetoothInputProfileHandler mBluetoothInputProfileHandler;
    165     private BluetoothHealthProfileHandler mBluetoothHealthProfileHandler;
    166     private static final String INCOMING_CONNECTION_FILE =
    167       "/data/misc/bluetooth/incoming_connection.conf";
    168     private HashMap<String, Pair<Integer, String>> mIncomingConnections;
    169     private HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState;
    170 
    171     private static class RemoteService {
    172         public String address;
    173         public ParcelUuid uuid;
    174         public RemoteService(String address, ParcelUuid uuid) {
    175             this.address = address;
    176             this.uuid = uuid;
    177         }
    178         @Override
    179         public boolean equals(Object o) {
    180             if (o instanceof RemoteService) {
    181                 RemoteService service = (RemoteService)o;
    182                 return address.equals(service.address) && uuid.equals(service.uuid);
    183             }
    184             return false;
    185         }
    186 
    187         @Override
    188         public int hashCode() {
    189             int hash = 1;
    190             hash = hash * 31 + (address == null ? 0 : address.hashCode());
    191             hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
    192             return hash;
    193         }
    194     }
    195 
    196     static {
    197         classInitNative();
    198     }
    199 
    200     public BluetoothService(Context context) {
    201         mContext = context;
    202 
    203         // Need to do this in place of:
    204         // mBatteryStats = BatteryStatsService.getService();
    205         // Since we can not import BatteryStatsService from here. This class really needs to be
    206         // moved to java/services/com/android/server/
    207         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
    208 
    209         initializeNativeDataNative();
    210 
    211         if (isEnabledNative() == 1) {
    212             Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
    213             disableNative();
    214         }
    215 
    216         mBondState = new BluetoothBondState(context, this);
    217         mAdapterProperties = new BluetoothAdapterProperties(context, this);
    218         mDeviceProperties = new BluetoothDeviceProperties(this);
    219 
    220         mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
    221         mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
    222         mUuidIntentTracker = new ArrayList<String>();
    223         mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
    224         mServiceRecordToPid = new HashMap<Integer, Pair<Integer, IBinder>>();
    225         mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>();
    226         mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);
    227         mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP);
    228 
    229         mHfpProfileState.start();
    230         mA2dpProfileState.start();
    231 
    232         IntentFilter filter = new IntentFilter();
    233         registerForAirplaneMode(filter);
    234 
    235         filter.addAction(Intent.ACTION_DOCK_EVENT);
    236         mContext.registerReceiver(mReceiver, filter);
    237         mBluetoothInputProfileHandler = BluetoothInputProfileHandler.getInstance(mContext, this);
    238         mBluetoothPanProfileHandler = BluetoothPanProfileHandler.getInstance(mContext, this);
    239         mBluetoothHealthProfileHandler = BluetoothHealthProfileHandler.getInstance(mContext, this);
    240         mIncomingConnections = new HashMap<String, Pair<Integer, String>>();
    241         mProfileConnectionState = new HashMap<Integer, Pair<Integer, Integer>>();
    242     }
    243 
    244     public static synchronized String readDockBluetoothAddress() {
    245         if (mDockAddress != null) return mDockAddress;
    246 
    247         BufferedInputStream file = null;
    248         String dockAddress;
    249         try {
    250             file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
    251             byte[] address = new byte[17];
    252             file.read(address);
    253             dockAddress = new String(address);
    254             dockAddress = dockAddress.toUpperCase();
    255             if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
    256                 mDockAddress = dockAddress;
    257                 return mDockAddress;
    258             } else {
    259                 Log.e(TAG, "CheckBluetoothAddress failed for car dock address: "
    260                         + dockAddress);
    261             }
    262         } catch (FileNotFoundException e) {
    263             Log.e(TAG, "FileNotFoundException while trying to read dock address");
    264         } catch (IOException e) {
    265             Log.e(TAG, "IOException while trying to read dock address");
    266         } finally {
    267             if (file != null) {
    268                 try {
    269                     file.close();
    270                 } catch (IOException e) {
    271                     // Ignore
    272                 }
    273             }
    274         }
    275         mDockAddress = null;
    276         return null;
    277     }
    278 
    279     private synchronized boolean writeDockPin() {
    280         BufferedWriter out = null;
    281         try {
    282             out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
    283 
    284             // Generate a random 4 digit pin between 0000 and 9999
    285             // This is not truly random but good enough for our purposes.
    286             int pin = (int) Math.floor(Math.random() * 10000);
    287 
    288             mDockPin = String.format("%04d", pin);
    289             out.write(mDockPin);
    290             return true;
    291         } catch (FileNotFoundException e) {
    292             Log.e(TAG, "FileNotFoundException while trying to write dock pairing pin");
    293         } catch (IOException e) {
    294             Log.e(TAG, "IOException while while trying to write dock pairing pin");
    295         } finally {
    296             if (out != null) {
    297                 try {
    298                     out.close();
    299                 } catch (IOException e) {
    300                     // Ignore
    301                 }
    302             }
    303         }
    304         mDockPin = null;
    305         return false;
    306     }
    307 
    308     /*package*/ synchronized String getDockPin() {
    309         return mDockPin;
    310     }
    311 
    312     public synchronized void initAfterRegistration() {
    313         mAdapter = BluetoothAdapter.getDefaultAdapter();
    314         mBluetoothState = new BluetoothAdapterStateMachine(mContext, this, mAdapter);
    315         mBluetoothState.start();
    316         if (mContext.getResources().getBoolean
    317             (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
    318             mBluetoothState.sendMessage(BluetoothAdapterStateMachine.TURN_HOT);
    319         }
    320         mEventLoop = mBluetoothState.getBluetoothEventLoop();
    321     }
    322 
    323     public synchronized void initAfterA2dpRegistration() {
    324         mEventLoop.getProfileProxy();
    325     }
    326 
    327     @Override
    328     protected void finalize() throws Throwable {
    329         mContext.unregisterReceiver(mReceiver);
    330         try {
    331             cleanupNativeDataNative();
    332         } finally {
    333             super.finalize();
    334         }
    335     }
    336 
    337     public boolean isEnabled() {
    338         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    339         return isEnabledInternal();
    340     }
    341 
    342     private boolean isEnabledInternal() {
    343         return (getBluetoothStateInternal() == BluetoothAdapter.STATE_ON);
    344     }
    345 
    346     public int getBluetoothState() {
    347         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    348         return getBluetoothStateInternal();
    349     }
    350 
    351     int getBluetoothStateInternal() {
    352         return mBluetoothState.getBluetoothAdapterState();
    353     }
    354 
    355     /**
    356      * Bring down bluetooth and disable BT in settings. Returns true on success.
    357      */
    358     public boolean disable() {
    359         return disable(true);
    360     }
    361 
    362     /**
    363      * Bring down bluetooth. Returns true on success.
    364      *
    365      * @param saveSetting If true, persist the new setting
    366      */
    367     public synchronized boolean disable(boolean saveSetting) {
    368         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
    369 
    370         int adapterState = getBluetoothStateInternal();
    371 
    372         switch (adapterState) {
    373         case BluetoothAdapter.STATE_OFF:
    374             return true;
    375         case BluetoothAdapter.STATE_ON:
    376             break;
    377         default:
    378             return false;
    379         }
    380 
    381         mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_OFF, saveSetting);
    382         return true;
    383     }
    384 
    385     synchronized void disconnectDevices() {
    386         // Disconnect devices handled by BluetoothService.
    387         for (BluetoothDevice device: getConnectedInputDevices()) {
    388             disconnectInputDevice(device);
    389         }
    390 
    391         for (BluetoothDevice device: getConnectedPanDevices()) {
    392             disconnectPanDevice(device);
    393         }
    394     }
    395 
    396     /**
    397      * The Bluetooth has been turned off, but hot. Do bonding, profile cleanup
    398      */
    399     synchronized void finishDisable() {
    400         // mark in progress bondings as cancelled
    401         for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
    402             mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
    403                                     BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
    404         }
    405 
    406         // Stop the profile state machine for bonded devices.
    407         for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDED)) {
    408             removeProfileState(address);
    409         }
    410 
    411         // update mode
    412         Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
    413         intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
    414         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
    415     }
    416 
    417     /**
    418      * Local clean up after broadcasting STATE_OFF intent
    419      */
    420     synchronized void cleanupAfterFinishDisable() {
    421         mAdapterProperties.clear();
    422 
    423         for (Integer srHandle : mServiceRecordToPid.keySet()) {
    424             removeServiceRecordNative(srHandle);
    425         }
    426         mServiceRecordToPid.clear();
    427 
    428         mProfilesConnected = 0;
    429         mProfilesConnecting = 0;
    430         mProfilesDisconnecting = 0;
    431         mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
    432         mAdapterUuids = null;
    433         mAdapterSdpHandles = null;
    434 
    435         // Log bluetooth off to battery stats.
    436         long ident = Binder.clearCallingIdentity();
    437         try {
    438             mBatteryStats.noteBluetoothOff();
    439         } catch (RemoteException e) {
    440         } finally {
    441             Binder.restoreCallingIdentity(ident);
    442         }
    443     }
    444 
    445     /**
    446      * power off Bluetooth
    447      */
    448     synchronized void shutoffBluetooth() {
    449         if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles);
    450         setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE,
    451                 BluetoothPanProfileHandler.NAP_BRIDGE);
    452         tearDownNativeDataNative();
    453     }
    454 
    455     /**
    456      * Data clean up after Bluetooth shutoff
    457      */
    458     synchronized void cleanNativeAfterShutoffBluetooth() {
    459         // Ths method is called after shutdown of event loop in the Bluetooth shut down
    460         // procedure
    461 
    462         // the adapter property could be changed before event loop is stoped, clear it again
    463         mAdapterProperties.clear();
    464         disableNative();
    465     }
    466 
    467     /** Bring up BT and persist BT on in settings */
    468     public boolean enable() {
    469         return enable(true);
    470     }
    471 
    472     /**
    473      * Enable this Bluetooth device, asynchronously.
    474      * This turns on/off the underlying hardware.
    475      *
    476      * @param saveSetting If true, persist the new state of BT in settings
    477      * @return True on success (so far)
    478      */
    479     public synchronized boolean enable(boolean saveSetting) {
    480         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    481                                                 "Need BLUETOOTH_ADMIN permission");
    482 
    483         // Airplane mode can prevent Bluetooth radio from being turned on.
    484         if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
    485             return false;
    486         }
    487         mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON, saveSetting);
    488         return true;
    489     }
    490 
    491     /**
    492      * Turn on Bluetooth Module, Load firmware, and do all the preparation
    493      * needed to get the Bluetooth Module ready but keep it not discoverable
    494      * and not connectable.
    495      */
    496     /* package */ synchronized boolean prepareBluetooth() {
    497         if (!setupNativeDataNative()) {
    498             return false;
    499         }
    500         switchConnectable(false);
    501         updateSdpRecords();
    502         return true;
    503     }
    504 
    505     private final Handler mHandler = new Handler() {
    506         @Override
    507         public void handleMessage(Message msg) {
    508             switch (msg.what) {
    509             case MESSAGE_UUID_INTENT:
    510                 String address = (String)msg.obj;
    511                 if (address != null) {
    512                     sendUuidIntent(address);
    513                     makeServiceChannelCallbacks(address);
    514                 }
    515                 break;
    516             case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
    517                 address = (String)msg.obj;
    518                 if (address == null) return;
    519                 int attempt = mBondState.getAttempt(address);
    520 
    521                 // Try only if attemps are in progress and cap it 2 attempts
    522                 // The 2 attempts cap is a fail safe if the stack returns
    523                 // an incorrect error code for bonding failures and if the pin
    524                 // is entered wrongly twice we should abort.
    525                 if (attempt > 0 && attempt <= 2) {
    526                     mBondState.attempt(address);
    527                     createBond(address);
    528                     return;
    529                 }
    530                 if (attempt > 0) mBondState.clearPinAttempts(address);
    531                 break;
    532             case MESSAGE_REMOVE_SERVICE_RECORD:
    533                 Pair<Integer, Integer> pair = (Pair<Integer, Integer>) msg.obj;
    534                 checkAndRemoveRecord(pair.first, pair.second);
    535                 break;
    536             }
    537         }
    538     };
    539 
    540     private synchronized void addReservedSdpRecords(final ArrayList<ParcelUuid> uuids) {
    541         //Register SDP records.
    542         int[] svcIdentifiers = new int[uuids.size()];
    543         for (int i = 0; i < uuids.size(); i++) {
    544             svcIdentifiers[i] = BluetoothUuid.getServiceIdentifierFromParcelUuid(uuids.get(i));
    545         }
    546         mAdapterSdpHandles = addReservedServiceRecordsNative(svcIdentifiers);
    547     }
    548 
    549     private synchronized void updateSdpRecords() {
    550         ArrayList<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
    551 
    552         // Add the default records
    553         uuids.add(BluetoothUuid.HSP_AG);
    554         uuids.add(BluetoothUuid.ObexObjectPush);
    555 
    556         if (mContext.getResources().
    557                 getBoolean(com.android.internal.R.bool.config_voice_capable)) {
    558             uuids.add(BluetoothUuid.Handsfree_AG);
    559             uuids.add(BluetoothUuid.PBAP_PSE);
    560         }
    561 
    562         // Add SDP records for profiles maintained by Android userspace
    563         addReservedSdpRecords(uuids);
    564 
    565         // Enable profiles maintained by Bluez userspace.
    566         setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE,
    567                 BluetoothPanProfileHandler.NAP_BRIDGE);
    568 
    569         // Add SDP records for profiles maintained by Bluez userspace
    570         uuids.add(BluetoothUuid.AudioSource);
    571         uuids.add(BluetoothUuid.AvrcpTarget);
    572         uuids.add(BluetoothUuid.NAP);
    573 
    574         // Cannot cast uuids.toArray directly since ParcelUuid is parcelable
    575         mAdapterUuids = new ParcelUuid[uuids.size()];
    576         for (int i = 0; i < uuids.size(); i++) {
    577             mAdapterUuids[i] = uuids.get(i);
    578         }
    579     }
    580 
    581     /**
    582      * This function is called from Bluetooth Event Loop when onPropertyChanged
    583      * for adapter comes in with UUID property.
    584      * @param uuidsThe uuids of adapter as reported by Bluez.
    585      */
    586     /*package*/ synchronized void updateBluetoothState(String uuids) {
    587         ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids);
    588 
    589         if (mAdapterUuids != null &&
    590             BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {
    591             mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SERVICE_RECORD_LOADED);
    592         }
    593     }
    594 
    595     /**
    596      * This method is called immediately before Bluetooth module is turned on after
    597      * the adapter became pariable.
    598      * It inits bond state and profile state before STATE_ON intent is broadcasted.
    599      */
    600     /*package*/ void initBluetoothAfterTurningOn() {
    601         String discoverable = getProperty("Discoverable", false);
    602         String timeout = getProperty("DiscoverableTimeout", false);
    603         if (discoverable.equals("true") && Integer.valueOf(timeout) != 0) {
    604             setAdapterPropertyBooleanNative("Discoverable", 0);
    605         }
    606         mBondState.initBondState();
    607         initProfileState();
    608     }
    609 
    610     /**
    611      * This method is called immediately after Bluetooth module is turned on.
    612      * It starts auto-connection and places bluetooth on sign onto the battery
    613      * stats
    614      */
    615     /*package*/ void runBluetooth() {
    616         autoConnect();
    617 
    618         // Log bluetooth on to battery stats.
    619         long ident = Binder.clearCallingIdentity();
    620         try {
    621             mBatteryStats.noteBluetoothOn();
    622         } catch (RemoteException e) {
    623             Log.e(TAG, "", e);
    624         } finally {
    625             Binder.restoreCallingIdentity(ident);
    626         }
    627     }
    628 
    629     /*package*/ synchronized boolean attemptAutoPair(String address) {
    630         if (!mBondState.hasAutoPairingFailed(address) &&
    631                 !mBondState.isAutoPairingBlacklisted(address)) {
    632             mBondState.attempt(address);
    633             setPin(address, BluetoothDevice.convertPinToBytes("0000"));
    634             return true;
    635         }
    636         return false;
    637     }
    638 
    639     /*package*/ synchronized boolean isFixedPinZerosAutoPairKeyboard(String address) {
    640         // Check for keyboards which have fixed PIN 0000 as the pairing pin
    641         return mBondState.isFixedPinZerosAutoPairKeyboard(address);
    642     }
    643 
    644     /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) {
    645         if (result == BluetoothDevice.BOND_SUCCESS) {
    646             setBondState(address, BluetoothDevice.BOND_BONDED);
    647             if (mBondState.isAutoPairingAttemptsInProgress(address)) {
    648                 mBondState.clearPinAttempts(address);
    649             }
    650         } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
    651                 mBondState.getAttempt(address) == 1) {
    652             mBondState.addAutoPairingFailure(address);
    653             pairingAttempt(address, result);
    654         } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
    655               mBondState.isAutoPairingAttemptsInProgress(address)) {
    656             pairingAttempt(address, result);
    657         } else {
    658             setBondState(address, BluetoothDevice.BOND_NONE, result);
    659             if (mBondState.isAutoPairingAttemptsInProgress(address)) {
    660                 mBondState.clearPinAttempts(address);
    661             }
    662         }
    663     }
    664 
    665     /*package*/ synchronized String getPendingOutgoingBonding() {
    666         return mBondState.getPendingOutgoingBonding();
    667     }
    668 
    669     private void pairingAttempt(String address, int result) {
    670         // This happens when our initial guess of "0000" as the pass key
    671         // fails. Try to create the bond again and display the pin dialog
    672         // to the user. Use back-off while posting the delayed
    673         // message. The initial value is
    674         // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
    675         // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
    676         // reached, display an error to the user.
    677         int attempt = mBondState.getAttempt(address);
    678         if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
    679                     MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
    680             mBondState.clearPinAttempts(address);
    681             setBondState(address, BluetoothDevice.BOND_NONE, result);
    682             return;
    683         }
    684 
    685         Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
    686         message.obj = address;
    687         boolean postResult =  mHandler.sendMessageDelayed(message,
    688                                         attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
    689         if (!postResult) {
    690             mBondState.clearPinAttempts(address);
    691             setBondState(address,
    692                     BluetoothDevice.BOND_NONE, result);
    693             return;
    694         }
    695     }
    696 
    697     /*package*/ BluetoothDevice getRemoteDevice(String address) {
    698         return mAdapter.getRemoteDevice(address);
    699     }
    700 
    701     private static String toBondStateString(int bondState) {
    702         switch (bondState) {
    703         case BluetoothDevice.BOND_NONE:
    704             return "not bonded";
    705         case BluetoothDevice.BOND_BONDING:
    706             return "bonding";
    707         case BluetoothDevice.BOND_BONDED:
    708             return "bonded";
    709         default:
    710             return "??????";
    711         }
    712     }
    713 
    714     public synchronized boolean setName(String name) {
    715         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    716                                                 "Need BLUETOOTH_ADMIN permission");
    717         if (name == null) {
    718             return false;
    719         }
    720         return setPropertyString("Name", name);
    721     }
    722 
    723     //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
    724     // Either have a single property function with Object as the parameter
    725     // or have a function for each property and then obfuscate in the JNI layer.
    726     // The following looks dirty.
    727     private boolean setPropertyString(String key, String value) {
    728         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    729         if (!isEnabledInternal()) return false;
    730         return setAdapterPropertyStringNative(key, value);
    731     }
    732 
    733     private boolean setPropertyInteger(String key, int value) {
    734         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    735         if (!isEnabledInternal()) return false;
    736         return setAdapterPropertyIntegerNative(key, value);
    737     }
    738 
    739     private boolean setPropertyBoolean(String key, boolean value) {
    740         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    741         if (!isEnabledInternal()) return false;
    742         return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
    743     }
    744 
    745     /**
    746      * Set the discoverability window for the device.  A timeout of zero
    747      * makes the device permanently discoverable (if the device is
    748      * discoverable).  Setting the timeout to a nonzero value does not make
    749      * a device discoverable; you need to call setMode() to make the device
    750      * explicitly discoverable.
    751      *
    752      * @param timeout The discoverable timeout in seconds.
    753      */
    754     public synchronized boolean setDiscoverableTimeout(int timeout) {
    755         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    756                                                 "Need BLUETOOTH_ADMIN permission");
    757         return setPropertyInteger("DiscoverableTimeout", timeout);
    758     }
    759 
    760     public synchronized boolean setScanMode(int mode, int duration) {
    761         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
    762                                                 "Need WRITE_SECURE_SETTINGS permission");
    763         boolean pairable;
    764         boolean discoverable;
    765 
    766         switch (mode) {
    767         case BluetoothAdapter.SCAN_MODE_NONE:
    768             pairable = false;
    769             discoverable = false;
    770             break;
    771         case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
    772             pairable = true;
    773             discoverable = false;
    774             break;
    775         case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
    776             pairable = true;
    777             discoverable = true;
    778             if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
    779             break;
    780         default:
    781             Log.w(TAG, "Requested invalid scan mode " + mode);
    782             return false;
    783         }
    784 
    785         setPropertyBoolean("Discoverable", discoverable);
    786         setPropertyBoolean("Pairable", pairable);
    787         return true;
    788     }
    789 
    790     /**
    791      * @param on true set the local Bluetooth module to be connectable
    792      *                The dicoverability is recovered to what it was before
    793      *                switchConnectable(false) call
    794      *           false set the local Bluetooth module to be not connectable
    795      *                 and not dicoverable
    796      */
    797     /*package*/ synchronized void switchConnectable(boolean on) {
    798         setAdapterPropertyBooleanNative("Powered", on ? 1 : 0);
    799     }
    800 
    801     /*package*/ synchronized void setPairable() {
    802         String pairableString = getProperty("Pairable", false);
    803         if (pairableString == null) {
    804             Log.e(TAG, "null pairableString");
    805             return;
    806         }
    807         if (pairableString.equals("false")) {
    808             setAdapterPropertyBooleanNative("Pairable", 1);
    809         }
    810     }
    811 
    812     /*package*/ synchronized String getProperty(String name, boolean checkState) {
    813         // If checkState is false, check if the event loop is running.
    814         // before making the call to Bluez
    815         if (checkState) {
    816             if (!isEnabledInternal()) return null;
    817         } else if (!mEventLoop.isEventLoopRunning()) {
    818             return null;
    819         }
    820 
    821         return mAdapterProperties.getProperty(name);
    822     }
    823 
    824     BluetoothAdapterProperties getAdapterProperties() {
    825         return mAdapterProperties;
    826     }
    827 
    828     BluetoothDeviceProperties getDeviceProperties() {
    829         return mDeviceProperties;
    830     }
    831 
    832     boolean isRemoteDeviceInCache(String address) {
    833         return mDeviceProperties.isInCache(address);
    834     }
    835 
    836     void setRemoteDeviceProperty(String address, String name, String value) {
    837         mDeviceProperties.setProperty(address, name, value);
    838     }
    839 
    840     void updateRemoteDevicePropertiesCache(String address) {
    841         mDeviceProperties.updateCache(address);
    842     }
    843 
    844     public synchronized String getAddress() {
    845         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    846         // Don't check state since we want to provide address, even if BT is off
    847         return getProperty("Address", false);
    848     }
    849 
    850     public synchronized String getName() {
    851         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    852         // Don't check state since we want to provide name, even if BT is off
    853         return getProperty("Name", false);
    854     }
    855 
    856     public synchronized ParcelUuid[] getUuids() {
    857         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    858         String value =  getProperty("UUIDs", true);
    859         if (value == null) return null;
    860         return convertStringToParcelUuid(value);
    861     }
    862 
    863     private synchronized ParcelUuid[] convertStringToParcelUuid(String value) {
    864         String[] uuidStrings = null;
    865         // The UUIDs are stored as a "," separated string.
    866         uuidStrings = value.split(",");
    867         ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
    868 
    869         for (int i = 0; i < uuidStrings.length; i++) {
    870             uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
    871         }
    872         return uuids;
    873     }
    874 
    875     /**
    876      * Returns the user-friendly name of a remote device.  This value is
    877      * returned from our local cache, which is updated when onPropertyChange
    878      * event is received.
    879      * Do not expect to retrieve the updated remote name immediately after
    880      * changing the name on the remote device.
    881      *
    882      * @param address Bluetooth address of remote device.
    883      *
    884      * @return The user-friendly name of the specified remote device.
    885      */
    886     public synchronized String getRemoteName(String address) {
    887         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    888         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
    889             return null;
    890         }
    891         return mDeviceProperties.getProperty(address, "Name");
    892     }
    893 
    894     /**
    895      * Returns alias of a remote device.  This value is returned from our
    896      * local cache, which is updated when onPropertyChange event is received.
    897      *
    898      * @param address Bluetooth address of remote device.
    899      *
    900      * @return The alias of the specified remote device.
    901      */
    902     public synchronized String getRemoteAlias(String address) {
    903 
    904         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    905         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
    906             return null;
    907         }
    908         return mDeviceProperties.getProperty(address, "Alias");
    909     }
    910 
    911     /**
    912      * Set the alias of a remote device.
    913      *
    914      * @param address Bluetooth address of remote device.
    915      * @param alias new alias to change to
    916      * @return true on success, false on error
    917      */
    918     public synchronized boolean setRemoteAlias(String address, String alias) {
    919         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    920         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
    921             return false;
    922         }
    923 
    924         return setDevicePropertyStringNative(getObjectPathFromAddress(address),
    925                                              "Alias", alias);
    926     }
    927 
    928     /**
    929      * Get the discoverability window for the device.  A timeout of zero
    930      * means that the device is permanently discoverable (if the device is
    931      * in the discoverable mode).
    932      *
    933      * @return The discoverability window of the device, in seconds.  A negative
    934      *         value indicates an error.
    935      */
    936     public synchronized int getDiscoverableTimeout() {
    937         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    938         String timeout = getProperty("DiscoverableTimeout", true);
    939         if (timeout != null)
    940            return Integer.valueOf(timeout);
    941         else
    942             return -1;
    943     }
    944 
    945     public synchronized int getScanMode() {
    946         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    947         if (!isEnabledInternal())
    948             return BluetoothAdapter.SCAN_MODE_NONE;
    949 
    950         boolean pairable = getProperty("Pairable", true).equals("true");
    951         boolean discoverable = getProperty("Discoverable", true).equals("true");
    952         return bluezStringToScanMode (pairable, discoverable);
    953     }
    954 
    955     public synchronized boolean startDiscovery() {
    956         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    957                                                 "Need BLUETOOTH_ADMIN permission");
    958         if (!isEnabledInternal()) return false;
    959 
    960         return startDiscoveryNative();
    961     }
    962 
    963     public synchronized boolean cancelDiscovery() {
    964         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    965                                                 "Need BLUETOOTH_ADMIN permission");
    966         if (!isEnabledInternal()) return false;
    967 
    968         return stopDiscoveryNative();
    969     }
    970 
    971     public synchronized boolean isDiscovering() {
    972         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
    973 
    974         String discoveringProperty = getProperty("Discovering", false);
    975         if (discoveringProperty == null) {
    976             return false;
    977         }
    978 
    979         return discoveringProperty.equals("true");
    980     }
    981 
    982     private boolean isBondingFeasible(String address) {
    983         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
    984                                                 "Need BLUETOOTH_ADMIN permission");
    985         if (!isEnabledInternal()) return false;
    986 
    987         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
    988             return false;
    989         }
    990         address = address.toUpperCase();
    991 
    992         if (mBondState.getPendingOutgoingBonding() != null) {
    993             Log.d(TAG, "Ignoring createBond(): another device is bonding");
    994             // a different device is currently bonding, fail
    995             return false;
    996         }
    997 
    998         // Check for bond state only if we are not performing auto
    999         // pairing exponential back-off attempts.
   1000         if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
   1001                 mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
   1002             Log.d(TAG, "Ignoring createBond(): this device is already bonding or bonded");
   1003             return false;
   1004         }
   1005 
   1006         if (address.equals(mDockAddress)) {
   1007             if (!writeDockPin()) {
   1008                 Log.e(TAG, "Error while writing Pin for the dock");
   1009                 return false;
   1010             }
   1011         }
   1012         return true;
   1013     }
   1014 
   1015     public synchronized boolean createBond(String address) {
   1016         if (!isBondingFeasible(address)) return false;
   1017 
   1018         if (!createPairedDeviceNative(address, 60000  /*1 minute*/ )) {
   1019             return false;
   1020         }
   1021 
   1022         mBondState.setPendingOutgoingBonding(address);
   1023         mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
   1024 
   1025         return true;
   1026     }
   1027 
   1028     public synchronized boolean createBondOutOfBand(String address, byte[] hash,
   1029                                                     byte[] randomizer) {
   1030         if (!isBondingFeasible(address)) return false;
   1031 
   1032         if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) {
   1033             return false;
   1034         }
   1035 
   1036         setDeviceOutOfBandData(address, hash, randomizer);
   1037         mBondState.setPendingOutgoingBonding(address);
   1038         mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
   1039 
   1040         return true;
   1041     }
   1042 
   1043     public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash,
   1044             byte[] randomizer) {
   1045         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   1046                                                 "Need BLUETOOTH_ADMIN permission");
   1047         if (!isEnabledInternal()) return false;
   1048 
   1049         Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer);
   1050 
   1051         if (DBG) {
   1052             Log.d(TAG, "Setting out of band data for: " + address + ":" +
   1053                   Arrays.toString(hash) + ":" + Arrays.toString(randomizer));
   1054         }
   1055 
   1056         mDeviceOobData.put(address, value);
   1057         return true;
   1058     }
   1059 
   1060     Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) {
   1061         return mDeviceOobData.get(device.getAddress());
   1062     }
   1063 
   1064 
   1065     public synchronized byte[] readOutOfBandData() {
   1066         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   1067                                                 "Need BLUETOOTH permission");
   1068         if (!isEnabledInternal()) return null;
   1069 
   1070         return readAdapterOutOfBandDataNative();
   1071     }
   1072 
   1073     public synchronized boolean cancelBondProcess(String address) {
   1074         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   1075                                                 "Need BLUETOOTH_ADMIN permission");
   1076         if (!isEnabledInternal()) return false;
   1077 
   1078         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   1079             return false;
   1080         }
   1081         address = address.toUpperCase();
   1082         if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
   1083             return false;
   1084         }
   1085 
   1086         mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
   1087                                 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
   1088         cancelDeviceCreationNative(address);
   1089         return true;
   1090     }
   1091 
   1092     public synchronized boolean removeBond(String address) {
   1093         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   1094                                                 "Need BLUETOOTH_ADMIN permission");
   1095         if (!isEnabledInternal()) return false;
   1096 
   1097         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   1098             return false;
   1099         }
   1100         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
   1101         if (state != null) {
   1102             state.sendMessage(BluetoothDeviceProfileState.UNPAIR);
   1103             return true;
   1104         } else {
   1105             return false;
   1106         }
   1107     }
   1108 
   1109     public synchronized boolean removeBondInternal(String address) {
   1110         // Unset the trusted device state and then unpair
   1111         setTrust(address, false);
   1112         return removeDeviceNative(getObjectPathFromAddress(address));
   1113     }
   1114 
   1115     public synchronized String[] listBonds() {
   1116         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   1117         return mBondState.listInState(BluetoothDevice.BOND_BONDED);
   1118     }
   1119 
   1120     /*package*/ synchronized String[] listInState(int state) {
   1121       return mBondState.listInState(state);
   1122     }
   1123 
   1124     public synchronized int getBondState(String address) {
   1125         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   1126         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   1127             return BluetoothDevice.ERROR;
   1128         }
   1129         return mBondState.getBondState(address.toUpperCase());
   1130     }
   1131 
   1132     /*package*/ synchronized boolean setBondState(String address, int state) {
   1133         return setBondState(address, state, 0);
   1134     }
   1135 
   1136     /*package*/ synchronized boolean setBondState(String address, int state, int reason) {
   1137         mBondState.setBondState(address.toUpperCase(), state, reason);
   1138         return true;
   1139     }
   1140 
   1141     public synchronized boolean isBluetoothDock(String address) {
   1142         SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
   1143                 Context.MODE_PRIVATE);
   1144 
   1145         return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
   1146     }
   1147 
   1148     /*package*/ String[] getRemoteDeviceProperties(String address) {
   1149         if (!isEnabledInternal()) return null;
   1150 
   1151         String objectPath = getObjectPathFromAddress(address);
   1152         return (String [])getDevicePropertiesNative(objectPath);
   1153     }
   1154 
   1155     /**
   1156      * Sets the remote device trust state.
   1157      *
   1158      * @return boolean to indicate operation success or fail
   1159      */
   1160     public synchronized boolean setTrust(String address, boolean value) {
   1161         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   1162             mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   1163                     "Need BLUETOOTH_ADMIN permission");
   1164             return false;
   1165         }
   1166 
   1167         if (!isEnabledInternal()) return false;
   1168 
   1169         return setDevicePropertyBooleanNative(
   1170                 getObjectPathFromAddress(address), "Trusted", value ? 1 : 0);
   1171     }
   1172 
   1173     /**
   1174      * Gets the remote device trust state as boolean.
   1175      * Note: this value may be
   1176      * retrieved from cache if we retrieved the data before *
   1177      *
   1178      * @return boolean to indicate trusted or untrusted state
   1179      */
   1180     public synchronized boolean getTrustState(String address) {
   1181         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   1182             mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   1183             return false;
   1184         }
   1185 
   1186         String val = mDeviceProperties.getProperty(address, "Trusted");
   1187         if (val == null) {
   1188             return false;
   1189         } else {
   1190             return val.equals("true");
   1191         }
   1192     }
   1193 
   1194     /**
   1195      * Gets the remote major, minor classes encoded as a 32-bit
   1196      * integer.
   1197      *
   1198      * Note: this value is retrieved from cache, because we get it during
   1199      *       remote-device discovery.
   1200      *
   1201      * @return 32-bit integer encoding the remote major, minor, and service
   1202      *         classes.
   1203      */
   1204     public synchronized int getRemoteClass(String address) {
   1205         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   1206             mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   1207             return BluetoothClass.ERROR;
   1208         }
   1209         String val = mDeviceProperties.getProperty(address, "Class");
   1210         if (val == null)
   1211             return BluetoothClass.ERROR;
   1212         else {
   1213             return Integer.valueOf(val);
   1214         }
   1215     }
   1216 
   1217 
   1218     /**
   1219      * Gets the UUIDs supported by the remote device
   1220      *
   1221      * @return array of 128bit ParcelUuids
   1222      */
   1223     public synchronized ParcelUuid[] getRemoteUuids(String address) {
   1224         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   1225         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   1226             return null;
   1227         }
   1228         return getUuidFromCache(address);
   1229     }
   1230 
   1231     ParcelUuid[] getUuidFromCache(String address) {
   1232         String value = mDeviceProperties.getProperty(address, "UUIDs");
   1233         if (value == null) return null;
   1234 
   1235         String[] uuidStrings = null;
   1236         // The UUIDs are stored as a "," separated string.
   1237         uuidStrings = value.split(",");
   1238         ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
   1239 
   1240         for (int i = 0; i < uuidStrings.length; i++) {
   1241             uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
   1242         }
   1243         return uuids;
   1244     }
   1245 
   1246     /**
   1247      * Connect and fetch new UUID's using SDP.
   1248      * The UUID's found are broadcast as intents.
   1249      * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
   1250      * a given uuid.
   1251      * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
   1252      * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
   1253      * callback and broadcast intents.
   1254      */
   1255     public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
   1256             IBluetoothCallback callback) {
   1257         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   1258         if (!isEnabledInternal()) return false;
   1259 
   1260         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   1261             return false;
   1262         }
   1263 
   1264         RemoteService service = new RemoteService(address, uuid);
   1265         if (uuid != null && mUuidCallbackTracker.get(service) != null) {
   1266             // An SDP query for this address & uuid is already in progress
   1267             // Do not add this callback for the uuid
   1268             return false;
   1269         }
   1270 
   1271         if (mUuidIntentTracker.contains(address)) {
   1272             // An SDP query for this address is already in progress
   1273             // Add this uuid onto the in-progress SDP query
   1274             if (uuid != null) {
   1275                 mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
   1276             }
   1277             return true;
   1278         }
   1279 
   1280         // If the device is already created, we will
   1281         // do the SDP on the callback of createDeviceNative.
   1282         boolean ret= createDeviceNative(address);
   1283 
   1284         mUuidIntentTracker.add(address);
   1285         if (uuid != null) {
   1286             mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
   1287         }
   1288 
   1289         Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
   1290         message.obj = address;
   1291         mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
   1292         return ret;
   1293     }
   1294 
   1295     /**
   1296      * Gets the rfcomm channel associated with the UUID.
   1297      * Pulls records from the cache only.
   1298      *
   1299      * @param address Address of the remote device
   1300      * @param uuid ParcelUuid of the service attribute
   1301      *
   1302      * @return rfcomm channel associated with the service attribute
   1303      *         -1 on error
   1304      */
   1305     public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
   1306         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   1307         if (!isEnabledInternal()) return -1;
   1308 
   1309         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   1310             return BluetoothDevice.ERROR;
   1311         }
   1312         // Check if we are recovering from a crash.
   1313         if (mDeviceProperties.isEmpty()) {
   1314             if (mDeviceProperties.updateCache(address) == null)
   1315                 return -1;
   1316         }
   1317 
   1318         Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
   1319         if (value != null && value.containsKey(uuid))
   1320             return value.get(uuid);
   1321         return -1;
   1322     }
   1323 
   1324     public synchronized boolean setPin(String address, byte[] pin) {
   1325         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   1326                                                 "Need BLUETOOTH_ADMIN permission");
   1327         if (!isEnabledInternal()) return false;
   1328 
   1329         if (pin == null || pin.length <= 0 || pin.length > 16 ||
   1330             !BluetoothAdapter.checkBluetoothAddress(address)) {
   1331             return false;
   1332         }
   1333         address = address.toUpperCase();
   1334         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
   1335         if (data == null) {
   1336             Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
   1337                   "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
   1338                   " or by bluez.\n");
   1339             return false;
   1340         }
   1341         // bluez API wants pin as a string
   1342         String pinString;
   1343         try {
   1344             pinString = new String(pin, "UTF8");
   1345         } catch (UnsupportedEncodingException uee) {
   1346             Log.e(TAG, "UTF8 not supported?!?");
   1347             return false;
   1348         }
   1349         return setPinNative(address, pinString, data.intValue());
   1350     }
   1351 
   1352     public synchronized boolean setPasskey(String address, int passkey) {
   1353         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   1354                                                 "Need BLUETOOTH_ADMIN permission");
   1355         if (!isEnabledInternal()) return false;
   1356 
   1357         if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
   1358             return false;
   1359         }
   1360         address = address.toUpperCase();
   1361         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
   1362         if (data == null) {
   1363             Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
   1364                   "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
   1365                   " or by bluez.\n");
   1366             return false;
   1367         }
   1368         return setPasskeyNative(address, passkey, data.intValue());
   1369     }
   1370 
   1371     public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
   1372         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   1373                                                 "Need BLUETOOTH_ADMIN permission");
   1374         if (!isEnabledInternal()) return false;
   1375 
   1376         address = address.toUpperCase();
   1377         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
   1378         if (data == null) {
   1379             Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
   1380                   "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
   1381                   " or by bluez.\n");
   1382             return false;
   1383         }
   1384         return setPairingConfirmationNative(address, confirm, data.intValue());
   1385     }
   1386 
   1387     public synchronized boolean setRemoteOutOfBandData(String address) {
   1388         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   1389                                                 "Need BLUETOOTH_ADMIN permission");
   1390         if (!isEnabledInternal()) return false;
   1391         address = address.toUpperCase();
   1392         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
   1393         if (data == null) {
   1394             Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " +
   1395                   "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
   1396                   " or by bluez.\n");
   1397             return false;
   1398         }
   1399 
   1400         Pair<byte[], byte[]> val = mDeviceOobData.get(address);
   1401         byte[] hash, randomizer;
   1402         if (val == null) {
   1403             // TODO: check what should be passed in this case.
   1404             hash = new byte[16];
   1405             randomizer = new byte[16];
   1406         } else {
   1407             hash = val.first;
   1408             randomizer = val.second;
   1409         }
   1410         return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue());
   1411     }
   1412 
   1413     public synchronized boolean cancelPairingUserInput(String address) {
   1414         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   1415                                                 "Need BLUETOOTH_ADMIN permission");
   1416         if (!isEnabledInternal()) return false;
   1417 
   1418         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   1419             return false;
   1420         }
   1421         mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
   1422                 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
   1423         address = address.toUpperCase();
   1424         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
   1425         if (data == null) {
   1426             Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
   1427                 "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
   1428                 "by the remote or by bluez.\n");
   1429             return false;
   1430         }
   1431         return cancelPairingUserInputNative(address, data.intValue());
   1432     }
   1433 
   1434     /*package*/ void updateDeviceServiceChannelCache(String address) {
   1435         if (DBG) Log.d(TAG, "updateDeviceServiceChannelCache(" + address + ")");
   1436 
   1437         // We are storing the rfcomm channel numbers only for the uuids
   1438         // we are interested in.
   1439         ParcelUuid[] deviceUuids = getRemoteUuids(address);
   1440 
   1441         ArrayList<ParcelUuid> applicationUuids = new ArrayList<ParcelUuid>();
   1442 
   1443         synchronized (this) {
   1444             for (RemoteService service : mUuidCallbackTracker.keySet()) {
   1445                 if (service.address.equals(address)) {
   1446                     applicationUuids.add(service.uuid);
   1447                 }
   1448             }
   1449         }
   1450 
   1451         Map <ParcelUuid, Integer> uuidToChannelMap = new HashMap<ParcelUuid, Integer>();
   1452 
   1453         // Retrieve RFCOMM channel for default uuids
   1454         for (ParcelUuid uuid : RFCOMM_UUIDS) {
   1455             if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
   1456                 int channel = getDeviceServiceChannelForUuid(address, uuid);
   1457                 uuidToChannelMap.put(uuid, channel);
   1458                 if (DBG) Log.d(TAG, "\tuuid(system): " + uuid + " " + channel);
   1459             }
   1460         }
   1461         // Retrieve RFCOMM channel for application requested uuids
   1462         for (ParcelUuid uuid : applicationUuids) {
   1463             if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
   1464                 int channel = getDeviceServiceChannelForUuid(address, uuid);
   1465                 uuidToChannelMap.put(uuid, channel);
   1466                 if (DBG) Log.d(TAG, "\tuuid(application): " + uuid + " " + channel);
   1467             }
   1468         }
   1469 
   1470         synchronized (this) {
   1471             // Make application callbacks
   1472             for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
   1473                     iter.hasNext();) {
   1474                 RemoteService service = iter.next();
   1475                 if (service.address.equals(address)) {
   1476                     if (uuidToChannelMap.containsKey(service.uuid)) {
   1477                         int channel = uuidToChannelMap.get(service.uuid);
   1478 
   1479                         if (DBG) Log.d(TAG, "Making callback for " + service.uuid +
   1480                                     " with result " + channel);
   1481                         IBluetoothCallback callback = mUuidCallbackTracker.get(service);
   1482                         if (callback != null) {
   1483                             try {
   1484                                 callback.onRfcommChannelFound(channel);
   1485                             } catch (RemoteException e) {Log.e(TAG, "", e);}
   1486                         }
   1487 
   1488                         iter.remove();
   1489                     }
   1490                 }
   1491             }
   1492 
   1493             // Update cache
   1494             mDeviceServiceChannelCache.put(address, uuidToChannelMap);
   1495         }
   1496     }
   1497 
   1498     private int getDeviceServiceChannelForUuid(String address,
   1499             ParcelUuid uuid) {
   1500         return getDeviceServiceChannelNative(getObjectPathFromAddress(address),
   1501                 uuid.toString(), 0x0004);
   1502     }
   1503 
   1504     /**
   1505      * b is a handle to a Binder instance, so that this service can be notified
   1506      * for Applications that terminate unexpectedly, to clean there service
   1507      * records
   1508      */
   1509     public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
   1510             int channel, IBinder b) {
   1511         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   1512         if (!isEnabledInternal()) return -1;
   1513 
   1514         if (serviceName == null || uuid == null || channel < 1 ||
   1515                 channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
   1516             return -1;
   1517         }
   1518         if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
   1519             Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
   1520             return -1;
   1521         }
   1522         int handle = addRfcommServiceRecordNative(serviceName,
   1523                 uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
   1524                 (short)channel);
   1525         if (DBG) Log.d(TAG, "new handle " + Integer.toHexString(handle));
   1526         if (handle == -1) {
   1527             return -1;
   1528         }
   1529 
   1530         int pid = Binder.getCallingPid();
   1531         mServiceRecordToPid.put(new Integer(handle), new Pair<Integer, IBinder>(pid, b));
   1532         try {
   1533             b.linkToDeath(new Reaper(handle, pid, RFCOMM_RECORD_REAPER), 0);
   1534         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1535         return handle;
   1536     }
   1537 
   1538     public void removeServiceRecord(int handle) {
   1539         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   1540                                                 "Need BLUETOOTH permission");
   1541         // Since this is a binder call check if Bluetooth is off
   1542         if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return;
   1543         Message message = mHandler.obtainMessage(MESSAGE_REMOVE_SERVICE_RECORD);
   1544         message.obj = new Pair<Integer, Integer>(handle, Binder.getCallingPid());
   1545         mHandler.sendMessage(message);
   1546     }
   1547 
   1548     private synchronized void checkAndRemoveRecord(int handle, int pid) {
   1549         Pair<Integer, IBinder> pidPair = mServiceRecordToPid.get(handle);
   1550         if (pidPair != null && pid == pidPair.first) {
   1551             if (DBG) Log.d(TAG, "Removing service record " +
   1552                 Integer.toHexString(handle) + " for pid " + pid);
   1553             mServiceRecordToPid.remove(handle);
   1554             removeServiceRecordNative(handle);
   1555         }
   1556     }
   1557 
   1558     private class Reaper implements IBinder.DeathRecipient {
   1559         int mPid;
   1560         int mHandle;
   1561         int mType;
   1562 
   1563         Reaper(int handle, int pid, int type) {
   1564             mPid = pid;
   1565             mHandle = handle;
   1566             mType = type;
   1567         }
   1568 
   1569         Reaper(int pid, int type) {
   1570             mPid = pid;
   1571             mType = type;
   1572         }
   1573 
   1574         @Override
   1575         public void binderDied() {
   1576             synchronized (BluetoothService.this) {
   1577                 if (DBG) Log.d(TAG, "Tracked app " + mPid + " died" + "Type:" + mType);
   1578                 if (mType == RFCOMM_RECORD_REAPER) {
   1579                     checkAndRemoveRecord(mHandle, mPid);
   1580                 } else if (mType == STATE_CHANGE_REAPER) {
   1581                     mStateChangeTracker.remove(mPid);
   1582                 }
   1583             }
   1584         }
   1585     }
   1586 
   1587 
   1588     @Override
   1589     public boolean changeApplicationBluetoothState(boolean on,
   1590             IBluetoothStateChangeCallback callback, IBinder binder) {
   1591         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   1592 
   1593         int pid = Binder.getCallingPid();
   1594         //mStateChangeTracker is a synchronized map
   1595         if (!mStateChangeTracker.containsKey(pid)) {
   1596             if (on) {
   1597                 mStateChangeTracker.put(pid, callback);
   1598             } else {
   1599                 return false;
   1600             }
   1601         } else if (!on) {
   1602             mStateChangeTracker.remove(pid);
   1603         }
   1604 
   1605         if (binder != null) {
   1606             try {
   1607                 binder.linkToDeath(new Reaper(pid, STATE_CHANGE_REAPER), 0);
   1608             } catch (RemoteException e) {
   1609                 Log.e(TAG, "", e);
   1610                 return false;
   1611             }
   1612         }
   1613 
   1614         int type;
   1615         if (on) {
   1616             type = BluetoothAdapterStateMachine.PER_PROCESS_TURN_ON;
   1617         } else {
   1618             type = BluetoothAdapterStateMachine.PER_PROCESS_TURN_OFF;
   1619         }
   1620 
   1621         mBluetoothState.sendMessage(type, callback);
   1622         return true;
   1623     }
   1624 
   1625     boolean isApplicationStateChangeTrackerEmpty() {
   1626         return mStateChangeTracker.isEmpty();
   1627     }
   1628 
   1629     void clearApplicationStateChangeTracker() {
   1630         mStateChangeTracker.clear();
   1631     }
   1632 
   1633     Collection<IBluetoothStateChangeCallback> getApplicationStateChangeCallbacks() {
   1634         return mStateChangeTracker.values();
   1635     }
   1636 
   1637     int getNumberOfApplicationStateChangeTrackers() {
   1638         return mStateChangeTracker.size();
   1639     }
   1640 
   1641     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
   1642         @Override
   1643         public void onReceive(Context context, Intent intent) {
   1644             if (intent == null) return;
   1645 
   1646             String action = intent.getAction();
   1647             if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
   1648                 ContentResolver resolver = context.getContentResolver();
   1649                 // Query the airplane mode from Settings.System just to make sure that
   1650                 // some random app is not sending this intent and disabling bluetooth
   1651                 if (isAirplaneModeOn()) {
   1652                     mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_ON);
   1653                 } else {
   1654                     mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_OFF);
   1655                 }
   1656             } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
   1657                 int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
   1658                         Intent.EXTRA_DOCK_STATE_UNDOCKED);
   1659                 if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
   1660                 if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
   1661                     mDockAddress = null;
   1662                     mDockPin = null;
   1663                 } else {
   1664                     SharedPreferences.Editor editor =
   1665                         mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
   1666                                 mContext.MODE_PRIVATE).edit();
   1667                     editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
   1668                     editor.apply();
   1669                 }
   1670             }
   1671         }
   1672     };
   1673 
   1674     private void registerForAirplaneMode(IntentFilter filter) {
   1675         final ContentResolver resolver = mContext.getContentResolver();
   1676         final String airplaneModeRadios = Settings.System.getString(resolver,
   1677                 Settings.System.AIRPLANE_MODE_RADIOS);
   1678         final String toggleableRadios = Settings.System.getString(resolver,
   1679                 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
   1680 
   1681         mIsAirplaneSensitive = airplaneModeRadios == null ? true :
   1682                 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
   1683         mIsAirplaneToggleable = toggleableRadios == null ? false :
   1684                 toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
   1685 
   1686         if (mIsAirplaneSensitive) {
   1687             filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
   1688         }
   1689     }
   1690 
   1691     /* Returns true if airplane mode is currently on */
   1692     private final boolean isAirplaneModeOn() {
   1693         return Settings.System.getInt(mContext.getContentResolver(),
   1694                 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
   1695     }
   1696 
   1697     /* Broadcast the Uuid intent */
   1698     /*package*/ synchronized void sendUuidIntent(String address) {
   1699         ParcelUuid[] uuid = getUuidFromCache(address);
   1700         Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
   1701         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
   1702         intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
   1703         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
   1704         mUuidIntentTracker.remove(address);
   1705     }
   1706 
   1707     /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
   1708         for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
   1709                 iter.hasNext();) {
   1710             RemoteService service = iter.next();
   1711             if (service.address.equals(address)) {
   1712                 if (DBG) Log.d(TAG, "Cleaning up failed UUID channel lookup: "
   1713                     + service.address + " " + service.uuid);
   1714                 IBluetoothCallback callback = mUuidCallbackTracker.get(service);
   1715                 if (callback != null) {
   1716                     try {
   1717                         callback.onRfcommChannelFound(-1);
   1718                     } catch (RemoteException e) {Log.e(TAG, "", e);}
   1719                 }
   1720 
   1721                 iter.remove();
   1722             }
   1723         }
   1724     }
   1725 
   1726     @Override
   1727     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1728         if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) {
   1729             return;
   1730         }
   1731 
   1732         pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
   1733         pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
   1734 
   1735         pw.println("Local address = " + getAddress());
   1736         pw.println("Local name = " + getName());
   1737         pw.println("isDiscovering() = " + isDiscovering());
   1738 
   1739         mAdapter.getProfileProxy(mContext,
   1740                                  mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
   1741         mAdapter.getProfileProxy(mContext,
   1742                 mBluetoothProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
   1743         mAdapter.getProfileProxy(mContext,
   1744                 mBluetoothProfileServiceListener, BluetoothProfile.PAN);
   1745 
   1746         dumpKnownDevices(pw);
   1747         dumpAclConnectedDevices(pw);
   1748         dumpHeadsetService(pw);
   1749         dumpInputDeviceProfile(pw);
   1750         dumpPanProfile(pw);
   1751         dumpApplicationServiceRecords(pw);
   1752         dumpProfileState(pw);
   1753     }
   1754 
   1755     private void dumpProfileState(PrintWriter pw) {
   1756         pw.println("\n--Profile State dump--");
   1757         pw.println("\n Headset profile state:" +
   1758                 mAdapter.getProfileConnectionState(BluetoothProfile.HEADSET));
   1759         pw.println("\n A2dp profile state:" +
   1760                 mAdapter.getProfileConnectionState(BluetoothProfile.A2DP));
   1761         pw.println("\n HID profile state:" +
   1762                 mAdapter.getProfileConnectionState(BluetoothProfile.INPUT_DEVICE));
   1763         pw.println("\n PAN profile state:" +
   1764                 mAdapter.getProfileConnectionState(BluetoothProfile.PAN));
   1765     }
   1766 
   1767     private void dumpHeadsetService(PrintWriter pw) {
   1768         pw.println("\n--Headset Service--");
   1769         if (mBluetoothHeadset != null) {
   1770             List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
   1771             if (deviceList.size() == 0) {
   1772                 pw.println("No headsets connected");
   1773             } else {
   1774                 BluetoothDevice device = deviceList.get(0);
   1775                 pw.println("\ngetConnectedDevices[0] = " + device);
   1776                 dumpHeadsetConnectionState(pw, device);
   1777                 pw.println("getBatteryUsageHint() = " +
   1778                              mBluetoothHeadset.getBatteryUsageHint(device));
   1779             }
   1780 
   1781             deviceList.clear();
   1782             deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
   1783                      BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
   1784             pw.println("--Connected and Disconnected Headsets");
   1785             for (BluetoothDevice device: deviceList) {
   1786                 pw.println(device);
   1787                 if (mBluetoothHeadset.isAudioConnected(device)) {
   1788                     pw.println("SCO audio connected to device:" + device);
   1789                 }
   1790             }
   1791         }
   1792         mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
   1793     }
   1794 
   1795     private void dumpInputDeviceProfile(PrintWriter pw) {
   1796         pw.println("\n--Bluetooth Service- Input Device Profile");
   1797         if (mInputDevice != null) {
   1798             List<BluetoothDevice> deviceList = mInputDevice.getConnectedDevices();
   1799             if (deviceList.size() == 0) {
   1800                 pw.println("No input devices connected");
   1801             } else {
   1802                 pw.println("Number of connected devices:" + deviceList.size());
   1803                 BluetoothDevice device = deviceList.get(0);
   1804                 pw.println("getConnectedDevices[0] = " + device);
   1805                 pw.println("Priority of Connected device = " + mInputDevice.getPriority(device));
   1806 
   1807                 switch (mInputDevice.getConnectionState(device)) {
   1808                     case BluetoothInputDevice.STATE_CONNECTING:
   1809                         pw.println("getConnectionState() = STATE_CONNECTING");
   1810                         break;
   1811                     case BluetoothInputDevice.STATE_CONNECTED:
   1812                         pw.println("getConnectionState() = STATE_CONNECTED");
   1813                         break;
   1814                     case BluetoothInputDevice.STATE_DISCONNECTING:
   1815                         pw.println("getConnectionState() = STATE_DISCONNECTING");
   1816                         break;
   1817                 }
   1818             }
   1819             deviceList.clear();
   1820             deviceList = mInputDevice.getDevicesMatchingConnectionStates(new int[] {
   1821                      BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
   1822             pw.println("--Connected and Disconnected input devices");
   1823             for (BluetoothDevice device: deviceList) {
   1824                 pw.println(device);
   1825             }
   1826         }
   1827         mAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mBluetoothHeadset);
   1828     }
   1829 
   1830     private void dumpPanProfile(PrintWriter pw) {
   1831         pw.println("\n--Bluetooth Service- Pan Profile");
   1832         if (mPan != null) {
   1833             List<BluetoothDevice> deviceList = mPan.getConnectedDevices();
   1834             if (deviceList.size() == 0) {
   1835                 pw.println("No Pan devices connected");
   1836             } else {
   1837                 pw.println("Number of connected devices:" + deviceList.size());
   1838                 BluetoothDevice device = deviceList.get(0);
   1839                 pw.println("getConnectedDevices[0] = " + device);
   1840 
   1841                 switch (mPan.getConnectionState(device)) {
   1842                     case BluetoothInputDevice.STATE_CONNECTING:
   1843                         pw.println("getConnectionState() = STATE_CONNECTING");
   1844                         break;
   1845                     case BluetoothInputDevice.STATE_CONNECTED:
   1846                         pw.println("getConnectionState() = STATE_CONNECTED");
   1847                         break;
   1848                     case BluetoothInputDevice.STATE_DISCONNECTING:
   1849                         pw.println("getConnectionState() = STATE_DISCONNECTING");
   1850                         break;
   1851                 }
   1852             }
   1853             deviceList.clear();
   1854             deviceList = mPan.getDevicesMatchingConnectionStates(new int[] {
   1855                      BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
   1856             pw.println("--Connected and Disconnected Pan devices");
   1857             for (BluetoothDevice device: deviceList) {
   1858                 pw.println(device);
   1859             }
   1860         }
   1861     }
   1862 
   1863     private void dumpHeadsetConnectionState(PrintWriter pw,
   1864             BluetoothDevice device) {
   1865         switch (mBluetoothHeadset.getConnectionState(device)) {
   1866             case BluetoothHeadset.STATE_CONNECTING:
   1867                 pw.println("getConnectionState() = STATE_CONNECTING");
   1868                 break;
   1869             case BluetoothHeadset.STATE_CONNECTED:
   1870                 pw.println("getConnectionState() = STATE_CONNECTED");
   1871                 break;
   1872             case BluetoothHeadset.STATE_DISCONNECTING:
   1873                 pw.println("getConnectionState() = STATE_DISCONNECTING");
   1874                 break;
   1875             case BluetoothHeadset.STATE_AUDIO_CONNECTED:
   1876                 pw.println("getConnectionState() = STATE_AUDIO_CONNECTED");
   1877                 break;
   1878         }
   1879     }
   1880 
   1881     private void dumpApplicationServiceRecords(PrintWriter pw) {
   1882         pw.println("\n--Application Service Records--");
   1883         for (Integer handle : mServiceRecordToPid.keySet()) {
   1884             Integer pid = mServiceRecordToPid.get(handle).first;
   1885             pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
   1886         }
   1887         mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset);
   1888     }
   1889 
   1890     private void dumpAclConnectedDevices(PrintWriter pw) {
   1891         String[] devicesObjectPath = getKnownDevices();
   1892         pw.println("\n--ACL connected devices--");
   1893         if (devicesObjectPath != null) {
   1894             for (String device : devicesObjectPath) {
   1895                 pw.println(getAddressFromObjectPath(device));
   1896             }
   1897         }
   1898     }
   1899 
   1900     private void dumpKnownDevices(PrintWriter pw) {
   1901         pw.println("\n--Known devices--");
   1902         for (String address : mDeviceProperties.keySet()) {
   1903             int bondState = mBondState.getBondState(address);
   1904             pw.printf("%s %10s (%d) %s\n", address,
   1905                        toBondStateString(bondState),
   1906                        mBondState.getAttempt(address),
   1907                        getRemoteName(address));
   1908 
   1909             Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
   1910             if (uuidChannels == null) {
   1911                 pw.println("\tuuids = null");
   1912             } else {
   1913                 for (ParcelUuid uuid : uuidChannels.keySet()) {
   1914                     Integer channel = uuidChannels.get(uuid);
   1915                     if (channel == null) {
   1916                         pw.println("\t" + uuid);
   1917                     } else {
   1918                         pw.println("\t" + uuid + " RFCOMM channel = " + channel);
   1919                     }
   1920                 }
   1921             }
   1922             for (RemoteService service : mUuidCallbackTracker.keySet()) {
   1923                 if (service.address.equals(address)) {
   1924                     pw.println("\tPENDING CALLBACK: " + service.uuid);
   1925                 }
   1926             }
   1927         }
   1928     }
   1929 
   1930     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
   1931         new BluetoothProfile.ServiceListener() {
   1932         public void onServiceConnected(int profile, BluetoothProfile proxy) {
   1933             if (profile == BluetoothProfile.HEADSET) {
   1934                 mBluetoothHeadset = (BluetoothHeadset) proxy;
   1935             } else if (profile == BluetoothProfile.INPUT_DEVICE) {
   1936                 mInputDevice = (BluetoothInputDevice) proxy;
   1937             } else if (profile == BluetoothProfile.PAN) {
   1938                 mPan = (BluetoothPan) proxy;
   1939             }
   1940         }
   1941         public void onServiceDisconnected(int profile) {
   1942             if (profile == BluetoothProfile.HEADSET) {
   1943                 mBluetoothHeadset = null;
   1944             } else if (profile == BluetoothProfile.INPUT_DEVICE) {
   1945                 mInputDevice = null;
   1946             } else if (profile == BluetoothProfile.PAN) {
   1947                 mPan = null;
   1948             }
   1949         }
   1950     };
   1951 
   1952     /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
   1953         if (pairable && discoverable)
   1954             return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
   1955         else if (pairable && !discoverable)
   1956             return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
   1957         else
   1958             return BluetoothAdapter.SCAN_MODE_NONE;
   1959     }
   1960 
   1961     /* package */ static String scanModeToBluezString(int mode) {
   1962         switch (mode) {
   1963         case BluetoothAdapter.SCAN_MODE_NONE:
   1964             return "off";
   1965         case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
   1966             return "connectable";
   1967         case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
   1968             return "discoverable";
   1969         }
   1970         return null;
   1971     }
   1972 
   1973     /*package*/ String getAddressFromObjectPath(String objectPath) {
   1974         String adapterObjectPath = mAdapterProperties.getObjectPath();
   1975         if (adapterObjectPath == null || objectPath == null) {
   1976             Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
   1977                     "  or deviceObjectPath:" + objectPath + " is null");
   1978             return null;
   1979         }
   1980         if (!objectPath.startsWith(adapterObjectPath)) {
   1981             Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
   1982                     "  is not a prefix of deviceObjectPath:" + objectPath +
   1983                     "bluetoothd crashed ?");
   1984             return null;
   1985         }
   1986         String address = objectPath.substring(adapterObjectPath.length());
   1987         if (address != null) return address.replace('_', ':');
   1988 
   1989         Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
   1990         return null;
   1991     }
   1992 
   1993     /*package*/ String getObjectPathFromAddress(String address) {
   1994         String path = mAdapterProperties.getObjectPath();
   1995         if (path == null) {
   1996             Log.e(TAG, "Error: Object Path is null");
   1997             return null;
   1998         }
   1999         path = path + address.replace(":", "_");
   2000         return path;
   2001     }
   2002 
   2003     /*package */ void setLinkTimeout(String address, int num_slots) {
   2004         String path = getObjectPathFromAddress(address);
   2005         boolean result = setLinkTimeoutNative(path, num_slots);
   2006 
   2007         if (!result) Log.d(TAG, "Set Link Timeout to " + num_slots + " slots failed");
   2008     }
   2009 
   2010     /**** Handlers for PAN  Profile ****/
   2011     // TODO: This needs to be converted to a state machine.
   2012 
   2013     public boolean isTetheringOn() {
   2014         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   2015         synchronized (mBluetoothPanProfileHandler) {
   2016             return mBluetoothPanProfileHandler.isTetheringOn();
   2017         }
   2018     }
   2019 
   2020     /*package*/boolean allowIncomingTethering() {
   2021         synchronized (mBluetoothPanProfileHandler) {
   2022             return mBluetoothPanProfileHandler.allowIncomingTethering();
   2023         }
   2024     }
   2025 
   2026     public void setBluetoothTethering(boolean value) {
   2027         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   2028         synchronized (mBluetoothPanProfileHandler) {
   2029             mBluetoothPanProfileHandler.setBluetoothTethering(value);
   2030         }
   2031     }
   2032 
   2033     public int getPanDeviceConnectionState(BluetoothDevice device) {
   2034         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   2035         synchronized (mBluetoothPanProfileHandler) {
   2036             return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device);
   2037         }
   2038     }
   2039 
   2040     public boolean connectPanDevice(BluetoothDevice device) {
   2041         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   2042             "Need BLUETOOTH_ADMIN permission");
   2043         synchronized (mBluetoothPanProfileHandler) {
   2044             return mBluetoothPanProfileHandler.connectPanDevice(device);
   2045         }
   2046     }
   2047 
   2048     public List<BluetoothDevice> getConnectedPanDevices() {
   2049         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   2050         synchronized (mBluetoothPanProfileHandler) {
   2051             return mBluetoothPanProfileHandler.getConnectedPanDevices();
   2052         }
   2053     }
   2054 
   2055     public List<BluetoothDevice> getPanDevicesMatchingConnectionStates(
   2056             int[] states) {
   2057         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   2058         synchronized (mBluetoothPanProfileHandler) {
   2059             return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states);
   2060         }
   2061     }
   2062 
   2063     public boolean disconnectPanDevice(BluetoothDevice device) {
   2064         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   2065             "Need BLUETOOTH_ADMIN permission");
   2066         synchronized (mBluetoothPanProfileHandler) {
   2067             return mBluetoothPanProfileHandler.disconnectPanDevice(device);
   2068         }
   2069     }
   2070 
   2071     /*package*/void handlePanDeviceStateChange(BluetoothDevice device,
   2072                                                              String iface,
   2073                                                              int state,
   2074                                                              int role) {
   2075         synchronized (mBluetoothPanProfileHandler) {
   2076             mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, iface, state, role);
   2077         }
   2078     }
   2079 
   2080     /*package*/void handlePanDeviceStateChange(BluetoothDevice device,
   2081                                                              int state, int role) {
   2082         synchronized (mBluetoothPanProfileHandler) {
   2083             mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, null, state, role);
   2084         }
   2085     }
   2086 
   2087     /**** Handlers for Input Device Profile ****/
   2088     // This needs to be converted to state machine
   2089 
   2090     public boolean connectInputDevice(BluetoothDevice device) {
   2091         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   2092                                                 "Need BLUETOOTH_ADMIN permission");
   2093         BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
   2094         synchronized (mBluetoothInputProfileHandler) {
   2095             return mBluetoothInputProfileHandler.connectInputDevice(device, state);
   2096         }
   2097     }
   2098 
   2099     public boolean connectInputDeviceInternal(BluetoothDevice device) {
   2100         synchronized (mBluetoothInputProfileHandler) {
   2101             return mBluetoothInputProfileHandler.connectInputDeviceInternal(device);
   2102         }
   2103     }
   2104 
   2105     public boolean disconnectInputDevice(BluetoothDevice device) {
   2106         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   2107                                                 "Need BLUETOOTH_ADMIN permission");
   2108         BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
   2109         synchronized (mBluetoothInputProfileHandler) {
   2110             return mBluetoothInputProfileHandler.disconnectInputDevice(device, state);
   2111         }
   2112     }
   2113 
   2114     public boolean disconnectInputDeviceInternal(BluetoothDevice device) {
   2115         synchronized (mBluetoothInputProfileHandler) {
   2116             return mBluetoothInputProfileHandler.disconnectInputDeviceInternal(device);
   2117         }
   2118     }
   2119 
   2120     public int getInputDeviceConnectionState(BluetoothDevice device) {
   2121         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   2122         synchronized (mBluetoothInputProfileHandler) {
   2123             return mBluetoothInputProfileHandler.getInputDeviceConnectionState(device);
   2124         }
   2125     }
   2126 
   2127     public List<BluetoothDevice> getConnectedInputDevices() {
   2128         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   2129         synchronized (mBluetoothInputProfileHandler) {
   2130             return mBluetoothInputProfileHandler.getConnectedInputDevices();
   2131         }
   2132     }
   2133 
   2134     public List<BluetoothDevice> getInputDevicesMatchingConnectionStates(
   2135             int[] states) {
   2136         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   2137         synchronized (mBluetoothInputProfileHandler) {
   2138             return mBluetoothInputProfileHandler.getInputDevicesMatchingConnectionStates(states);
   2139         }
   2140     }
   2141 
   2142 
   2143     public int getInputDevicePriority(BluetoothDevice device) {
   2144         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   2145         synchronized (mBluetoothInputProfileHandler) {
   2146             return mBluetoothInputProfileHandler.getInputDevicePriority(device);
   2147         }
   2148     }
   2149 
   2150     public boolean setInputDevicePriority(BluetoothDevice device, int priority) {
   2151         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   2152                                                 "Need BLUETOOTH_ADMIN permission");
   2153         synchronized (mBluetoothInputProfileHandler) {
   2154             return mBluetoothInputProfileHandler.setInputDevicePriority(device, priority);
   2155         }
   2156     }
   2157 
   2158     /**
   2159      * Handle incoming profile acceptance for profiles handled by Bluetooth Service,
   2160      * currently PAN and HID. This also is the catch all for all rejections for profiles
   2161      * that is not supported.
   2162      *
   2163      * @param device - Bluetooth Device
   2164      * @param allow - true / false
   2165      * @return
   2166      */
   2167     public boolean allowIncomingProfileConnect(BluetoothDevice device, boolean allow) {
   2168         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
   2169                                                 "Need BLUETOOTH_ADMIN permission");
   2170         String address = device.getAddress();
   2171         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   2172             return false;
   2173         }
   2174 
   2175         Integer data = getAuthorizationAgentRequestData(address);
   2176         if (data == null) {
   2177             Log.w(TAG, "allowIncomingProfileConnect(" + device +
   2178                   ") called but no native data available");
   2179             return false;
   2180         }
   2181         if (DBG) log("allowIncomingProfileConnect: " + device + " : " + allow + " : " + data);
   2182         return setAuthorizationNative(address, allow, data.intValue());
   2183     }
   2184 
   2185     /*package*/List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
   2186         synchronized (mBluetoothInputProfileHandler) {
   2187             return mBluetoothInputProfileHandler.lookupInputDevicesMatchingStates(states);
   2188         }
   2189     }
   2190 
   2191     /*package*/void handleInputDevicePropertyChange(String address, boolean connected) {
   2192         synchronized (mBluetoothInputProfileHandler) {
   2193             mBluetoothInputProfileHandler.handleInputDevicePropertyChange(address, connected);
   2194         }
   2195     }
   2196 
   2197     /**** Handlers for Health Device Profile ****/
   2198     // TODO: All these need to be converted to a state machine.
   2199 
   2200     public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config,
   2201                                             IBluetoothHealthCallback callback) {
   2202         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   2203                 "Need BLUETOOTH permission");
   2204         synchronized (mBluetoothHealthProfileHandler) {
   2205                 return mBluetoothHealthProfileHandler.registerAppConfiguration(config, callback);
   2206         }
   2207     }
   2208 
   2209     public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
   2210         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   2211                 "Need BLUETOOTH permission");
   2212         synchronized (mBluetoothHealthProfileHandler) {
   2213                 return mBluetoothHealthProfileHandler.unregisterAppConfiguration(config);
   2214         }
   2215     }
   2216 
   2217 
   2218     public boolean connectChannelToSource(BluetoothDevice device,
   2219             BluetoothHealthAppConfiguration config) {
   2220         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   2221                 "Need BLUETOOTH permission");
   2222         synchronized (mBluetoothHealthProfileHandler) {
   2223             return mBluetoothHealthProfileHandler.connectChannelToSource(device,
   2224                     config);
   2225         }
   2226     }
   2227 
   2228     public boolean connectChannelToSink(BluetoothDevice device,
   2229             BluetoothHealthAppConfiguration config, int channelType) {
   2230         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   2231                                                 "Need BLUETOOTH permission");
   2232         synchronized (mBluetoothHealthProfileHandler) {
   2233             return mBluetoothHealthProfileHandler.connectChannel(device, config,
   2234                     channelType);
   2235         }
   2236     }
   2237 
   2238     public boolean disconnectChannel(BluetoothDevice device,
   2239             BluetoothHealthAppConfiguration config, int id) {
   2240         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   2241                 "Need BLUETOOTH permission");
   2242         synchronized (mBluetoothHealthProfileHandler) {
   2243             return mBluetoothHealthProfileHandler.disconnectChannel(device, config, id);
   2244         }
   2245     }
   2246 
   2247     public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
   2248             BluetoothHealthAppConfiguration config) {
   2249         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   2250                 "Need BLUETOOTH permission");
   2251         synchronized (mBluetoothHealthProfileHandler) {
   2252             return mBluetoothHealthProfileHandler.getMainChannelFd(device, config);
   2253         }
   2254     }
   2255 
   2256     /*package*/ void onHealthDevicePropertyChanged(String devicePath,
   2257             String channelPath) {
   2258         synchronized (mBluetoothHealthProfileHandler) {
   2259             mBluetoothHealthProfileHandler.onHealthDevicePropertyChanged(devicePath,
   2260                     channelPath);
   2261         }
   2262     }
   2263 
   2264     /*package*/ void onHealthDeviceChannelChanged(String devicePath,
   2265             String channelPath, boolean exists) {
   2266         synchronized(mBluetoothHealthProfileHandler) {
   2267             mBluetoothHealthProfileHandler.onHealthDeviceChannelChanged(devicePath,
   2268                     channelPath, exists);
   2269         }
   2270     }
   2271 
   2272     /*package*/ void onHealthDeviceChannelConnectionError(int channelCode,
   2273             int newState) {
   2274         synchronized(mBluetoothHealthProfileHandler) {
   2275             mBluetoothHealthProfileHandler.onHealthDeviceChannelConnectionError(channelCode,
   2276                                                                                 newState);
   2277         }
   2278     }
   2279 
   2280     public int getHealthDeviceConnectionState(BluetoothDevice device) {
   2281         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   2282                 "Need BLUETOOTH permission");
   2283         synchronized (mBluetoothHealthProfileHandler) {
   2284             return mBluetoothHealthProfileHandler.getHealthDeviceConnectionState(device);
   2285         }
   2286     }
   2287 
   2288     public List<BluetoothDevice> getConnectedHealthDevices() {
   2289         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   2290                 "Need BLUETOOTH permission");
   2291         synchronized (mBluetoothHealthProfileHandler) {
   2292             return mBluetoothHealthProfileHandler.getConnectedHealthDevices();
   2293         }
   2294     }
   2295 
   2296     public List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(
   2297             int[] states) {
   2298         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
   2299                 "Need BLUETOOTH permission");
   2300         synchronized (mBluetoothHealthProfileHandler) {
   2301             return mBluetoothHealthProfileHandler.
   2302                     getHealthDevicesMatchingConnectionStates(states);
   2303         }
   2304     }
   2305 
   2306     /*package*/boolean notifyIncomingHidConnection(String address) {
   2307         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
   2308         if (state == null) {
   2309             return false;
   2310         }
   2311         Message msg = new Message();
   2312         msg.what = BluetoothDeviceProfileState.CONNECT_HID_INCOMING;
   2313         state.sendMessage(msg);
   2314         return true;
   2315     }
   2316 
   2317     public boolean connectHeadset(String address) {
   2318         if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
   2319 
   2320         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
   2321         if (state != null) {
   2322             Message msg = new Message();
   2323             msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
   2324             msg.obj = state;
   2325             mHfpProfileState.sendMessage(msg);
   2326             return true;
   2327         }
   2328         return false;
   2329     }
   2330 
   2331     public boolean disconnectHeadset(String address) {
   2332         if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
   2333 
   2334         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
   2335         if (state != null) {
   2336             Message msg = new Message();
   2337             msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING;
   2338             msg.obj = state;
   2339             mHfpProfileState.sendMessage(msg);
   2340             return true;
   2341         }
   2342         return false;
   2343     }
   2344 
   2345     public boolean connectSink(String address) {
   2346         if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
   2347 
   2348         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
   2349         if (state != null) {
   2350             Message msg = new Message();
   2351             msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
   2352             msg.obj = state;
   2353             mA2dpProfileState.sendMessage(msg);
   2354             return true;
   2355         }
   2356         return false;
   2357     }
   2358 
   2359     public boolean disconnectSink(String address) {
   2360         if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
   2361 
   2362         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
   2363         if (state != null) {
   2364             Message msg = new Message();
   2365             msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING;
   2366             msg.obj = state;
   2367             mA2dpProfileState.sendMessage(msg);
   2368             return true;
   2369         }
   2370         return false;
   2371     }
   2372 
   2373     BluetoothDeviceProfileState addProfileState(String address, boolean setTrust) {
   2374         BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
   2375         if (state != null) return state;
   2376 
   2377         state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust);
   2378         mDeviceProfileState.put(address, state);
   2379         state.start();
   2380         return state;
   2381     }
   2382 
   2383     void removeProfileState(String address) {
   2384         mDeviceProfileState.remove(address);
   2385     }
   2386 
   2387     synchronized String[] getKnownDevices() {
   2388         String[] bonds = null;
   2389         String val = getProperty("Devices", true);
   2390         if (val != null) {
   2391             bonds = val.split(",");
   2392         }
   2393         return bonds;
   2394     }
   2395 
   2396     private void initProfileState() {
   2397         String[] bonds = null;
   2398         String val = getProperty("Devices", false);
   2399         if (val != null) {
   2400             bonds = val.split(",");
   2401         }
   2402         if (bonds == null) {
   2403             return;
   2404         }
   2405         for (String path : bonds) {
   2406             String address = getAddressFromObjectPath(path);
   2407             BluetoothDeviceProfileState state = addProfileState(address, false);
   2408         }
   2409     }
   2410 
   2411     private void autoConnect() {
   2412         String[] bonds = getKnownDevices();
   2413         if (bonds == null) {
   2414             return;
   2415         }
   2416         for (String path : bonds) {
   2417             String address = getAddressFromObjectPath(path);
   2418             BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
   2419             if (state != null) {
   2420                 Message msg = new Message();
   2421                 msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES;
   2422                 state.sendMessage(msg);
   2423             }
   2424         }
   2425     }
   2426 
   2427     public boolean notifyIncomingConnection(String address) {
   2428         BluetoothDeviceProfileState state =
   2429              mDeviceProfileState.get(address);
   2430         if (state != null) {
   2431             Message msg = new Message();
   2432             msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
   2433             state.sendMessage(msg);
   2434             return true;
   2435         }
   2436         return false;
   2437     }
   2438 
   2439     /*package*/ boolean notifyIncomingA2dpConnection(String address) {
   2440        BluetoothDeviceProfileState state =
   2441             mDeviceProfileState.get(address);
   2442        if (state != null) {
   2443            Message msg = new Message();
   2444            msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
   2445            state.sendMessage(msg);
   2446            return true;
   2447        }
   2448        return false;
   2449     }
   2450 
   2451     /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) {
   2452         mA2dpService = a2dpService;
   2453     }
   2454 
   2455     /*package*/ Integer getAuthorizationAgentRequestData(String address) {
   2456         Integer data = mEventLoop.getAuthorizationAgentRequestData().remove(address);
   2457         return data;
   2458     }
   2459 
   2460     public void sendProfileStateMessage(int profile, int cmd) {
   2461         Message msg = new Message();
   2462         msg.what = cmd;
   2463         if (profile == BluetoothProfileState.HFP) {
   2464             mHfpProfileState.sendMessage(msg);
   2465         } else if (profile == BluetoothProfileState.A2DP) {
   2466             mA2dpProfileState.sendMessage(msg);
   2467         }
   2468     }
   2469 
   2470     public int getAdapterConnectionState() {
   2471         return mAdapterConnectionState;
   2472     }
   2473 
   2474     public int getProfileConnectionState(int profile) {
   2475         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
   2476 
   2477         Pair<Integer, Integer> state = mProfileConnectionState.get(profile);
   2478         if (state == null) return BluetoothProfile.STATE_DISCONNECTED;
   2479 
   2480         return state.first;
   2481     }
   2482 
   2483     private void updateProfileConnectionState(int profile, int newState, int oldState) {
   2484         // mProfileConnectionState is a hashmap -
   2485         // <Integer, Pair<Integer, Integer>>
   2486         // The key is the profile, the value is a pair. first element
   2487         // is the state and the second element is the number of devices
   2488         // in that state.
   2489         int numDev = 1;
   2490         int newHashState = newState;
   2491         boolean update = true;
   2492 
   2493         // The following conditions are considered in this function:
   2494         // 1. If there is no record of profile and state - update
   2495         // 2. If a new device's state is current hash state - increment
   2496         //    number of devices in the state.
   2497         // 3. If a state change has happened to Connected or Connecting
   2498         //    (if current state is not connected), update.
   2499         // 4. If numDevices is 1 and that device state is being updated, update
   2500         // 5. If numDevices is > 1 and one of the devices is changing state,
   2501         //    decrement numDevices but maintain oldState if it is Connected or
   2502         //    Connecting
   2503         Pair<Integer, Integer> stateNumDev = mProfileConnectionState.get(profile);
   2504         if (stateNumDev != null) {
   2505             int currHashState = stateNumDev.first;
   2506             numDev = stateNumDev.second;
   2507 
   2508             if (newState == currHashState) {
   2509                 numDev ++;
   2510             } else if (newState == BluetoothProfile.STATE_CONNECTED ||
   2511                    (newState == BluetoothProfile.STATE_CONNECTING &&
   2512                     currHashState != BluetoothProfile.STATE_CONNECTED)) {
   2513                  numDev = 1;
   2514             } else if (numDev == 1 && oldState == currHashState) {
   2515                  update = true;
   2516             } else if (numDev > 1 && oldState == currHashState) {
   2517                  numDev --;
   2518 
   2519                  if (currHashState == BluetoothProfile.STATE_CONNECTED ||
   2520                      currHashState == BluetoothProfile.STATE_CONNECTING) {
   2521                     newHashState = currHashState;
   2522                  }
   2523             } else {
   2524                  update = false;
   2525             }
   2526         }
   2527 
   2528         if (update) {
   2529             mProfileConnectionState.put(profile, new Pair<Integer, Integer>(newHashState,
   2530                     numDev));
   2531         }
   2532     }
   2533 
   2534     public synchronized void sendConnectionStateChange(BluetoothDevice
   2535             device, int profile, int state, int prevState) {
   2536         // Since this is a binder call check if Bluetooth is on still
   2537         if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return;
   2538 
   2539         if (!validateProfileConnectionState(state) ||
   2540                 !validateProfileConnectionState(prevState)) {
   2541             // Previously, an invalid state was broadcast anyway,
   2542             // with the invalid state converted to -1 in the intent.
   2543             // Better to log an error and not send an intent with
   2544             // invalid contents or set mAdapterConnectionState to -1.
   2545             Log.e(TAG, "Error in sendConnectionStateChange: "
   2546                     + "prevState " + prevState + " state " + state);
   2547             return;
   2548         }
   2549 
   2550         updateProfileConnectionState(profile, state, prevState);
   2551 
   2552         if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
   2553             mAdapterConnectionState = state;
   2554 
   2555             if (state == BluetoothProfile.STATE_DISCONNECTED) {
   2556                 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.ALL_DEVICES_DISCONNECTED);
   2557             }
   2558 
   2559             Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
   2560             intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
   2561             intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
   2562                     convertToAdapterState(state));
   2563             intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE,
   2564                     convertToAdapterState(prevState));
   2565             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2566             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
   2567             Log.d(TAG, "CONNECTION_STATE_CHANGE: " + device + ": "
   2568                     + prevState + " -> " + state);
   2569         }
   2570     }
   2571 
   2572     private boolean validateProfileConnectionState(int state) {
   2573         return (state == BluetoothProfile.STATE_DISCONNECTED ||
   2574                 state == BluetoothProfile.STATE_CONNECTING ||
   2575                 state == BluetoothProfile.STATE_CONNECTED ||
   2576                 state == BluetoothProfile.STATE_DISCONNECTING);
   2577     }
   2578 
   2579     private int convertToAdapterState(int state) {
   2580         switch (state) {
   2581             case BluetoothProfile.STATE_DISCONNECTED:
   2582                 return BluetoothAdapter.STATE_DISCONNECTED;
   2583             case BluetoothProfile.STATE_DISCONNECTING:
   2584                 return BluetoothAdapter.STATE_DISCONNECTING;
   2585             case BluetoothProfile.STATE_CONNECTED:
   2586                 return BluetoothAdapter.STATE_CONNECTED;
   2587             case BluetoothProfile.STATE_CONNECTING:
   2588                 return BluetoothAdapter.STATE_CONNECTING;
   2589         }
   2590         Log.e(TAG, "Error in convertToAdapterState");
   2591         return -1;
   2592     }
   2593 
   2594     private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
   2595         switch (prevState) {
   2596             case BluetoothProfile.STATE_CONNECTING:
   2597                 mProfilesConnecting--;
   2598                 break;
   2599 
   2600             case BluetoothProfile.STATE_CONNECTED:
   2601                 mProfilesConnected--;
   2602                 break;
   2603 
   2604             case BluetoothProfile.STATE_DISCONNECTING:
   2605                 mProfilesDisconnecting--;
   2606                 break;
   2607         }
   2608 
   2609         switch (state) {
   2610             case BluetoothProfile.STATE_CONNECTING:
   2611                 mProfilesConnecting++;
   2612                 return (mProfilesConnected == 0 && mProfilesConnecting == 1);
   2613 
   2614             case BluetoothProfile.STATE_CONNECTED:
   2615                 mProfilesConnected++;
   2616                 return (mProfilesConnected == 1);
   2617 
   2618             case BluetoothProfile.STATE_DISCONNECTING:
   2619                 mProfilesDisconnecting++;
   2620                 return (mProfilesConnected == 0 && mProfilesDisconnecting == 1);
   2621 
   2622             case BluetoothProfile.STATE_DISCONNECTED:
   2623                 return (mProfilesConnected == 0 && mProfilesConnecting == 0);
   2624 
   2625             default:
   2626                 return true;
   2627         }
   2628     }
   2629 
   2630     private void createIncomingConnectionStateFile() {
   2631         File f = new File(INCOMING_CONNECTION_FILE);
   2632         if (!f.exists()) {
   2633             try {
   2634                 f.createNewFile();
   2635             } catch (IOException e) {
   2636                 Log.e(TAG, "IOException: cannot create file");
   2637             }
   2638         }
   2639     }
   2640 
   2641     /** @hide */
   2642     public Pair<Integer, String> getIncomingState(String address) {
   2643         if (mIncomingConnections.isEmpty()) {
   2644             createIncomingConnectionStateFile();
   2645             readIncomingConnectionState();
   2646         }
   2647         return mIncomingConnections.get(address);
   2648     }
   2649 
   2650     private void readIncomingConnectionState() {
   2651         synchronized(mIncomingConnections) {
   2652             FileInputStream fstream = null;
   2653             try {
   2654               fstream = new FileInputStream(INCOMING_CONNECTION_FILE);
   2655               DataInputStream in = new DataInputStream(fstream);
   2656               BufferedReader file = new BufferedReader(new InputStreamReader(in));
   2657               String line;
   2658               while((line = file.readLine()) != null) {
   2659                   line = line.trim();
   2660                   if (line.length() == 0) continue;
   2661                   String[] value = line.split(",");
   2662                   if (value != null && value.length == 3) {
   2663                       Integer val1 = Integer.parseInt(value[1]);
   2664                       Pair<Integer, String> val = new Pair(val1, value[2]);
   2665                       mIncomingConnections.put(value[0], val);
   2666                   }
   2667               }
   2668             } catch (FileNotFoundException e) {
   2669                 log("FileNotFoundException: readIncomingConnectionState" + e.toString());
   2670             } catch (IOException e) {
   2671                 log("IOException: readIncomingConnectionState" + e.toString());
   2672             } finally {
   2673                 if (fstream != null) {
   2674                     try {
   2675                         fstream.close();
   2676                     } catch (IOException e) {
   2677                         // Ignore
   2678                     }
   2679                 }
   2680             }
   2681         }
   2682     }
   2683 
   2684     private void truncateIncomingConnectionFile() {
   2685         RandomAccessFile r = null;
   2686         try {
   2687             r = new RandomAccessFile(INCOMING_CONNECTION_FILE, "rw");
   2688             r.setLength(0);
   2689         } catch (FileNotFoundException e) {
   2690             log("FileNotFoundException: truncateIncomingConnectionState" + e.toString());
   2691         } catch (IOException e) {
   2692             log("IOException: truncateIncomingConnectionState" + e.toString());
   2693         } finally {
   2694             if (r != null) {
   2695                 try {
   2696                     r.close();
   2697                 } catch (IOException e) {
   2698                     // ignore
   2699                  }
   2700             }
   2701         }
   2702     }
   2703 
   2704     /** @hide */
   2705     public void writeIncomingConnectionState(String address, Pair<Integer, String> data) {
   2706         synchronized(mIncomingConnections) {
   2707             mIncomingConnections.put(address, data);
   2708 
   2709             truncateIncomingConnectionFile();
   2710             BufferedWriter out = null;
   2711             StringBuilder value = new StringBuilder();
   2712             try {
   2713                 out = new BufferedWriter(new FileWriter(INCOMING_CONNECTION_FILE, true));
   2714                 for (String devAddress: mIncomingConnections.keySet()) {
   2715                   Pair<Integer, String> val = mIncomingConnections.get(devAddress);
   2716                   value.append(devAddress);
   2717                   value.append(",");
   2718                   value.append(val.first.toString());
   2719                   value.append(",");
   2720                   value.append(val.second);
   2721                   value.append("\n");
   2722                 }
   2723                 out.write(value.toString());
   2724             } catch (FileNotFoundException e) {
   2725                 log("FileNotFoundException: writeIncomingConnectionState" + e.toString());
   2726             } catch (IOException e) {
   2727                 log("IOException: writeIncomingConnectionState" + e.toString());
   2728             } finally {
   2729                 if (out != null) {
   2730                     try {
   2731                         out.close();
   2732                     } catch (IOException e) {
   2733                         // Ignore
   2734                     }
   2735                 }
   2736             }
   2737         }
   2738     }
   2739 
   2740     private static void log(String msg) {
   2741         Log.d(TAG, msg);
   2742     }
   2743 
   2744     private native static void classInitNative();
   2745     private native void initializeNativeDataNative();
   2746     private native boolean setupNativeDataNative();
   2747     private native boolean tearDownNativeDataNative();
   2748     private native void cleanupNativeDataNative();
   2749     /*package*/ native String getAdapterPathNative();
   2750 
   2751     private native int isEnabledNative();
   2752     /*package*/ native int enableNative();
   2753     /*package*/ native int disableNative();
   2754 
   2755     /*package*/ native Object[] getAdapterPropertiesNative();
   2756     private native Object[] getDevicePropertiesNative(String objectPath);
   2757     private native boolean setAdapterPropertyStringNative(String key, String value);
   2758     private native boolean setAdapterPropertyIntegerNative(String key, int value);
   2759     private native boolean setAdapterPropertyBooleanNative(String key, int value);
   2760 
   2761     private native boolean startDiscoveryNative();
   2762     private native boolean stopDiscoveryNative();
   2763 
   2764     private native boolean createPairedDeviceNative(String address, int timeout_ms);
   2765     private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms);
   2766     private native byte[] readAdapterOutOfBandDataNative();
   2767 
   2768     private native boolean cancelDeviceCreationNative(String address);
   2769     private native boolean removeDeviceNative(String objectPath);
   2770     private native int getDeviceServiceChannelNative(String objectPath, String uuid,
   2771             int attributeId);
   2772 
   2773     private native boolean cancelPairingUserInputNative(String address, int nativeData);
   2774     private native boolean setPinNative(String address, String pin, int nativeData);
   2775     private native boolean setPasskeyNative(String address, int passkey, int nativeData);
   2776     private native boolean setPairingConfirmationNative(String address, boolean confirm,
   2777             int nativeData);
   2778     private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash,
   2779                                                         byte[] randomizer, int nativeData);
   2780 
   2781     private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
   2782             int value);
   2783     private native boolean setDevicePropertyStringNative(String objectPath, String key,
   2784             String value);
   2785     private native boolean createDeviceNative(String address);
   2786     /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
   2787 
   2788     private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
   2789             short channel);
   2790     private native boolean removeServiceRecordNative(int handle);
   2791     private native boolean setLinkTimeoutNative(String path, int num_slots);
   2792 
   2793     native boolean connectInputDeviceNative(String path);
   2794     native boolean disconnectInputDeviceNative(String path);
   2795 
   2796     native boolean setBluetoothTetheringNative(boolean value, String nap, String bridge);
   2797     native boolean connectPanDeviceNative(String path, String dstRole);
   2798     native boolean disconnectPanDeviceNative(String path);
   2799     native boolean disconnectPanServerDeviceNative(String path,
   2800             String address, String iface);
   2801 
   2802     private native int[] addReservedServiceRecordsNative(int[] uuuids);
   2803     private native boolean removeReservedServiceRecordsNative(int[] handles);
   2804 
   2805     // Health API
   2806     native String registerHealthApplicationNative(int dataType, String role, String name,
   2807             String channelType);
   2808     native String registerHealthApplicationNative(int dataType, String role, String name);
   2809     native boolean unregisterHealthApplicationNative(String path);
   2810     native boolean createChannelNative(String devicePath, String appPath, String channelType,
   2811                                        int code);
   2812     native boolean destroyChannelNative(String devicePath, String channelpath, int code);
   2813     native String getMainChannelNative(String path);
   2814     native String getChannelApplicationNative(String channelPath);
   2815     native ParcelFileDescriptor getChannelFdNative(String channelPath);
   2816     native boolean releaseChannelFdNative(String channelPath);
   2817     native boolean setAuthorizationNative(String address, boolean value, int data);
   2818 }
   2819