KDBinder ======== 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. Binder API ---------- 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. Low-level KDBUS layer --------------------- `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. Build instructions ------------------ 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. ### Integrating KDBUS and KDBinder in the Android tree 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 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". ### Build and install the Android filesystem 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][1] 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. [1]: https://git.linaro.org/ci/linaro-image-tools.git ### Setting up the JUNO board and booting to Android We are going to install a UEFI firmware on the juno board. You may download it [here][2], it is called "juno-uefi.zip". [2]: https://community.arm.com/docs/DOC-10804#jive_content_id_41_Prebuilt_configurations 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. Testing KDBUS and KDBinder -------------------------- 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 ### Building and installing KDBUS The KDBUS out-of-tree module needs to be built against the kernel. We are using the bare metal toolchain from [linaro][3] (but any AArch64 toolchain should be just as fine, modify `CROSS_COMPILE` accordingly). [3]: https://releases.linaro.org/components/toolchain/binaries/latest-5.1/aarch64-elf/gcc-linaro-5.1-2015.08-x86_64_aarch64-elf.tar.xz $ 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 ### Building, uploading and testing KDBinder 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 ### binderAddInts benchmark running with KDBUS 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