Porting Guide: Difference between revisions
No edit summary |
No edit summary |
||
| (9 intermediate revisions by 3 users not shown) | |||
| Line 1: | Line 1: | ||
[[Category:Porters]] | [[Category:Porters]] | ||
== Prerequisites == | |||
AsteroidOS is a Linux distribution, and therefore it can run on devices with mainline kernels, or with vendor kernels and hardware abstraction from other platforms such as Tizen. Most devices right now use Android kernels and Hybris, and therefore that's what this guide covers. | |||
In order to run AsteroidOS using Hybris, your watch needs to meet the following criteria: | |||
* It needs to currently be running WearOS or other Android variant | |||
* It needs to have an unlockable bootloader, and you need a way to write boot images to the device. | |||
** This means you need a USB data connection to the watch. A significant number of watches do not expose USB data connections (either charging wirelessly, or charging via a connector that only supports USB power), but USB can be found on the inside by a determined hacker. Porting without USB is outside the scope of this guide. | |||
* You need to have a copy of the kernel source. | |||
** This kernel needs to include the DTS, a structure of files that describe the device's hardware - Most vendor kernels include the DTS, but on newer watches the DTS has often been found to be incomplete. | |||
== Goal == | |||
By the end, you should end up with an AsteroidOS hardware adaptation layer, which consists of: | |||
* OpenEmbedded recipes describing the compilation of the various HW adaptation components. | * OpenEmbedded recipes describing the compilation of the various HW adaptation components. | ||
* An appropriate vendor kernel | ** An appropriate vendor kernel, likely with some patches applied to fix compilation issues, or add functionality needed by Hybris and AsteroidOS. | ||
* A set of Wear OS’s proprietary binary blobs used through libhybris in order to access some of the Android’s HALs. | ** 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. | *** These may either be shipped as part of the AsteroidOS install, or be mounted from an existing partition on the watch | ||
** Some middleware configuration files to use your HW adaptation. | |||
== Preflight: AsteroidOS bitbake environment == | |||
* If you've not got an AsteroidOS bitbake set up already, follow the instructions at [[Building AsteroidOS]]. | |||
* You may also want to go into meta-smartwatch and create a new branch for your port. As you're working, it's a good idea to make frequent commits so you can revert any changes. | |||
== Setting up the OpenEmbedded layer == | |||
In order to add the support of your watch to AsteroidOS, you’ll need to write an OpenEmbedded layer. An overview of layers is available in the [[OpenEmbedded]] page. | |||
The easiest way to create an OpenEmbedded layer for your device is to copy and modify one that already exists within [https://github.com/AsteroidOS/meta-smartwatch meta-smartwatch]. The device you copy from will depend on the Android version of your target device. | |||
{| class="wikitable" | |||
|+ | |||
!Android version | |||
!Best watch to copy | |||
|- | |||
|5 (lollipop) | |||
|dory | |||
|- | |||
|6 (marshmallow) | |||
|swift | |||
|- | |||
|7 (nougat) | |||
| | |||
|- | |||
|8 (oreo) | |||
|narwhal | |||
|- | |||
|9 (pie) | |||
|catfish | |||
|} | |||
Now, make sure you're in meta-smartwatch and run scripts/new-watch.sh SOURCECODENAME NEWCODENAME, such as scripts/new-watch.sh ray beluga , which will: | |||
== | * copy meta-BASECODENAME to meta-TARGETCODENAME | ||
* roughly replace all references to the base device's codename with the target device's codename | |||
==== machine.conf ==== | |||
In your new meta-XXX layer, edit <code>[https://github.com/AsteroidOS/meta-smartwatch/blob/master/meta-dory/conf/machine/dory.conf conf/machine/XXX.conf]</code>. This file describes general information about your specific watch, such as the kernel recipe, the display size and available sensors, and the packages that should be installed by default. | |||
== 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. | 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 === | === Getting kernel source === | ||
First of all, you need to find the [https://android.googlesource.com/kernel/msm/+refs git repository], branch and commit containing the source code of the watch you want to work on. Replace [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-kernel/linux/linux-dory_lp-mr1.bb#L11 SRC_URI] and [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-kernel/linux/linux-dory_lp-mr1.bb#L16 SRCREV] accordingly. | |||
==== Defconfig ==== | |||
Then, try to find your watch’s [https://android.googlesource.com/kernel/msm/+/android-msm-dory-3.10-marshmallow-mr1-wear-release/arch/arm/configs/dory_defconfig defconfig] in the kernel’s <code>arch/arm/configs/</code> directory. | |||
Copy this base defconfig onto <code>[https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-kernel/linux/linux-dory/defconfig meta-XXX/recipes-kernel/linux/linux-XXX/defconfig]</code>. | |||
If you're porting a watch with an android base before Oreo (8), you should be able to use the [https://github.com/AsteroidOS/meta-asteroid/blob/master/scripts/check-config <code>check-config</code> script of meta-asteroid] with the <code>-w</code> flag to fix a couple of configuration values. | |||
If you're porting a watch with an android base before Oreo (8), you should be able to use the [https://github.com/AsteroidOS/meta-asteroid/blob/master/scripts/check-config <code>check-config</code> script of meta-asteroid] with the <code>-w</code> flag to fix a couple of configuration values | |||
Post Pie (Android 9), 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. | |||
'''Extra-Note''': The Yocto project provides a [http://www.yoctoproject.org/docs/1.6.1/kernel-dev/kernel-dev.html handy manual] on how to work with the Linux kernel with OpenEmbedded. | '''Extra-Note''': The Yocto project provides a [http://www.yoctoproject.org/docs/1.6.1/kernel-dev/kernel-dev.html handy manual] on how to work with the Linux kernel with OpenEmbedded. | ||
== | ==== Patches ==== | ||
If you already know you need to patch your kernel’s tree, add the path to [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-kernel/linux/linux-dory/0001-Backport-mainline-4.1-Bluetooth-subsystem.patch the patches] to [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-kernel/linux/linux-dory_lp-mr1.bb#L14 SRC_URI]. | |||
==== Picking an Android boot image class ==== | |||
Kernel compilation will produce outputs (zImage-dtb, Image.gz-dtb, Image with separate dtb...) that will not directly boot on your watch. In order to be started by your watch’s bootloader, this image needs to be packed with an initramfs into a single android-format boot.img file. (for more information cf. [[Boot Process]]) | |||
The kernel recipe for most watches inherits one of the [https://github.com/AsteroidOS/meta-asteroid/tree/master/classes AsteroidOS-specific boot image assembly classes], which means that compiling the kernel will also assemble a boot image. | |||
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 [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-kernel/linux/linux-dory_lp-mr1.bb#L36 inherit] one of the [https://github.com/AsteroidOS/meta-asteroid/tree/master/classes provided bbclass] and adapt the config accordingly. | |||
<code>recipes-kernel/linux/linux-XXX-ver/img_info</code> defines variables used by the image assembly process, such as the kernel command line. | |||
== | === Your first boot === | ||
If you boot your | You should now have done all the work necessary for the boot image to build - so this is a good time to try doing that. | ||
==== Build ==== | |||
You can build just the bootable image for your watch using <code>bitbake linux-XXX</code>. | |||
* If the kernel compilation fails, you will need to patch the kernel. See if there are existing patches that fix the same problem for other watches. | |||
Once the kernel/boot image build succeeds, it will produce an output at <code>build/tmp/deploy/images/XXX/image.fastboot</code>. The specific name of this bootable image will depend on the image format and codename of your device. | |||
====== Forcing debug-ramdisk ====== | |||
For your first boot, we don't want to worry about switching into the rootfs. To stop the boot process before this, modify the [https://github.com/AsteroidOS/meta-asteroid/blob/master/recipes-core/initrdscripts/initramfs-scripts-android/init.sh#L42 init script] by adding a <code>true</code> after the line with the debug-ramdisk check. This will cause the watch to start adb instead, which serves as a useful checkpoint. | |||
==== Boot ==== | |||
To get your new image booted on the watch, get it into fastboot and make sure you've already unlocked the bootloader. Then you'll need to do one of the following things, depending on your device: | |||
* run <code>fastboot boot image.fastboot</code>. This tends not to work on newer watches | |||
* flash the image to recovery partition using <code>fastboot flash recovery</code> then | |||
** <code>fastboot reboot recovery</code> (which doesn't work the same on all devices) | |||
** use a button combination to reboot to recovery | |||
The following should now happen | |||
* Fastboot will load the DTB and your kernel | |||
* Once the kernel boots, it will load the initramfs' init script | |||
* In a normal boot, the init script will try to mount the rootfs, chroot into it and start systemd (see [[Boot Process]]) | |||
* However, if you forced debug-ramdisk (as mentioned above), it will instead start the adb daemon. You should now be able to see the watch appear as a usb adb device | |||
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.) 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 [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-core/initrdscripts/initramfs-boot-android/init.sh#L54 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|Boot Process page]] should help you retrieve your systemd logs and isolate the cause of your boot problem. | 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 [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-core/initrdscripts/initramfs-boot-android/init.sh#L54 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|Boot Process page]] should help you retrieve your systemd logs and isolate the cause of your boot problem. | ||
| Line 53: | Line 120: | ||
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 <code>/proc/last_kmsg</code> virtual file in Wear OS when enabling the <code>CONFIG_ANDROID_RAM_CONSOLE</code> kernel option. Analyzing the logs should also help narrowing down the issue to a faulty driver or config. | 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 <code>/proc/last_kmsg</code> virtual file in Wear OS when enabling the <code>CONFIG_ANDROID_RAM_CONSOLE</code> kernel option. Analyzing the logs should also help narrowing down the issue to a faulty driver or config. | ||
== USB == | == Rootfs == | ||
=== Build === | |||
To build the rootfs, run <code>bitbake asteroid-image</code>. This should produce an image at <code>build/tmp/deploy/images/XXX/asteroid-image-XXX.rootfs.ext4</code>. | |||
=== Flash === | |||
There are a few ways of getting the rootfs onto the device: | |||
* Classically, this would be done by flashing the <code>asteroid-image-XXX.rootfs.ext4</code> directly to the userdata partition - <code>fastboot flash userdata asteroid-image-XXX.rootfs.ext4</code>. This is still the most desirable way to do things, but some modern watches seem to have bootloader bugs which prevent this. | |||
* You may need to allow the bootloader or the original android to create its own filesystem in userdata, then drop <code>asteroidos.ext</code> in the root of this filesystem | |||
** If this is the only option on your device, you may want to use an [https://github.com/AsteroidOS/meta-smartwatch/blob/master/meta-beluga/recipes-core/initrdscripts/initramfs-scripts-android/init.machine.sh init script extension similar to beluga] | |||
==== Partition map ==== | |||
Modify <code>meta-XXX/recipes-core/initrdscripts/initramfs-scripts-android/machine.conf</code> (NB this is not <code>meta-XXX/conf/machine.conf</code>) so that the partitions match those on your watch. | |||
== Android binary blobs == | |||
Libhybris provides adaptations between Android HAL (hardware abstraction layers) and Linux-oriented userspace APIs such as Qt QPA for display, Geoclue for GPS, SensorFW for sensors. For this to work, we need to provide Hybris with some compiled bits of android: one group of binaries is patched for hybris and compiled from android source, while the other group of android binaries is extracted from the retail firmware of your device. | |||
==== For Android <=7: The android-xxx recipe ==== | |||
You'll be doing all your work in the <code>meta-XXX/recipes-android/android/android_XXX-*.bb</code> file. Here, in SRC-URI, you'll need two tarballs. These provide the two groups of android binaries needed by hybris: | |||
* For the Android version and CPU architecture of your device. | |||
** If a device with your android version already exists, you can point to same files such as in https://github.com/AsteroidOS/meta-smartwatch/blob/master/meta-dory/recipes-android/android/android_dory-mm.bb#L5C12-L5C87. | |||
** If there's no device with the same android version, you'll need to build these yourself. 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've build your first <code>/system/</code> directory, host it somewhere on the net (currently we use dropbox, which isn't ideal) and then point to it such as in [https://github.com/AsteroidOS/meta-smartwatch/blob/master/meta-dory/recipes-android/android/android_dory-mm.bb#L5C12-L5C87 github.com/AsteroidOS/meta-smartwatch/blob/master/meta-dory/recipes-android/android/android_dory-mm.bb#L5C12-L5C87]. | |||
* For your specific device | |||
** Generally, this means dumping the entirety of <code>/system/</code> from your device and packaging it up into a tarball. Host this somewhere on the net (currently we use dropbox, which isn't ideal), then point to it such as in https://github.com/AsteroidOS/meta-smartwatch/blob/master/meta-dory/recipes-android/android/android_dory-mm.bb#L6C5-L6C77 | |||
** Once you've done this, move on to the Peripheral bringup section below | |||
==== For Android >=8: Mounting /vendor/ ==== | |||
On newer versions of android, we instead mount the <code>/vendor/</code> partition as it already exists on the device. | |||
* in machine.conf, include on of the [https://github.com/AsteroidOS/meta-asteroid/tree/master/recipes-android/android generic oreo or pie android recipes]. | |||
** If there's no recipe for your android version, you may be able to get away with an earlier version, such as aurora using the android 9 blobs recipe for an android 11 port | |||
** If there's no recipe for your device architecture, you will need to build a new set of binaries for your device - ask in the matrix chat for help, as this process isn't well-documented. | |||
* make sure you added the vendor partition to the partition map | |||
== Peripheral bringup == | |||
=== 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 <code>dmesg -w</code> 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. | If you have your AsteroidOS system running, you will want to get a shell access to it with adb or SSH over USB. Use <code>dmesg -w</code> 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 [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-core/initrdscripts/initramfs-boot-android/init.sh#L26 your ramdisk’s init script]. Once you’re sure the USB config is the same, you should try to run [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-core/initrdscripts/initramfs-boot-android/init.sh#L52 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. | First of all, try to replicate the config of your Wear OS’s init scripts in [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-core/initrdscripts/initramfs-boot-android/init.sh#L26 your ramdisk’s init script]. Once you’re sure the USB config is the same, you should try to run [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-core/initrdscripts/initramfs-boot-android/init.sh#L52 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 <code>CONFIG_USB_G_ANDROID</code> is still enabled in the generated <code>build/tmp | If the problem is the same, you may have a problem with your kernel’s config or drivers. First of all, make sure <code>CONFIG_USB_G_ANDROID</code> is still enabled in the generated <code>build/tmp/work/XXX-oe-linux-gnueabi/linux-XXX/*/git/.config</code> as it is quite common to find bitbake removing this option. If the option is still there, your kernel may need special patches. | ||
== Display == | === 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 <code>journalctl –no-pager</code> or <code>systemctl –no-pager</code> 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: | 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 <code>journalctl –no-pager</code> or <code>systemctl –no-pager</code> 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: | ||
<pre> | <pre> | ||
| Line 70: | Line 176: | ||
== Touch == | |||
=== 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 [https://github.com/AsteroidOS/meta-tetra-hybris/tree/master/recipes-asteroid/asteroid-launcher this bbappend] to use <code>/dev/input/event1</code> instead of the default event0. | 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 [https://github.com/AsteroidOS/meta-tetra-hybris/tree/master/recipes-asteroid/asteroid-launcher this bbappend] to use <code>/dev/input/event1</code> instead of the default event0. | ||
== Audio == | === 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 [https://github.com/AsteroidOS/meta-asteroid/tree/master/recipes-multimedia/pulseaudio 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 <code>build/tmp | 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 [https://github.com/AsteroidOS/meta-asteroid/tree/master/recipes-multimedia/pulseaudio 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 <code>build/tmp/work/armv7vehf-neon-oe-linux-gnueabi/pulseaudio/15.0-r0/packages-split/pulseaudio-misc/</code> package. If you lack an audio interface, make sure you [https://github.com/AsteroidOS/meta-dory-hybris/commit/0276357cdb266ce28eb37ca958c70f5273d588cd loaded the audio firmware]. | ||
In case a problem persist, enabling [https://wiki.ubuntu.com/PulseAudio/Log extra debug information] from pulseaudio can give you detailed info on the cause of the issue. | In case a problem persist, enabling [https://wiki.ubuntu.com/PulseAudio/Log extra debug information] from pulseaudio can give you detailed info on the cause of the issue. | ||
| Line 80: | Line 187: | ||
To play an audio file use the following command: | To play an audio file use the following command: | ||
<pre> | <pre> | ||
gst-launch-1.0 filesrc location=input.mp3 ! mpegaudioparse! mpg123audiodec ! pulsesink | gst-launch-1.0 filesrc location=input.mp3 ! mpegaudioparse ! mpg123audiodec ! pulsesink | ||
</pre> | </pre> | ||
| Line 88: | Line 195: | ||
</pre> | </pre> | ||
== Bluetooth == | === 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. | 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. | ||
| Line 97: | Line 204: | ||
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 <code>/proc/lpm/</code>. With BlueZ, this proc interface is never used hence the kernel driver must be adapted to receive HCI events from the BT subsystem with [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-kernel/linux/linux-dory/0003-bluesleep-Use-kernel-s-HCI-events-instead-of-proc-bl.patch a patch]. Finally, brcm-patchram-plus must also be [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-android/brcm-patchram-plus/brcm-patchram-plus_git.bbappend#L3 compiled with a special flag] defining the target device and the [https://github.com/AsteroidOS/brcm-patchram-plus/commit/94fb127e614b19a9a95561b8c1a0716e2e1e6293 low power mode options to use]. | 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 <code>/proc/lpm/</code>. With BlueZ, this proc interface is never used hence the kernel driver must be adapted to receive HCI events from the BT subsystem with [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-kernel/linux/linux-dory/0003-bluesleep-Use-kernel-s-HCI-events-instead-of-proc-bl.patch a patch]. Finally, brcm-patchram-plus must also be [https://github.com/AsteroidOS/meta-dory-hybris/blob/master/recipes-android/brcm-patchram-plus/brcm-patchram-plus_git.bbappend#L3 compiled with a special flag] defining the target device and the [https://github.com/AsteroidOS/brcm-patchram-plus/commit/94fb127e614b19a9a95561b8c1a0716e2e1e6293 low power mode options to use]. | ||
=== Sensors === | |||
== 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. | 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. | ||
| Line 109: | Line 215: | ||
For more information on how to debug an issue, check the Troubleshooting paragraph of this page. | 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 <code>test_vibrator</code> command. For more information on how to debug an issue, check the Troubleshooting paragraph of this page. | In order to use vibration on Asteroid with the Android HAL, you need to make sure libhybris recognizes your vibrator by running the <code>test_vibrator</code> 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. | 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 == | |||
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| SSH documentation page]]. | 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| SSH documentation page]]. | ||
== Troubleshooting == | === 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 <code>strace gdb asteroid-launcher-dbg</code> packages to the [https://github.com/AsteroidOS/meta-asteroid/blob/master/classes/asteroid-image.bbclass#L9 asteroid-image class]. | 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 <code>strace gdb asteroid-launcher-dbg</code> packages to the [https://github.com/AsteroidOS/meta-asteroid/blob/master/classes/asteroid-image.bbclass#L9 asteroid-image class]. | ||
Latest revision as of 19:23, 27 June 2026
Prerequisites
AsteroidOS is a Linux distribution, and therefore it can run on devices with mainline kernels, or with vendor kernels and hardware abstraction from other platforms such as Tizen. Most devices right now use Android kernels and Hybris, and therefore that's what this guide covers.
In order to run AsteroidOS using Hybris, your watch needs to meet the following criteria:
- It needs to currently be running WearOS or other Android variant
- It needs to have an unlockable bootloader, and you need a way to write boot images to the device.
- This means you need a USB data connection to the watch. A significant number of watches do not expose USB data connections (either charging wirelessly, or charging via a connector that only supports USB power), but USB can be found on the inside by a determined hacker. Porting without USB is outside the scope of this guide.
- You need to have a copy of the kernel source.
- This kernel needs to include the DTS, a structure of files that describe the device's hardware - Most vendor kernels include the DTS, but on newer watches the DTS has often been found to be incomplete.
Goal
By the end, you should end up with an AsteroidOS hardware adaptation layer, which consists of:
- OpenEmbedded recipes describing the compilation of the various HW adaptation components.
- An appropriate vendor kernel, likely with some patches applied to fix compilation issues, or add functionality needed by Hybris and AsteroidOS.
- A set of Wear OS’s proprietary binary blobs used through libhybris in order to access some of the Android’s HALs.
- These may either be shipped as part of the AsteroidOS install, or be mounted from an existing partition on the watch
- Some middleware configuration files to use your HW adaptation.
Preflight: AsteroidOS bitbake environment
- If you've not got an AsteroidOS bitbake set up already, follow the instructions at Building AsteroidOS.
- You may also want to go into meta-smartwatch and create a new branch for your port. As you're working, it's a good idea to make frequent commits so you can revert any changes.
Setting up the OpenEmbedded layer
In order to add the support of your watch to AsteroidOS, you’ll need to write an OpenEmbedded layer. An overview of layers is available in the OpenEmbedded page.
The easiest way to create an OpenEmbedded layer for your device is to copy and modify one that already exists within meta-smartwatch. The device you copy from will depend on the Android version of your target device.
| Android version | Best watch to copy |
|---|---|
| 5 (lollipop) | dory |
| 6 (marshmallow) | swift |
| 7 (nougat) | |
| 8 (oreo) | narwhal |
| 9 (pie) | catfish |
Now, make sure you're in meta-smartwatch and run scripts/new-watch.sh SOURCECODENAME NEWCODENAME, such as scripts/new-watch.sh ray beluga , which will:
- copy meta-BASECODENAME to meta-TARGETCODENAME
- roughly replace all references to the base device's codename with the target device's codename
machine.conf
In your new meta-XXX layer, edit conf/machine/XXX.conf. This file describes general information about your specific watch, such as the kernel recipe, the display size and available sensors, and the packages that should be installed by default.
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. Replace 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/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.
Post Pie (Android 9), 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.
Extra-Note: The Yocto project provides a handy manual on how to work with the Linux kernel with OpenEmbedded.
Patches
If you already know you need to patch your kernel’s tree, add the path to the patches to SRC_URI.
Picking an Android boot image class
Kernel compilation will produce outputs (zImage-dtb, Image.gz-dtb, Image with separate dtb...) that will not directly boot on your watch. In order to be started by your watch’s bootloader, this image needs to be packed with an initramfs into a single android-format boot.img file. (for more information cf. Boot Process)
The kernel recipe for most watches inherits one of the AsteroidOS-specific boot image assembly classes, which means that compiling the kernel will also assemble a boot image.
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.
recipes-kernel/linux/linux-XXX-ver/img_info defines variables used by the image assembly process, such as the kernel command line.
Your first boot
You should now have done all the work necessary for the boot image to build - so this is a good time to try doing that.
Build
You can build just the bootable image for your watch using bitbake linux-XXX.
- If the kernel compilation fails, you will need to patch the kernel. See if there are existing patches that fix the same problem for other watches.
Once the kernel/boot image build succeeds, it will produce an output at build/tmp/deploy/images/XXX/image.fastboot. The specific name of this bootable image will depend on the image format and codename of your device.
Forcing debug-ramdisk
For your first boot, we don't want to worry about switching into the rootfs. To stop the boot process before this, modify the init script by adding a true after the line with the debug-ramdisk check. This will cause the watch to start adb instead, which serves as a useful checkpoint.
Boot
To get your new image booted on the watch, get it into fastboot and make sure you've already unlocked the bootloader. Then you'll need to do one of the following things, depending on your device:
- run
fastboot boot image.fastboot. This tends not to work on newer watches - flash the image to recovery partition using
fastboot flash recoverythenfastboot reboot recovery(which doesn't work the same on all devices)- use a button combination to reboot to recovery
The following should now happen
- Fastboot will load the DTB and your kernel
- Once the kernel boots, it will load the initramfs' init script
- In a normal boot, the init script will try to mount the rootfs, chroot into it and start systemd (see Boot Process)
- However, if you forced debug-ramdisk (as mentioned above), it will instead start the adb daemon. You should now be able to see the watch appear as a usb adb device
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.) 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.
Rootfs
Build
To build the rootfs, run bitbake asteroid-image. This should produce an image at build/tmp/deploy/images/XXX/asteroid-image-XXX.rootfs.ext4.
Flash
There are a few ways of getting the rootfs onto the device:
- Classically, this would be done by flashing the
asteroid-image-XXX.rootfs.ext4directly to the userdata partition -fastboot flash userdata asteroid-image-XXX.rootfs.ext4. This is still the most desirable way to do things, but some modern watches seem to have bootloader bugs which prevent this. - You may need to allow the bootloader or the original android to create its own filesystem in userdata, then drop
asteroidos.extin the root of this filesystem- If this is the only option on your device, you may want to use an init script extension similar to beluga
Partition map
Modify meta-XXX/recipes-core/initrdscripts/initramfs-scripts-android/machine.conf (NB this is not meta-XXX/conf/machine.conf) so that the partitions match those on your watch.
Android binary blobs
Libhybris provides adaptations between Android HAL (hardware abstraction layers) and Linux-oriented userspace APIs such as Qt QPA for display, Geoclue for GPS, SensorFW for sensors. For this to work, we need to provide Hybris with some compiled bits of android: one group of binaries is patched for hybris and compiled from android source, while the other group of android binaries is extracted from the retail firmware of your device.
For Android <=7: The android-xxx recipe
You'll be doing all your work in the meta-XXX/recipes-android/android/android_XXX-*.bb file. Here, in SRC-URI, you'll need two tarballs. These provide the two groups of android binaries needed by hybris:
- For the Android version and CPU architecture of your device.
- If a device with your android version already exists, you can point to same files such as in https://github.com/AsteroidOS/meta-smartwatch/blob/master/meta-dory/recipes-android/android/android_dory-mm.bb#L5C12-L5C87.
- If there's no device with the same android version, you'll need to build these yourself. 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've build your first
/system/directory, host it somewhere on the net (currently we use dropbox, which isn't ideal) and then point to it such as in github.com/AsteroidOS/meta-smartwatch/blob/master/meta-dory/recipes-android/android/android_dory-mm.bb#L5C12-L5C87.
- Once you've build your first
- For your specific device
- Generally, this means dumping the entirety of
/system/from your device and packaging it up into a tarball. Host this somewhere on the net (currently we use dropbox, which isn't ideal), then point to it such as in https://github.com/AsteroidOS/meta-smartwatch/blob/master/meta-dory/recipes-android/android/android_dory-mm.bb#L6C5-L6C77 - Once you've done this, move on to the Peripheral bringup section below
- Generally, this means dumping the entirety of
For Android >=8: Mounting /vendor/
On newer versions of android, we instead mount the /vendor/ partition as it already exists on the device.
- in machine.conf, include on of the generic oreo or pie android recipes.
- If there's no recipe for your android version, you may be able to get away with an earlier version, such as aurora using the android 9 blobs recipe for an android 11 port
- If there's no recipe for your device architecture, you will need to build a new set of binaries for your device - ask in the matrix chat for help, as this process isn't well-documented.
- make sure you added the vendor partition to the partition map
Peripheral bringup
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/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/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.