Android-Adding Bluetooth Profile

From Texas Instruments Wiki
Jump to: navigation, search

This wiki highlights on - "How to add bluetooth profile(HID) support into android framework". This can be taken as a reference to add more profiles for bluetooth or other software stack under android framework.

Android Bluetooth Framewrok

BT Stack.jpg

Bluetooth profiles supported by android

Android's Bluetooth stack uses BlueZ for:

  • GAP profile: Generic Access protocol
  • SDP profile : Service discovery protocol
  • Headset and Handsfree (v1.5) profiles are implemented in the Android framework and are both tightly coupled with the Phone App. These profiles are also SIG qualified.
  • RFCOMM profile: Cable replacement protocol,and is a SIG-qualified Bluetooth 2.0 host stack.

BlueZ Website: http://wiki.bluez.org/ Documentation: mydroid\external\bluez\utils\doc

Bluez is GPL licensed, so the Android framework interacts with userspace bluez code through D-BUS IPC to avoid proprietary code.

D-BUS website: http://www.freedesktop.org/wiki/IntroductionToDBus

Android Bluetooth Source

  • Bluez 3.38 (user space and kernel)
<android-src>/external/bluez
<android-src>/kernel/drivers/bluetooth
<android-src>/kernel/net/bluetooth
  • Android App framework (java & c++)
<android-src>/frameworks/base/core/jni/android_bluetooth_*.cpp
<android-src>/frameworks/base/core/java/android/bluetooth/*.java
<android-src>/frameworks/bases/services/java/com/android/server (system_server)
  • Android UI application
<android-src>/packages/apps/Phone/src/com/android/phone (Phone App)
<android-src>/package/apps/Settings/src/com/android/settings/bluetooth/ (Settings App)

Bluetooth event flow in Android Source Tree

500px-Bluetooth Source Flow Android.jpg
Above diagram explains a sequence of bluetooth event flow with respect to android source tree

  • BlueZ
    • BlueZ provides support for the core Bluetooth layers and protocols
    • Android BlueZ is software stack implenation which will get/send bluetooth controls and data to/from bluetooth h/w using kenrel (bluez) modules.
    • BlueZ also expose a interface for android framework which enable door to access bluetooth functionalities.
    • Documenataion of exposed interface can be found at <android-src>/external/bluetooth/bluez/doc
    • Android framework communicates with bluez using D-Bus protocol.Interface to use for diffenent types of bluetooth porfile is documented at <android-src>/external/bluetooth/bluez/doc

e.g. Bluetooth input device - Exposed API is available at <android-src>/external/bluetooth/bluez/doc/input-api.txt

Input hierarchy
===============
Service     org.bluez
Interface   org.bluez.Input
Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
Methods     void Connect()
            Connect to the input device.

        	void Disconnect()
            Disconnect from the input device.

	        dict GetProperties()
            Returns all properties for the interface. See the
            properties section for available properties.


Signals     PropertyChanged(string name, variant value)

            This signal indicates a changed value of the given
            property.

Properties  boolean Connected [readonly]

            Indicates if the device is connected.
  • Framework Layer
    • Bluetooth functionality in a framewrok is divided in two parts
      • Bluetooth JNI Service : This component talks to bluez using D-Bus interface
frameworks/base/core/jni/Android.mk
frameworks/base/jcore/jni/AndroidRuntime.cpp
frameworks/base/core/jni/android_server_BluetoothEventLoop.cpp
frameworks/base/core/jni/android_server_BluetoothHidService.cpp
      • Bluetooth Service Layer : This component provides interface to application to communicate with bluez using component#1.
frameworks/base/core/java/android/server/BluetoothEventLoop.java
frameworks/base/core/java/android/server/BluetoothHidService.java
frameworks/base/services/java/com/android/server/SystemServer.java
  • Application Layer
    • Application : Component that creates user interface
    • Service  : Component talks to android framewrok using AIDL to get/send bluetooth controls and data
Application:
packages/apps/Phone/src/com/android/phone
package/apps/Settings/src/com/android/settings/bluetooth/

Service : (android.bluetooth)
frameworks/base/core/java/android/bluetooth/BluetoothClass.java
frameworks/base/core/java/android/bluetooth/BluetoothUuid.java
frameworks/base/core/java/android/bluetooth/BluetoothHid.java

AIDL:
frameworks/base/core/java/android/bluetooth/IBluetoothHid.aidl

Adding a bluetooth HID profile

  • Note : For complete code reference guide; kindly take reference of attached patch.

http://processors.wiki.ti.com/index.php/File:Bluetooth-HID-support-Android.zip

Create JNI interface

  • Create File:<android-src>/frameworks/base/core/jni/android_server_BluetoothHidService.cpp

static bool initNative(JNIEnv* env, jobject object) {
	/* open dbus connection */
}

static void cleanupNative(JNIEnv* env, jobject object) {
	 /* close dbus connection */
}

static jobjectArray getInputPropertiesNative(JNIEnv *env, jobject object,
                                            jstring path) {
	/* talk to bluez with interface org.bluez.Input and method :GetProperties */
}

static jboolean connectInputNative(JNIEnv *env, jobject object, jstring path) {
	/* talk to bluez with interface org.bluez.Input and method :Connect */
}

static jboolean disconnectInputNative(JNIEnv *env, jobject object,
                                     jstring path) {
	/* talk to bluez with interface org.bluez.Input and method :Disconnect */
}

DBusHandlerResult hid_event_filter(DBusMessage *msg, JNIEnv *env) {
	/* talk to bluez with interface org.bluez.Input and signal :PropertyChanged */
}

static JNINativeMethod sMethods[] = {
    {"initNative", "()Z", (void *)initNative},
    {"cleanupNative", "()V", (void *)cleanupNative},

    /* Bluez audio 4.40 API */
    {"connectInputNative", "(Ljava/lang/String;)Z", (void *)connectInputNative},
    {"disconnectInputNative", "(Ljava/lang/String;)Z", (void *)disconnectInputNative},
    {"getInputPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
                                    (void *)getInputPropertiesNative},                                                       
};

int register_android_server_BluetoothHidService(JNIEnv *env) {
	/* register HID service and methods mentioned above */
}

  • Add HID support to eventloop :
/* Open :<android-src>/frameworks/base/core/jni/android_server_BluetoothEventLoop.cpp */
/* 1. add entry to fucntion static "setUpEventLoop" */
static jboolean setUpEventLoop(native_data_t *nat) {
.....
.....
	dbus_bus_add_match(nat->conn,
       "type='signal',interface='org.bluez.Input'",
       &err);
        if (dbus_error_is_set(&err)) {
            LOG_AND_FREE_DBUS_ERROR(&err);
            return JNI_FALSE;
        }
..
..
}

/* 2. add entry to function "tearDownEventLoop" */
static void tearDownEventLoop(native_data_t *nat) {
.....
....
 dbus_bus_remove_match(nat->conn,
       "type='signal',interface='org.bluez.Input'",
        &err);
	    if (dbus_error_is_set(&err)) {
            LOG_AND_FREE_DBUS_ERROR(&err);
        }

....
}

/* 3. delcare extern for hid_event_filter : Implemented in android_server_BluetoothHidService.cpp */
extern DBusHandlerResult hid_event_filter(DBusMessage *msg, JNIEnv *env);

/* call "hid_event_filter(msg, env);" in function :event_filter
static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
                                      void *data) {
.....
.....
hid_event_filter(msg, env);
ret = a2dp_event_filter(msg, env);
}
  • Register HID service and add build support
/* open frameworks/base/core/jni/Android.mk, add android_server_BluetoothHidService.cpp for build  */
LOCAL_SRC_FILES += android_server_BluetoothHidService.cpp
/* open : frameworks/base/core/jni/AndroidRuntime.cpp and add HID service registration */
extern int register_android_server_BluetoothHidService(JNIEnv* env);
/* in function static const RegJNIRec add HID entry */
static const RegJNIRec gRegJNI[] = {
....
....
REG_JNI(register_android_server_BluetoothHidService),
....
....
}

Create framework service for Bluetooth HID

  • Create bluetooth HID service
/* create file :frameworks/base/java/android/server/BluetoothHidService.java */
/* implement wrapper APIs for all methods present in JNI interface. For more info on code kindly refer attached patch */
  • register bluetooth HID service with system server
/* open file : <android-src>/frameworks/base/services/java/com/android/server/SystemServer.java */
import android.server.BluetoothHidService;
public void run() {
....
....
	BluetoothService bluetooth = null;
    BluetoothA2dpService bluetoothA2dp = null;
    /* HID port - start */
    BluetoothHidService bluetoothHid = null;
    /* HID port - end */
....
....
	bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
    ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
                                  bluetoothA2dp);
    /* HID port - start */
    if (SystemProperties.TARGET_OMAP4) {
    	bluetoothHid = new BluetoothHidService(context, bluetooth);
        ServiceManager.addService(BluetoothHidService.BLUETOOTH_HID_SERVICE,
        							bluetoothHid);
    }
    /* HID port - end */
....
....
}
  • Add authorization check at BluetoothEventLoop.java
/* open file :frameworks/base/core/java/android/server/BluetoothEventLoop.java */
private boolean onAgentAuthorize(String objectPath, String deviceUuid){
....
....
	if (mBluetoothService.isEnabled() &&
	..
	..
	}
    /* HID port - start */
    if (mBluetoothService.isEnabled() &&
          (BluetoothUuid.isInputHID(uuid)) && SystemProperties.TARGET_OMAP4) {
           authorized = true;
           Log.i(TAG, "Allowing incoming HID connection from " + address);
    /* HID port - end */
	}
	else {
	    Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
    }
....
....
}

Create Application Bluetooth HID service & Application moification to add bluetooth HID

  • Kindly refer user guide for creating custom service at

http://processors.wiki.ti.com/index.php/Android-Adding_SystemService

  • Create Blueetooth HID custom application service
/* create file : frameworks/base/core/java/android/bluetooth/BluetoothHid.java */
define BluetoothHID class with following methods:
public final class BluetoothHid { 
....
....
public BluetoothHid(Context c){
	/* Create a BluetoothHid proxy object for interacting with the local Bluetooth HID service */
	IBinder b = ServiceManager.getService(BluetoothHidService.BLUETOOTH_HID_SERVICE);
	mService = IBluetoothHid.Stub.asInterface(b); 
}
public boolean connectInput(BluetoothDevice device) {
	/* Initiate a connection to an HID input device */
	mService.connectInput(device);
}
public boolean disconnectInput(BluetoothDevice device) {
	/* Initiate disconnect from an HID input device.  */
	mService.disconnectInput(device);
}
public int getInputState(BluetoothDevice device) {
	/*  Get the state of an HID input device */
	 mService.getInputState(device);
}
....
/* Add more custom methods */
....
}
  • Create Uuid for bluetooth HID profile
/* open file : frameworks/base/core/java/android/bluetooth/BluetoothUuid.java */
public final class BluetoothUuid {
....
....
public static final ParcelUuid HID =
            ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
....
/* public static final ParcelUuid[] RESERVED_UUIDS = {
        AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
        ObexObjectPush};*/
change to 
public static final ParcelUuid[] RESERVED_UUIDS = {
        AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
        ObexObjectPush,HID};
...
/* HID port - start */
    public static boolean isInputHID(ParcelUuid uuid) {
        return uuid.equals(HID);
    }
/* HID port - end */
...
}
  • Create HID profile ID
/* open file : frameworks/base/core/java/android/bluetooth/BluetoothClass.java */
/* HID port - start */
/** @hide */
	public static final int PROFILE_HID = 3;
/* HID port - end */
  • Create AIDL file and add in build file
/* create file :frameworks/base/core/java/android/bluetooth/IBluetoothHid.aidl */
/* refer patch for more details */
  • Change application

Refer attached patch for more details

References

http://processors.wiki.ti.com/index.php/Android-Adding_SystemService
http://www.slideshare.net/erinyueh/android-bluetooth-introduction
https://sites.google.com/a/android.com/opensource/projects/bluetooth-faq
CategoryBeagleboard