[Android Software/Hacking General [Developers Only]] daniel_hk:
Introduction

When the bluetooth stack changed to Bluedroid in Android 4.2, it was a nightmare to some of the old devices like my GT-P6800. I didn't have any experience in Bluetooth before so I did what I know. I spent weeks to revert the 4.2 platform to Bluez. Even though I succeeded, it probably not doable for 4.3 and later.

Last Nov. I found that bluez.org announced support for Andriod in Sep. It gave me hope again! Thanks to the bluez team!:good: The principle is straight forward - Implement the functions defined in "hardware/libhardware/include/hardware/bluetooth.h". That's what I thought but I didn't have enough knowledge nor confidence to try...:o

After studying for a while, I started porting bluez to Android 4.4 last Christmas. It was frustrated and helpless. Although the lastest Android 4.4 example for Mako and Flo are out, they don't help much. A bunch of prebuilt kernel objects surely doesn't help! Porting for those devices already having bluedroid support is meaningless to most of us too... :(

Building the bluez hal and daemon are straight forward but how to make it really work is another story. After a few painful and frustrated weekends, I finally managed to pull everything together. I can start/stop and pairing bluetooth devices in the platform now. And here I'm, sharing my experiences. I think there might be better way and I welcome any corrections.

My p6800 has CSR bluetooth chip which has no bluedroid support. I think the same approach would work for other chips too. Cheers! :highfive:

** All paths assume your rom source dircetory to be the current directory **

1. Downlaod and Build

Bluez.org already has its own tutorial. I just summerize and list my suggestions.

1.1 local manifest

I learned my lesson and would avoid touching the "manifest.xml".

Add the following lines to your ".repo/local_manifests/local_menifest.xml"

For cm11, omni, etc.

<remote name="gcode" fetch="https://code.google.com/p/"/>
<remote name="korg" fetch="git://git.kernel.org/pub/scm/bluetooth/"/>
<remove-project name="android_external_bluetooth_bluedroid"/>
<project remote="korg" path="external/bluetooth/bluez" name="bluez" group="pdk" revision="master"/>
<project remote="korg" path="external/bluetooth/sbc" name="sbc" group="pdk" revision="master"/>
<project remote="gcode" path="external/bluetooth/glib" name="aosp-bluez.glib" group="pdk" revision="master"/>

For AOSP, replace the remove-project with:

<remove-project name="platform/external/bluetooth/bluedroid"/>

After repo sync, bluez will replace bluedroid.

1.2 patching bionic

The patches for bionic are simple. Mainly by adding two flags and the function epoll_create1().

Bionic may vary from ROMs. It is wiser to patch the bionic of your ROM manually. You may follow the changes of the two commits below:

https://code.google.com/p/aosp-blue...96020013615b00d70579123f&repo=platform-bionic

https://code.google.com/p/aosp-blue...3347746d0d9727d8439ef4c4&repo=platform-bionic

1.3 neccessary tools

There are tools in "external/bluetooth/bluez/tools". You may need some of those tools for setup or testing.

This is the "Android.mk" I added to "external/bluetooth/bluez/tools". You may cheery pick the required tools for your device.

#
# Bluetooth tools for setup and debug
#	daniel_hk
LOCAL_PATH := external/bluetooth

# Retrieve BlueZ version from configure.ac file
BLUEZ_VERSION := $(shell grep ^AC_INIT $(LOCAL_PATH)/bluez/configure.ac | cpp -P -D'AC_INIT(_,v)=v')

# Specify pathmap for glib
#pathmap_INCL += glib:external/bluetooth/glib

# Specify common compiler flags
BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\" \
-DSTORAGEDIR=$(ANDROID_STORAGEDIR) \

# Disable warnings enabled by Android but not enabled in autotools build
BLUEZ_COMMON_CFLAGS += -Wno-pointer-arith -Wno-missing-field-initializers

# @ daniel, extra tools for CSR
ifeq ($(BOARD_HAVE_BLUETOOTH_CSR),true)

#
# bccmd
#
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
bluez/lib/hci.c \
bluez/lib/bluetooth.c \
bluez/tools/bccmd.c \
bluez/tools/csr.c \
bluez/tools/csr_3wire.c \
bluez/tools/csr_bcsp.c \
bluez/tools/csr_hci.c \
bluez/tools/csr_h4.c \
bluez/tools/csr_usb.c \
bluez/tools/ubcsp.c

LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)

LOCAL_C_INCLUDES:=\
$(LOCAL_PATH)/bluez \
$(LOCAL_PATH)/bluez/lib \
$(LOCAL_PATH)/bluez/tools \
$(LOCAL_PATH)/bluez/src \
$(LOCAL_PATH)/bluez/src/shared \

LOCAL_MODULE:=bccmd

include $(BUILD_EXECUTABLE)

#
# sdptool
#
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
bluez/lib/hci.c \
bluez/lib/bluetooth.c \
bluez/lib/sdp.c \
bluez/tools/sdptool.c \
bluez/src/sdp-xml.c

LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)

LOCAL_C_INCLUDES:=\
$(LOCAL_PATH)/bluez \
$(LOCAL_PATH)/bluez/lib \
$(LOCAL_PATH)/bluez/tools \
$(LOCAL_PATH)/bluez/src \
$(LOCAL_PATH)/bluez/src/shared \

LOCAL_C_INCLUDES += \
$(call include-path-for, glib) \
$(call include-path-for, glib)/glib \

LOCAL_SHARED_LIBRARIES := \
libglib \

LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:=sdptool

include $(BUILD_EXECUTABLE)
endif

1.4 patches for CyanogenMod 11

In CyanogenMod 11, the function "pin_request_cb" has one more argument. The following file need some patches:

in the file "external/bluetooth/bluez/android/hal-bluetooth.c"

[I]** in function: handle_pin_request[/I]
bt_hal_cbacks->pin_request_cb(addr, name, ev->class_of_dev, 0);	// @ daniel, added 0 for cm11

in the file "external/bluetooth/bluez/android/client/if-bt.c"

[I]** in function: pin_request_cb[/I]
static void pin_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
uint32_t cod, uint8_t secure)	// @ daniel, added secure from cm11
{
/* Store for command completion */
bt_bdaddr_t2str(remote_bd_addr, last_remote_addr);
pin_request_addr = *remote_bd_addr;

haltest_info("%s: remote_bd_addr=%s bd_name=%s cod=%06x secure=%02x\n", __func__,
last_remote_addr, bd_name->name, cod, secure);	// @ daniel, added
terminal_prompt_for("Enter pin: ", pin_request_answer);
}

2. kerenl patch

In the "README" inside "external/bluetooth/bluez/android", there is the line:

If you have tried porting bluez and fail, check the logcat. You might probably found the error "Failed to access management interface". This is the key making bluez to work! Sadly, most of the existing Android kernels are before ver. 3.9! The latest kernel we have might be ver. 3.4.x and the kernel for my p6800 is ver. 3.0.x! As the above line stated, Bluez5 requires the kernel to have management interface 1.3 or above. That means we have to backport the bluetooth subsystem from at least ver. 3.9. I backport my kernel with the latest (3.13-1) found in linux-foundation.org: http://drvbp1.linux-foundation.org/~mcgrof/rel-html/backports/

It was a tough and painful job! There are lots of changes. I finally got a bootable backport kernel in 2 days!

I packed my patches in View attachment 2567966. This patch is for my 3.0.x kernel which might be different from other 3.0.x kernels. Don't have time to tidy up but it works for me. Although I've done the hard part:eek:, it still requires extra patience to get yours done. Prepare yourself...

2.1 Backport 3.13-1 to your kernel

Direct replacements.

Replace the following folders in the zip with the one in your kernel source:

drivers/bluetooth

net/bluetooth

include/net/bluetooth

include/backport​

Direct replacement might not work!

Check include/linux in the zip

For each file,

add the required part (which I delimited with comments @ daniel and //@ ) to the corresponding file in your kernel source.

If file not exist,

copy the files to your kernel source​

Check your defconfig. As README suggested, defconfig should have:

CONFIG_BT

CONFIG_BT_RFCOMM

CONFIG_BT_RFCOMM_TTY

CONFIG_BT_BNEP

CONFIG_BT_BNEP_MC_FILTER

CONFIG_BT_BNEP_PROTO_FILTER

CONFIG_BRIDGE

CONFIG_UHID

# and for CSR chips

CONFIG_BT_HCIUART=y

CONFIG_BT_HCIUART_H4=y

CONFIG_BT_HCIUART_BCSP=y
​

You probably need to compile the kernel many times to get it work. I worte a build script View attachment 2566366 to compile the kernel only.

Copy build-k to your ROM source directory and type:

./build-k <your device>

2.2 Backport-hid-generic to your kernel

There is another patch in the Mako-kern example:

https://code.google.com/p/aosp-blue...eneric-driver.patch?repo=device-lge-mako-kern

Don't know if it is required for your kernel but adding this patch seems doesn't hurt.

If you do it right, you may find "Bluetooth management interface 1.4" in your logcat. Congratulation! Bluetoothd can connect to your kernel now!

3. initialization and setup

Take a look at your devices tree's TARGET_CUSTOM_BLUEDROID definition. If you have a file assigned, it supposed to replace the file "bluetooth.c" in the "system/bluetooth" project. In Android 4.4, this project is no longer exist/needed. Before Android 4.2, this project provide the functions "bt_enable()" and "bt_disable()" which are called in the frameworks. These functions will tell you how to "power on", "power off" and init your device's Bluetooth chip.

For CSR:

set /sys/class/rfkill/rfkill0/state to 1 ("power on")

start the service "bccmd" which will setup the chip and upload a PSConfig to the chip

start the service "hciattach" which init the port hci0 with parameters

start the service "bluetoothd" which is the bluez stack

The services are defined in init.rc or init.${ro.hardware}.rc.

3.1 Test your device and the tools

Disable the "import init.bluetooth.rc" line if you have added it before.

Example for CSR chips. Follow the steps in bt_enable. In a terminal or via adb:

$ su	-- [I][COLOR="SeaGreen"]root user is required[/COLOR][/I]
# echo "1" > /sys/class/rfkill/rfkill0/state
# bccmd -t bcsp -d /dev/ttySAC0 -b 115200 psload -r /system/etc/PSConfig_8811.psr
Loading 0x212c ... done
Loading 0x212d ... done
...
Loading PSKEY_CLOCK_REQUEST_ENABLE ... done
Loading PSKEY_UART_HOST_WAKE ... done
# hciattach -p /dev/ttySAC0 bcsp 3000000 flow
Device setup complete
# hciconfig hci0 up
# hcitool scan	-- [I][COLOR="SeaGreen"]turn on a device's bluetooth for testing[/COLOR][/I]
Nexus 4	-- [I][COLOR="SeaGreen"]found the device means bluetooth is working now[/COLOR][/I]

3.2 Init sequence

In Bluez5, the HAL (bluetooth.default.so) driver will be loaded at boot and the daemon (bluetoothd) will be started inside too. Take a look at the function "bool hal_ipc_init(void)" in "external/bluetooth/bluez/android/hal-ipc.c". You may find how the HAL is init which is different from pre-4.2 Androids.

In order to get the daemon (bluetoothd) to work, we have to init the chip before that.

I worte a shell script init.bt.sh to init the chip/port:

#!/system/bin/sh
# modified by daniel_hk

LOG_TAG="CSR8811-HCI"
BTUART_PORT=/dev/ttySAC0
BTSTATE=/sys/class/rfkill/rfkill0/state
PSCONFIG=/system/etc/PSConfig_8811.psr

logi ()
{
/system/bin/log -t $LOG_TAG -p i ": $@"
}

loge ()
{
/system/bin/log -t $LOG_TAG -p e ": $@"
}

failed ()
{
loge "$1: exit code $2"
exit $2
}

#Enable power of csr chip
echo "1" > $BTSTATE

# PS Config with bccmd
logwrapper /system/bin/bccmd -t bcsp -d $BTUART_PORT -b 115200 psload -r $PSCONFIG
case $? in
0) logi "bccmd init port....done";;
*) failed "port: $BTUART_PORT - bccmd failed" $?;
exit $?;;
esac

# attach HCI
logwrapper /system/bin/hciattach -p $BTUART_PORT bcsp 3000000 flow
case $? in
0) logi "hci attached to : $BTUART_PORT";;
*) failed "port: $BTUART_PORT - hciattach failed" $?;
exit $?;;
esac

exit 0

It takes time for bccmd and hciattach to complete. Putting them in seperate services requires delay in between. I think it is better to run them as application one after one.

A new rc file init.${ro.hardware}.bt.rc is created and need to be imported in your init.${ro.hardware}.rc

on boot
start bt_init

on property:init.svc.bluetoothd=running
start hci0_up

on property:init.svc.bluetoothd=stopped
start hci0_down

service bt_init /system/bin/logwrapper /system/bin/sh /system/etc/init.bt.sh
class main
user root
group bluetooth net_bt_admin system
disabled
oneshot

service hci0_up /system/bin/logwrapper /system/xbin/hciconfig hci0 up
class main
group bluetooth
disabled
oneshot

service hci0_down /system/bin/logwrapper /system/xbin/hciconfig hci0 down
class main
group bluetooth
disabled
oneshot

import init.bluetooth.rc

Since HAL (bluetooth.default.so) is started quite early, I start the service bt_init at boot. I have tried a few places, daemon might timed out before bt_init finish. It also seems no need to repeat the init process everytime.

When bluetoothd is running (system/core/init will set the property init.svc.bluetoothd=running), set hci0 up with hciconfig. And when the service bluetoothd is stopped, set hci0 down with hciconfig. There might be a better way. Please indulge me if something better coming up.

You may turn ON/OFF bluetooth in settings now. Pairing and file transfer is working too.

4. Further porting

Take a look at the function get_profile_interface() in the file external/bluetooth/bluez/android/hal-bluetooth.c. Some interfaces which frameworks requested are missing.

eg.

Bluetooth Handsfree interface

Bluetooth Map Client Interface

Bluetooth Health Interface

Bluetooth GATT Interface​

Update: Fully support for Kitkat now. Check the README inside the android folder for detail.

As I mentioned before, I'm new to bluetooth. Further reading is required for me to fix other services. I also don't have enough time now. I have to process the stuck works after the Chinese New Year holiday. :cyclops: Hoping I can continue by the end of Feb. In the mean time, I hope someone have better knowledge may help fix other services.

For those devices don't have bluedroid support, we have a chance to carry on now! :D