This library is a proof of concept replacement for libbinder
, implementing a subset of its API on top of KDBUS. libbinder
is an interface between applications and the binder driver in the kernel. libkdbinder
follows the same principle, but allowing us to replace the binder driver by KDBUS.
Note that this work is experimental.
The current state of the Binder API that this library implements is documented in binder.md
.
We are aiming to implement as much of the API so that surfaceflinger can run along with bootanimation. However, this is a work in progress.
libkdbinder
implements its own internal interface for KDBUS, the details of this API are documented in kdbus.md
. The API tries to match how KDBUS works so it is recommended to have a look at the high level documentation of KDBUS.
Throughout these instructions, we'll assume the ${ANDROID_TREE}
environment variable points to where Android is checked out.
KDBinder was tested on the JUNO r2 development platform with a release of Android M from Linaro.
First of all, download the Android tree from linaro:
$ cd ${ANDROID_TREE} $ repo init -u https://android-review.linaro.org/platform/manifest -b android-6.0.1_r16 -g "default,device,arm" $ cd .repo $ git clone git://android.git.linaro.org/platform/manifest.git -b linaro-marshmallow local_manifests
We need to include KDBUS and KDBinder to the tree. We can do this by adding a local manifest file that points to both projects. The manifest will instruct repo
to fetch the out-of-tree KDBUS kernel module and KDBinder.
TODO: Add the linaro-android
remote to this manifest snippet.
$ cat > local_manifests/kdbinder.xml <<-EOF <?xml version="1.0" encoding="UTF-8"?> <manifest> <remote name="systemd" fetch="https://github.com/systemd/" /> <project path="external/kdbus" name="kdbus" remote="systemd" revision="master" /> <project path="frameworks/kdbinder" name="platform/external/kdbinder" remote="linaro-android" revision="master" /> </manifest> EOF
Download the Android tree.
$ cd ${ANDROID_TREE} $ repo sync -j${N_JOBS}
KDBUS requires a recent enough kernel, and the stable kernel we have checked out is based on 3.18 which is too old. We will use the latest kernel instead, as of the 11th of February.
$ cd kernel/linaro/armlt $ git checkout latest-armlt-20160211
Finally, the default configuration does not allow kernel modules. Enable it in "linaro/configs/android.conf" by setting "CONFIG_MODULES" to "y".
We are now ready to build the new kernel and Android filesystem. Watch out for the sudo prompt at the end (needed to temporarily mount the system image), it may time out after some time.
$ source build/envsetup.sh $ lunch juno-userdebug $ make -j${N_JOBS} selinuxtarballs
You may encounter errors (unsupported relocations) when linking ART executables. This seem to be a problem specific to Clang, recompile with GCC instead:
$ rm -rf out/host/linux-x86/obj{,32}/SHARED_LIBRARIES/*art* $ make -j${N_JOBS} selinuxtarballs WITHOUT_HOST_CLANG=true
We need to burn the filesystem onto a USB flash drive. Download the latest linaro-image-tools
from this git repository and run the following commands (replace sdX
with the drive's device node):
$ cd ${ANDROID_TREE}/out/target/product/juno $ sudo linaro-image-tools/linaro-android-media-create \ --mmc /dev/sdX --dev vexpress \ --systemimage system.img --userdataimage userdata.img \ --boot boot.tar.bz2
You may now connect the USB drive to the JUNO board.
We are going to install a UEFI firmware on the juno board. You may download it here, it is called "juno-uefi.zip".
Power on the JUNO board with a serial cable connected and press enter to stop auto boot. Then execute the following commands:
Cmd> flash Flash> eraseall Flash> exit Cmd> usb_on
You should now see the JUNO board come up as a USB storage device. Mount it, remove all of its content and replace it with the content of "juno-uefi.zip". Make sure you keep the directory structure. For instance:
# mount /dev/sdc1 /mnt # rm -r /mnt/* # unzip /path/to/juno-uefi.zip -d /mnt/
Then, we have to copy our kernel, device tree and ramdisk:
# cp ${ANDROID_TREE}/out/target/product/juno/boot/kernel /mnt/SOFTWARE/Image # cp ${ANDROID_TREE}/out/target/product/juno/boot/juno-r2.dtb /mnt/SOFTWARE/juno-r2.dtb # cp ${ANDROID_TREE}/out/target/product/juno/ramdisk.img /mnt/SOFTWARE/ramdisk.img
Finally, we need to instruct UEFI to boot our kernel. You should find the following file in "/mnt/SOFTWARE":
# cat /mnt/SOFTWARE/startup.nsh echo -off echo Juno startup.nsh from NOR flash echo Example command to start the kernel: echo norkern dtb=board.dtb initrd=ramdisk.img console=ttyAMA0,115200n8 root=/dev/sda2 rw rootwait earlyprintk=pl011,0x7ff80000 debug user_debug=31 androidboot.hardware=juno loglevel=9 sky2.mac_address=0xAA,0xBB,0xCC,0xDD,0xEE,0xFF
Append this file with the following line:
norkern dtb=board.dtb initrd=ramdisk.img console=ttyAMA0,115200n8 root=/dev/sda2 rw rootwait earlyprintk=pl011,0x7ff80000 debug user_debug=31 androidboot.hardware=juno loglevel=9 sky2.mac_address=0xAA,0xBB,0xCC,0xDD,0xEE,0xFF selinux=0
We are now ready to boot to Android. Make sure you've issued a "sync" before umounting the JUNO's USB storage device. Plug in the USB flash drive with the Android file system and enter reboot the board:
Cmd> reboot
If it all went well, you should have booted to a shell on the Android filesystem. Make sure you have connected an ethernet cable to the GigaBit ethernet port, just below the JTAG port. Network may take a few minutes to become ready.
We will need to send files over to the board with adb. However, the /system
partition is mounted as read-only by default so we remount it as read-write.
$ adb connect X.X.X.X $ adb remount
The KDBUS out-of-tree module needs to be built against the kernel. We are using the bare metal toolchain from linaro (but any AArch64 toolchain should be just as fine, modify CROSS_COMPILE
accordingly).
$ cd ${ANDROID_TREE}/external/kdbus $ export ARCH=arm64 $ export CROSS_COMPILE=aarch64-none-elf- $ make KERNELDIR=${ANDROID_TREE}/out/target/product/juno/obj/kernel module
Then you may upload and load KDBUS into the running kernel:
$ adb push ipc/kdbus/kdbus.ko /system/kdbus.ko $ adb shell # insmod /system/kdbus.ko # mount -t kdbusfs kdbusfs /sys/fs/kdbus
KDBinder was checked out in "frameworks/kdbinder" by repo. All we have to do now is build it and upload it to the target.
Build libkdbinder
and its test-suite:
$ cd ${ANDROID_TREE}/frameworks/kdbinder/libs/kdbinder $ mm
Build the kdbus_servicemanager
utility:
$ cd ${ANDROID_TREE}/frameworks/kdbinder/cmds $ mm
And upload everything to the target:
$ adb sync
For KDBinder to work, we need this service to run in the background. Leave adb shell running or background it, there doesn't seem to be a clean way to daemonize an arbitrary process from adb:
$ adb shell # kdbus_servicemanager &
Now you should be able to successfully run the tests on the target!
$ adb shell # /data/nativetest64/kdbinderTest/kdbinderTest # /data/nativetest64/kdbinderKDBUSTest/kdbinderKDBUSTest
The KDBinder tests we have run only make sure that the library itself is working. However, the interesting part is that libkdbinder
aims to be a drop-in replacement for libbinder
. This means we can choose to build packages depending on libbinder
with libkdbinder
instead.
At the moment, support for this is very limited. But here is a working example for the binderAddInts
benchmark.
Run the benchmark on the target. You may need to make it explicitly executable.
$ adb shell # chmod +x /data/nativebenchmarks/binderAddInts # /data/nativebenchmarks/binderAddInts
Let's create a version using libkdbinder
called kdbus_binderAddInts
!
Navigate to binderAddInts
:
$ cd ${ANDROID_TREE}/system/extras/tests/binder/benchmarks
Edit the Android.mk
file and append the following:
include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE_TAGS := eng tests LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativebenchmark LOCAL_STATIC_LIBRARIES += \ libtestUtil LOCAL_SHARED_LIBRARIES += \ libutils \ liblog \ libkdbinder LOCAL_C_INCLUDES += \ system/extras/tests/include \ frameworks/base/include \ frameworks/kdbinder/include/kdbinder LOCAL_MODULE := kdbus_binderAddInts LOCAL_SRC_FILES := binderAddInts.cpp include $(BUILD_EXECUTABLE)
This is building an executable from the same source as the binder version, but this time it builds against libkdbinder
.
Build, upload and run:
$ mm $ adb sync $ adb shell /data/nativebenchmark/kdbus_binderAddInts