Porting Guide

From AsteroidOS

An AsteroidOS hardware adaptation layer consists of:

  • OpenEmbedded recipes describing the compilation of the various HW adaptation components.
  • An appropriate vendor kernel able to boot the watch’s SoC and including the required drivers.
  • A set of Wear OS’s proprietary binary blobs used through libhybris in order to access some of the Android’s HALs.
  • Some middleware configuration files to use your HW adaptation.

Creating an OpenEmbedded BSP layer

In order to add the support of your watch to AsteroidOS, you’ll need to write an OpenEmbedded layer. Start by making sure you are familiar with the core concepts behind OpenEmbedded by reading the two related documentation pages.

The easiest way to create an OpenEmbedded layer for hardware adaptation is to modify one that already exists. If you want to base your port on an Android 5.5.1 base, you should base your layer on meta-dory-hybris. If you want to base your port on an Android 6 base, you should base your layer on meta-swift-hybris. If you want to base your port on an Android 8 base, you should base your layer on meta-mooneye-hybris.

Start by cloning the most appropriate layer into an src/meta-XXX-hybris/ directory in your AsteroidOS build tree. From now on, XXX will be a reference to your watch’s codename. Once you have that layer setup, roughly replace all references to the previous codename with XXX in the layer and add the path to your layer in your build/conf/bblayers.conf file.

The layer should describe a machine configuration to bitbake in conf/machine/XXX.conf. The definition of a machine allows to install hardware-specific packages in a generated rootfs and to give very general information about the hardware adaptation like the kernel or egl providers that should be used. Having a new machine also allows to modify other layers’ recipes based on the build’s target. For example a .bbappend file using the _XXX suffix appropriately can modify built files, apply patches, add build dependencies, add runtime dependencies or change compilation flags. bbappends are very powerful but should be used scarcely to avoid conflicts with other layers.

An hardware adaptation layer does not only modify other recipes with bbappend, it also provides a couple of new recipes that are hardware-specific. You can usually find two very important recipes: the kernel recipe and the Android’s blobs recipe. Those recipes will need extra-care and are the topic of the two following paragraphs.

Creating an appropriate Linux kernel recipe

The kernel recipe describes how to fetch/patch/configure/compile/install/package the vendor kernel. All of those steps may need to be modified from your base recipe.

Getting kernel source

First of all, you need to find the git repository, branch and commit containing the source code of the watch you want to work on. Adapt SRC_URI and SRCREV accordingly.

Defconfig

Then, try to find your watch’s defconfig in the kernel’s arch/arm/configs/ directory. Copy this base defconfig onto meta-XXX-hybris/recipes-kernel/linux/linux-XXX/defconfig. If you're porting a watch with an android base before Oreo (8), you should be able to use the check-config script of meta-asteroid with the -w flag to fix a couple of configuration values. Android Pie (9)'s libraries generally need SELinux to function, and our config checker script hasn't yet been adapted for this. You'll need to go through and enable relevant SELinux options manually, and currently it's best to cross-reference against the changes that were made to the defconfig of [beluga https://github.com/AsteroidOS/meta-smartwatch/blob/master/meta-beluga/recipes-kernel/linux/linux-beluga/defconfig] or [triggerfish https://github.com/AsteroidOS/meta-smartwatch/blob/master/meta-triggerfish/recipes-kernel/linux/linux-triggerfish/defconfig].

Patches

If you need to patch your kernel’s tree, add the path to the patches to SRC_URI.

Boot image building

The output of a kernel compilation is a single zImage. In order to be started by your watch’s bootloader, this image needs to be packed with an initramfs into a single boot.img file. (for more information cf. Boot Process) Three different tools can be used to pack the boot.img file: abootimg, mkboot and mkbootimg. Since some watches only work with one of those tools (without any apparent reason), you can inherit one of the provided bbclass and adapt the config accordingly. Extra-Note: The Yocto project provides a handy manual on how to work with the Linux kernel with OpenEmbedded.

Building the Android's /system/ directory

In order to get a full AsteroidOS environment, you will need to install the Android HALs required by the usage of libhybris in various AsteroidOS components.

Actually, only a very limited set of libs from Android is needed. Some of those libs (like bionic) need to be patched and must be recompiled from source. Hence, you’ll need to start by cloning a modified and stripped down Android source tree to compile the needed drivers. You can find detailed info on the build process that has been used for dory in README-system-dir. You’ll most likely need to adapt those instructions to your own need, thus you are strongly encouraged to document your steps in your own README-system-dir for reproducibility and in order to help future porters.

Once you’ll get your first /system/ directory, you can modify meta-XXX-hybris/recipes-android/android/android_XXX-*.bb to use your prebuilt tarball. The next steps in hardware adaptation will most likely require you to iterate various modifications to this system directory so don’t get too emotionally attached to this tarball yet.

Boot

If you boot your generated boot.img from your watch’s bootloader, fastboot should load your kernel which will load the initramfs’s init script which will eventually load you rootfs’s init system. (for more information cf. Boot Process) You can usually know if those steps have successfully been completed when the watch stays up and running and shows the AsteroidOS boot logo for a while (shown by psplash which is ran by systemd on the rootfs). In case your boot stops earlier, you have a boot problem to debug.

You need to proceed by elimination to find what causes your boot to fail. First of all, disable the ramfs → rootfs switch by adding a bash infinite loop early in your ramdisk’s init script. If you notice your watch does not crash anymore, you may have an issue with your rootfs. The Troubleshooting section of the Boot Process page should help you retrieve your systemd logs and isolate the cause of your boot problem.

If your watch keeps on crashing, you may have a problem with your kernel. Start by making sure you tried the different boot.img packing tools. If the problem persists, you’ll want to retrieve your kernel’s message logs. This can usually be retrieved from a /proc/last_kmsg virtual file in Wear OS when enabling the CONFIG_ANDROID_RAM_CONSOLE kernel option. Analyzing the logs should also help narrowing down the issue to a faulty driver or config.

USB

If you have your AsteroidOS system running, you will want to get a shell access to it with adb or SSH over USB. Use dmesg -w on your computer to check if your watch appears after having been booted for a few seconds. If you don’t see your watch, you may have a problem with your USB setup.

First of all, try to replicate the config of your Wear OS’s init scripts in your ramdisk’s init script. Once you’re sure the USB config is the same, you should try to run adbd from your ramdisk instead of the rootfs, if it solves the problem you may have an issue with usb_moded not starting adbd or RNDIS properly.

If the problem is the same, you may have a problem with your kernel’s config or drivers. First of all, make sure CONFIG_USB_G_ANDROID is still enabled in the generated build/tmp-glibc/work/XXX-oe-linux-gnueabi/linux-XXX/*/git/.config as it is quite common to find bitbake removing this option. If the option is still there, your kernel may need special patches.

Display

As soon as you’ll get access to a shell on AsteroidOS, you may find yourself without asteroid-launcher running. Checking the system logs with journalctl –no-pager or systemctl –no-pager usually shows a segfault from the asteroid-launcher process. This is to be expected on your first run and there is nothing to worry about. In order to reproduce the bug, you can start asteroid-launcher manually with:

EGL_PLATFORM=hwcomposer QT_QPA_PLATFORM=hwcomposer asteroid-launcher

asteroid-launcher uses lipstick which uses the hwcomposer QPA which uses libhybris which uses the Android graphic HAL to display things on screen. You may need to adapt the Android graphic HAL to answer the needs of hybris. (usually a matter of starting the right android boot services, having the right files placed in the right directories, having the right system.prop options etc…)

For more information on the Graphic Stack you may want to refer to the associated documentation page. For more information on how to debug an issue, check the Troubleshooting paragraph of this page.


Touch

Once you’ll get asteroid-launcher displaying things on screen, you may have no touch feedback from the UI. If that is the case, you’ll need to modify the asteroid-launcher start command to use a different evdevtouch file. For example, tetra uses this bbappend to use /dev/input/event1 instead of the default event0.

Audio

Smartwatches usually don’t carry speakers but they often have microphones. AsteroidOS does not use those microphones yet but it’s usually easy to support and should be supported for the future of the project. AsteroidOS uses pulseaudio for its audio stack. pulseaudio takes benefits from the pulseaudio-droid-card module to use the Android’s Audio HAL. In order to test the microphone, you can install and run parec from the build/tmp-glibc/work/armv7vehf-neon-oe-linux-gnueabi/pulseaudio/15.0-r0/packages-split/pulseaudio-misc/ package. If you lack an audio interface, make sure you loaded the audio firmware.

In case a problem persist, enabling extra debug information from pulseaudio can give you detailed info on the cause of the issue.

To play an audio file use the following command:

gst-launch-1.0 filesrc location=input.mp3 ! mpegaudioparse! mpg123audiodec ! pulsesink

To make an audio recording, use the following command:

gst-launch-1.0 pulsesrc ! audioconvert ! wavenc ! filesink location=recording.wav

Bluetooth

Smartwatches make extensive use of Bluetooth for connectivity. The AsteroidOS project comes with a set of Bluetooth Low Energy profiles implemented in the asteroid-btsyncd server daemon and AsteroidOSSync client. (for more information cf. Bluetooth) Bluetooth required a few extra steps to work on your port.

asteroid-btsyncd uses BlueZ’s DBus API to create a BLE server. Those APIs require a recent Bluetooth subsystem in your kernel. Unfortunately, Wear OS watches usually come with outdated kernels and a newer BT subsystem needs to be backported. The patch used in dory can be found here and should be adaptable to your kernel’s tree with very few conflicts.

Most Wear OS smartwatches carry a Broadcom BT chip that requires a proprietary firmware to be applied with a tool named brcm-patchram-plus. This tool is called from a systemd service named patchram.service, your HW adaptation layer should include a modified patchram.service file that uses the provided vendor’s firmware and tty line. Information about the config you should use can be found in the Android’s libbt-broadcom repository.

With a backported BT subsystem and patched BT firmware, you should already be able to get Bluetooth connectivity on your port but with very limited battery life. Broadcom’s bluetooth’s low power mode is handled by a kernel module named Bluesleep (or more recently Nitrous) that expects custom information to be written in /proc/lpm/. With BlueZ, this proc interface is never used hence the kernel driver must be adapted to receive HCI events from the BT subsystem with a patch. Finally, brcm-patchram-plus must also be compiled with a special flag defining the target device and the low power mode options to use.


Sensors

In AsteroidOS, sensors can be used by developers through the QtSensors API that uses the sensorfw backend. Sensorfwd is a sensor daemon that can use libhybris to interface with the Android’s Sensors HAL.

Most watches have a dedicated microcontroller that interfaces with sensors. This means that a daemon or kernel module (or something else) is responsible to upload and interface with the microcontroller from AsteroidOS.

In order to use sensors on AsteroidOS, you need to make sure libhybris recognizes your sensors by running the test_sensors command. For some platforms it is required to start a sensor daemon. This can usually be found in Wear OS's init scripts. A likely output of test_sensor for a platform needing a sensor daemon is:

sensors_open() failed: Operation not permitted

For more information on how to debug an issue, check the Troubleshooting paragraph of this page.


Haptics

In AsteroidOS, vibrations can be used by developers through the QtFeedback and ngfd APIs that usually rely on a libhybris backend which uses the Android’s vibration HAL. In order to use vibration on Asteroid with the Android HAL, you need to make sure libhybris recognizes your vibrator by running the test_vibrator command. For more information on how to debug an issue, check the Troubleshooting paragraph of this page.

A much cleaner way to vibrate in AsteroidOS would be to use an ffmemless kernel driver and the sensorfwd’s ffmemless backend but most watches don’t come with such a kernel driver and it would need to be developed.


WLAN

WLAN is not used by AsteroidOS’s user-interface yet but it should be supported for the future of the project. Some information about setting up a Wi-Fi interface can be found in the last paragraph of the SSH documentation page.

Troubleshooting

While porting AsteroidOS to your watch, you will most likely meet all kind of problems. In order to debug what’s going wrong with your setup you should install debug tools such as strace and gdb and the required debug sybols to your generated rootfs. For example, you can temporarily append the strace gdb asteroid-launcher-dbg packages to the asteroid-image class.

Other logical places to look for information that may help you solve the problems are: dmesg, journalctl --no-pager and /system/bin/logcat.

Once you come up with more information about your bug, your first reflex should be to search the asteroid’s IRC logs for similar issues. The SailfishOS porters community is another great place to search for information, you may also want to try your chance at searching the merproject’s IRC logs. Lastly you can also look through the GitHub issues for more information by other porters.

If you still couldn’t find a solution to your problem in the logs, don’t hesitate to ask questions on the #asteroid IRC or #Asteroid:matrix.org channel. There should be several porters able to help you.

Upstream your work

That’s it, you can finally use AsteroidOS on your watch! Sharing your work with the rest community should be the final step to ensure your layer will be maintained through time. Start by requesting on IRC the creation of a new AsteroidOS/meta-XXX-hybris repository and send a pull request to this repository. Your work will be carefully reviewed and commented before being integrated upstream. You’ll also need to send a pull-request to the AsteroidOS/asteroid repository to integrate your machine to prepare-build.sh and join the very privileged circle of AsteroidOS porters! Make sure your work is correctly detailed on the Porting Status page and share a photo of your watch for public twitter announcement.