Sailfish OS HADK original - SailfishOS-for-the-fairphone-4/getting_started GitHub Wiki
This wiki is a fork of the official Sailfish OS Hardware Adaptation Development Kit 4.5.0.19 located here.
By following this guide you can set up a Sailfish OS (or another Sailfish Core based) Linux system that will run on an Android device, on top of an existing Android Hardware Adaptation kernel and drivers. This consists of:
- Sailfish Core: the GNU/Linux userspace core
- Android Hardware Adaptation (HA/HAL), consisting of:
- Device-specific Android Kernel
- Android base which can be:
- LineageOS - https://wiki.lineageos.org
- AOSP - Android Open Source Project - https://source.android.com
- CAF - Code Aurora Forum - https://www.codeaurora.org
- Sony Open Devices program - https://developer.sony.com/develop/open-devices
- Vendor-specific Android base
- Binary device drivers taken from an Android base
- Hybris patches to the Android base
- The libhybris interface built against the binary drivers
- Middleware packages depending on hardware-specific plugins
- A Qt/Wayland QPA plugin utilizing the Android hwcomposer
- Sailfish OS components
The development environment uses the Platform SDK, with:
- Build Tools consisting of cross-compilers (tooling) and an emulated rootfs for your device architecture (tar-get), containing device-specific headers and libraries – will also be referred as build environment through-out the document
- a HA build SDK (a minimal Ubuntu chroot required to build the Android sources)
During the HA development you’ll typically have one window/terminal using the HA build SDK where you build and work on Android code and another session using the Platform SDK where you build RPMs for the hardware adaptation. Setting up the Platform SDK, as well as the device-specific build environment and the Ubuntu HA build chroot is described in Setting up the SDKs.
Commands and output from the Platform SDK session are indicated using PLATFORM_SDK $ at the top of the code block, like this:
PLATFORM_SDK $
echo "run this command in the Platform SDK terminal"How to enter PLATFORM_SDK $ is explained in Setup the Platform SDK.
Commands and output from the HA build session are indicated using HABUILD_SDK $ at the top of the code block, like this:
HABUILD_SDK $
echo "run this command in the Ubuntu HA build SDK terminal"How to enter HABUILD_SDK $ is explained in Entering Ubuntu Chroot.
In this guide, we refer to the SDK directory hosting Platform SDK, Build Tools, and Ubuntu chroot with the environment variable $PLATFORM_SDK_ROOT. You need around 10GB of space in total.
There are a number of components to build; the lower level and Android related components are built in the HA build SDK; the rest are built in the Platform SDK.
-
In the HA build SDK
- a kernel
- a hacking friendly initrd which supports various boot options
- hybris-boot.img and hybris-recovery.img (for booting and debugging)
- a minimal Android /system/ tree
- modified Android parts for compatibility with libhybris and Sailfish OS (e.g. Bionic libc, logcat, init, . . . )
-
In the Platform SDK
- RPM packages containing all the built binaries and extracted configs
- Hardware-specific middleware and plugins (e.g. Qt QPA plugins, PulseAudio)
For distribution, RPM packages are uploaded to a HA-specific repository. With this repository, full system imagesusing the mic utility. The mic utility is usually also run inside the Platform SDK.
The hybris-boot.img (containing both the kernel and our custom initrd) is flashed to the device, while the Sailfish OS rootfs is placed in a subdirectory of the /data/ partition alongside an existing, unmodified Android system. The Sailfish OS rootfs is then used as a switchroot target with /data bind-mounted inside it for shared access to any user data
- An Android device officially supported by LineageOS 15.1 (Android 8), 16.0 (Android 9) and 17.1 (Android 10) at the time of writing 2021-02-12. CyanogenMod versions (that are Sailfish OS-compatible) 10.1.x,11.0, 12.1, 13.0, 14.1 will require additional effort because CM has become obsolete. For more supported Android versions also check this link
- Throughout this guide we shall use the term Android base, which will refer to the appropriate base that you are porting on: LineageOS, AOSP, CAF etc
- We also support Sony Open Devices program, and published guidelines how to rebuild flashable images for:
- Starting with Sailfish OS 3.4.0, support for 64bit ARM SFOS userspace has been added
- Sailfish OS adaptations starting with CM 13.0 (Android 6) were constructed by running a mix of 64bit Linux Kernel and Android HAL, whilst Sailfish OS userspace was being run in the 32bit mode. Such mixed mode is still supported, but we encourage porters to switch to full 64bit ports (using Xperia 10 II as reference)
- See https://wiki.lineageos.org/devices for a list of compatible devices
- See https://wiki.merproject.org/wiki/Adaptations/libhybris for a status list of devices already ported using HADK
- See https://wiki.merproject.org/wiki/Adaptations/libhybris/porters for a list of ports in early stages, and their authors to contact on the IRC
- AOSP or CAF Android base support is also possible, but we choose LineageOS for a wider range of devices. It will be up to the porter to patch an AOSP/CAF base with hybris patches. Remaining differences in using it are minimal (e.g. using the lunch command instead of breakfast)
- Means to do backup and restore of the device contents (e.g. SD card or USB cable to host computer), as well as flash recovery images to the device
- A 64-bit x86 machine with a 64-bit Linux kernel
- Sailfish OS Platform SDK (installation explained later)
- At least 30 GiB of free disk space (20 GiB source download + more for building) for a complete Android 6 build; a minimal download and HADK build (only hardware adaptation-related components) requires slightly less space. Newer Android base versions yield increasingly bigger size requirement
Verify that you can backup and restore your device and that you understand device recovery options. This is not only useful when flashing images you build with this guide, but also in case you want to reset your device to its factory state with stock Android (note that not all Android vendors provide factory images for download, so you might need to create a full backup of your running Android system and store it in a safe place before starting to erase and reflash the device with your custom builds).
As mentioned above, it might be helpful to backup the existing stock Android image before flashing the Android base release for the first time, as obtaining the stock image might be hard for some vendors (e.g. some stock images are only available as self-extracting .exe package for Windows) or impossible (some vendors do not provide stock images for download).
Use Android Recovery (e.g. TWRP or ClockworkMod) to:
- Backup to SD card: system, data, boot and recovery partitions
- Test restoring the backup (important)
Warning: While backing up to internal device storage is possible for some devices, if during porting you end up overwriting that partition, your backups will be gone. In that case (and in case of devices without SD card slots), it’s better to also copy the backup data to your development machine (e.g. via adb pull in recovery). Recent versions of adb support full-device backups to a host computer using the adb backup feature.
See the ClockworkMod Instructions for additional help.
Flash an image that you built or obtained of your Android base, whether it’s LineageOS, CAF, AOSP, or another.
The official LineageOS flashing instructions can be found on this LineageOS wiki page.
You may also want to verify that the Android base build for your device is fully functional, to avoid wasting time with hardware adaptations that have known issues. Also, your device might have some hardware defects - testing in Android verifies that all components are working correctly, so you have a functionality baseline to compare your Sailfish OS build results with.
You should at least check the following features:
- OpenGL ES 2.0: Use e.g. Gears for Android to test (the hz you will get there will be max refresh rate).
- WLAN connectivity: Connect to an AP, ad-hoc or set up a mobile access point with your device.
- Audio: Headset detection, earpiece speaker, loudspeakers, etc.
- Bluetooth: Connect to bluetooth headsets, verify discoverability, send files.
- NFC: Check if NFC tags can be detected, read and/or written by the device.
- SD/MicroSD: Use a file manager app to see if inserted SD cards can be detected.
- USB: MTP, mass storage (if available) and adb access.
- Telephony: 2G/3G/LTE calls + data connectivity.
- GPS: Using GPS Test, check GLONASS too; typical time to fix; AGPS.
- Sensors: Using AndroSensor: Accelerometer, Proximity Sensor, Ambient Light Sensor, Gyroscope, Magnetometer (Compass), Hall (flip case),...
- LEDs: If your device has notification LEDs or keypad backlights.
- Camera (front and back): Also test functionality of zoom, flash, etc...
- Buttons: Volume up, volume down, power, camera shutter, etc...
- Video out: HDMI / MHL connectivity if you have the necessary adapters. TV out.
- Screen backlight: Suspend and backlight control, minimum and maximum brightness.
- Battery meter: Charge level, battery health, charging via USB (wall charger and host PC).
- Vibration motor: Intensity, patterns.
- HW composer version: check dumpsys SurfaceFlinger through ADB (see SF Layer Debugging).
- Fingerprint sensor
- FM Radio
We recommend that you write down the results of these tests, so you can always remember them.
Throughout this guide we will be referencing the location of your SDK, device build environment and source code. As is customary with Android hardware adaptations, the device vendor ($VENDOR) and device codename ($DEVICE) are also used, both in scripts and configuration files. Throughout this guide as example, we’ll use Nexus 5 (lge/hammerhead for its vendor/device pair), and port it using CyanogenMod 11.0 version as the “Android base”. Thus ensure you read the code snippets carefully and rename where appropriate for your ported device/vendor/base
Now run the following commands on your host operating system fitting for your device and setup
HOST $
cat <<'EOF' > $HOME/.hadk.env
export ANDROID_ROOT="$HOME/hadk"
export VENDOR="lge"
export DEVICE="hammerhead"
# "armv7hl" is still supported, but we encourage to have full 64bit ports
export PORT_ARCH="aarch64"
# Uncomment the next line to conveniently build all RPMs in local repo:
#alias mb2='mb2 --output-dir "${ANDROID_ROOT?}/droid-local-repo/${DEVICE?}"'
EOF
cat <<'EOF' >> $HOME/.mersdkubu.profile
function hadk() { source $HOME/.hadk.env; echo "Env setup for $DEVICE"; }
export PS1="HABUILD_SDK [\${DEVICE}] $PS1"
hadk
EOFThis ensures that the environment is setup correctly when you use the ubu-chroot command to enter the Android SDK. It also creates a function hadk that you can use to set or reset the environment variables.
Instructions are found on Sailfish OS docs (“Quick start” section is enough, do not install SDK Targets yet): https://docs.sailfishos.org/Tools/Platform_SDK/Installation/
Afterwards, temporarily leave the PLATFORM_SDK to top up your ~/.bashrc with necessary commands:
PLATFORM_SDK $
exitHOST $
cat <<'EOF' >> $HOME/.bashrc
if [[ $SAILFISH_SDK ]]; then
function hadk() { source $HOME/.hadk.env; echo "Env setup for $DEVICE"; }
hadk
fi
EOF
sfossdkWarning: With Platform SDK version 4.4.0.58 and olders you need to check the MERSDK variable instead of SAILFISH_SDK in the above code snippet.
You’ll need some tools which are not installed into the Platform SDK by default:
- android-tools-hadk contains tools and utilities needed for working with the Android SDK
- kmod is needed by mic’s qemu to build the image
- createrepo_c is needed when passing local repo to mic
PLATFORM_SDK $
sudo zypper ref
sudo zypper in android-tools-hadk kmod createrepo_cThe minimum Platform SDK SFOS version is 4.3.0.15. Use sdk-assistant command to upgrade your build tools, or create from new (especially when updating from 2.x to 3.x). To check what release you are on:
PLATFORM_SDK $
# if no such file, you're on an old SDK version
cat /etc/os-releaseMore information about keeping your SDK up-to-date: https://github.com/sailfishos/sdk-setup/blob/master/ sdk-setup/README.tips.wiki#SDK_Maintenance
In order to maintain build stability, we use a Ubuntu GNU/Linux chroot environment from within the Platform SDK to build our Android source tree. For Android device ports that require OpenJDK 1.8 or newer, the following commands download and unpack the rootfs to the appropriate location:
PLATFORM_SDK $
TARBALL=ubuntu-focal-20210531-android-rootfs.tar.bz2
curl -O https://releases.sailfishos.org/ubu/$TARBALL
UBUNTU_CHROOT=$PLATFORM_SDK_ROOT/sdks/ubuntu
sudo mkdir -p $UBUNTU_CHROOT
sudo tar --numeric-owner -xjf $TARBALL -C $UBUNTU_CHROOTIn case you find you’re not able to gain sudo privileges inside the Ubuntu Chroot, execute the following inside the Platform SDK:
PLATFORM_SDK $
sudo chroot $UBUNTU_CHROOT /bin/bash -c "chage -M 999999 $(id -nu 1000)"PLATFORM_SDK $
ubu-chroot -r $PLATFORM_SDK_ROOT/sdks/ubuntu
# FIXME: Hostname resolution might fail. This error can be ignored.
# Can be fixed manually by adding the hostname to /etc/hostsHABUILD_SDK $
# Now you are in the HABUILD_SDK environment
# To leave, just type `exit` or Ctrl+D, and you'll be back to the PLATFORM_SDKOur ubu-chroot environment is based on 20.04 LTS which provides OpenJDK 1.8 or newer.
If your Android base build requires an older Java Development Kit, please install the legacy ubu-chroot instead:
PLATFORM_SDK $
TARBALL=ubuntu-trusty-20180613-android-rootfs.tar.bz2
curl -O https://releases.sailfishos.org/ubu/$TARBALL
UBUNTU_CHROOT=$PLATFORM_SDK_ROOT/sdks/ubuntu
sudo mkdir -p $UBUNTU_CHROOT
sudo tar --numeric-owner -xjf $TARBALL -C $UBUNTU_CHROOTOur build process is based around the Android source tree, but where needed we’ve modified some projects, in order to apply patches required to make libhybris function correctly, and to minimise the built-in actions and services in the init.*.rc files.
Ensure you have setup your name and e-mail address in your Git configuration:
HABUILD_SDK $
git config --global user.name "Your Name"
git config --global user.email "[email protected]"Ensure Ubuntu chroot has cpio installed:
HABUILD_SDK $
sudo apt-get install cpioYou also need to install the repo command from the AOSP source code repositories, see Installing repo.
Note: If your port requires OpenJDK 1.7 or older, use the older repo tool for legacy Python 2 systems
After you’ve installed the repo command, a set of commands below will download the required projects for building the modified parts of the Android base used in Sailfish OS hardware adaptations
All available Android base variants and versions that you can port on can be seen here: https://github.com/ mer-hybris/android/branches
Choose a version which has the best hardware support for your device.
Alternatively, you can patch an Android base of your choosing (e.g. be it CAF or AOSP or another).
The result of your Sailfish OS port will be an installable ZIP file. Before deploying it onto your device, you’ll have to flash a corresponding version of the Android base, so Sailfish OS can re-use its Android HAL shared objects.
If your primary ROM does not match your Android base or its version, and you would like to keep it on your device, then look for MultiROM support for it. Starting with its version v28, it supports booting Sailfish OS.
This porting guide is using Nexus 5 and CyanogenMod 11.0 version as example:
HABUILD_SDK $
sudo mkdir -p $ANDROID_ROOT
sudo chown -R $USER $ANDROID_ROOT
cd $ANDROID_ROOT
repo init -u https://github.com/mer-hybris/android.git -b hybris-11.0The local manifest contains device-specific repositories, for Android as well as for the mer-hybris builds.
If your device has already been ported, its codes properly placed on GitHub, you should check this repository: https://github.com/mer-hybris/local_manifests (choose the branch of hybris-* that your are porting to), and use $DEVICE.xml file instead of creating a new one in this chapter.
Create directory at first:
HABUILD_SDK $
mkdir $ANDROID_ROOT/.repo/local_manifestsIf your are working on a new port, you’ll have to create the local manifest yourself, which contains at least two repos: one for the kernel, another for the device configuration. Find those in the LineageOS device wiki, for Nexus 5 it would be https://wiki.lineageos.org/devices/hammerhead/build#initialize-the-lineageos-source-repository Local manifest below will also need pointing to correct branches - identify which one matches the default manifest branch (stable/cm-11.0 in Nexus 5 case).
Add the following content to $ANDROID_ROOT/.repo/local_manifests/$DEVICE.xm
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<project path="device/lge/hammerhead"
name="CyanogenMod/android_device_lge_hammerhead"
revision="stable/cm-11.0" />
<project path="kernel/lge/hammerhead"
name="CyanogenMod/android_kernel_lge_hammerhead"
revision="stable/cm-11.0" />
</manifest>Time to sync the whole source code, this might take a while: Do not use –fetch-submodules parameter on hybris 18.1 or newer Android bases.
HABUILD_SDK $
repo sync --fetch-submodulesThe expected disk usage for the source tree after the sync is 13 GB (as of 2015-09-09, hybris-11.0 branch). Depending on your connection, this might take some time. In the mean time, make yourself familiar with the rest of this guide.
Currently in Sailfish OS, udev starts after initrd, which leaves us not being able to use generic partition names (independent of partition number).
In initrd we then have to specify hardcoded /dev/mmcblkXpY nodes for /boot and /data partitions.
After initrd, systemd needs to mount all other required partitions (such as /system, /firmware, /persist, /config, . . . ) for the HAL layer to work. The required partitions are read from .fstab and init.rc files, disabled there, and respective .mount units created – all done by $ANDROID_ROOT/rpm (droid-hal-device).
Unfortunately, systemd cannot recognise named partition paths in .mount units, because of the same late start of udev, even though one can see already created nodes under /dev/block/platform/*/by-name/ or /dev/block/platform/*/*/by-name.
To work around this, we need to create a map between partition names and numbers in hybris/hybris-boot/fixup-mountpoints for each device, for all partitions – in this way we are sure to cover them all, because if done manually by looking through fstab/rc files, some might get unnoticed
To get that mapping, you should flash and boot an image of your Android base and execute adb shell on your host and something like this: ls -l /dev/block/platform/*/by-name/ on your device. To get the correct path you must find Android’s fstab in device repository or in device itself and get by-name path like: block/bootdevice/by-name/userdata, ls -l /dev/block/platform/*/*/by-name/ or block/platform/*/by-name/userdata from it.
Once you’ve patched fixup-mountpoints, take care if you ever have to run repo sync --fetch-submodules again because it will reset your changes, unless the file .repo/local_manifests/$DEVICE.xml is pointing hybris-boot to your fork with the needed fixup- mountpoints changes.
Then when you get to boot to the Sailfish OS UI, please don’t forget to upstream your fixup-mountpoints patch.
In the Android build tree, run the following in a bash shell (if you are using e.g. zsh, you need to run these commands in a bash shell, as the Android build scripts are assuming you are running bash).
You’ll probably need to iterate this a few times to spot missing repositories, tools, configuration files and others
Before building it is recommended to read extra Android base specific hints from https://github.com/mer-hybris/hadk-faq#android-base-specific-fixes
HABUILD_SDK $
source build/envsetup.sh
export USE_CCACHE=1
breakfast $DEVICE
make -j$(nproc --all) hybris-hal droidmediaThe relevant output bits will be in out/target/product/$DEVICE/, in particular:
- hybris-boot.img: Kernel and initrd
- hybris-recovery.img: Recovery boot image
- system/ and root/: HAL system libraries and binaries
The approximate size of the output directory out/ after make hybris-hal is 10 GB (as of 2019-03-14, hybris-sony-aosp-8.1.0_r52-20190206 branch).
Once the kernel has built you can check the kernel config. You can use the Mer kernel config checker:
HABUILD_SDK $
cd $ANDROID_ROOT
hybris/mer-kernel-check/mer_verify_kernel_config \
./out/target/product/$DEVICE/obj/KERNEL_OBJ/.configApply listed modifications to the defconfig file that your Android base is using. Which one? It’s different for every device, most likely first:
- Check the value of
TARGET_KERNEL_CONFIGunder$ANDROID_ROOT/device/$VENDOR/*/BoardConfig*.mk - Examine the output of
make bootimagefor which defconfig is taken when you’re building kernel, e.g.:make -C kernel/lge/hammerhead ... cyanogenmod_hammerhead_defconfig - Check your Android base kernel’s commit history for the
arch/arm*/configsfolder, look for defconfig
If you are in a rush, get rid only of ERROR cases first, but don’t forget to come back to the WARNING ones too. After you’ll have applied the needed changes, re-run make hybris-boot and re-verify. Lather, rinse, repeat :) Run also make hybris-recovery in the end when no more errors.
Fork the kernel repo to your GitHub home (indicated by myname in this doc).
For Nexus 5 with CM 11.0 as base, the next action would be (rename where appropriate to match your device/branch)
HABUILD_SDK $
cd kernel/lge/hammerhead
git checkout -b hybris-11.0
DEFCONFIG=arch/arm/configs/cyanogenmod_hammerhead_defconfig
git add $DEFCONFIG
git commit -m "Hybris-friendly defconfig"
git remote add myname https://github.com/myname/android_kernel_lge_hammerhead
git push myname hybris-11.0Create PR to the forked kernel repo under github/mer-hybris. Ask a mer-hybris admin to create one, if it isn’t there.
Adjust your .repo/local_manifests/$DEVICE.xml by replacing the line
<project path="kernel/lge/hammerhead"
name="CyanogenMod/android_kernel_lge_hammerhead"
revision="stable/cm-11.0-XNG3C" />with
<project path="kernel/lge/hammerhead"
name="myname/android_kernel_lge_hammerhead"
revision="hybris-11.0" />- If
repo sync --fetch-submodulesfails with a message like fatal: duplicate pathdevice/samsung/smdk4412-common in /home/nemo/android/.repo/manifest.xml, remove the local manifest withrm .repo/local_manifests/roomservice.xml - If
repo sync --fetch-submodulesfails with some other error message try runningrepo syncto see if it helps. This is usually needed for hybris-18.1 or newer Android bases. - If you notice
git clonecommands starting to write out “Forbidden . . . ” on github repos, you might have hit API rate limit. To solve this, put your github credentials into~/.netrc. More info can be found following this link: Perm.auth. with Git repositories -
error: Cannot fetch . . . (GitError: –force-sync not enabled; cannot overwrite a local work tree., usually happens if
repo sync --fetch-submodulesgets interrupted. It is a bug of the repo tool. Ensure all your changes have been safely stowed (check with repo status), and then workaround by:
HABUILD_SDK $
repo sync --force-sync
repo sync --fetch-submodules- In some cases (with parallel builds), the build can fail, in this case, use
make -j1... to retry with a non-parallel build and see the error message without output from parallel jobs. The build usually ends with the following output:
HABUILD_SDK $
...
Install: .../out/target/product/$DEVICE/hybris-recovery.img
...
Install: .../out/target/product/$DEVICE/hybris-boot.imgIt is necessary to emulate your target device architecture and file system to build hardware adaptation packages in the next section. Download and install your build tools following instructions below.
Important: Minimum version for SFOS target is 4.3.0.15 (same requirement as for the Platform SDK Chroot earlier)
Warning: To ensure consistency with HADK build scripts, name your tooling SailfishOS-4.5.0 (or whichever release you are building for) instead of suggested SailfishOS-latest, and your target as $VENDOR-$DEVICE-$PORT_ARCH (instead of SailfishOS-latest-aarch64). Ignore the i486 tar get.
For ARM devices, choose aarch64 build target, unless you are building for the armv7hl Sailfish OS userspace.
https://docs.sailfishos.org/Tools/Platform_SDK/Target_Installation/
To verify the correct installation of the build tools, cross-compile a simple “Hello, World!” C application with
mb2 build-shell:
PLATFORM_SDK $
cd $HOME
mkdir hadk-test-tmp
cd hadk-test-tmp
cat > main.c << EOF
#include <stdlib.h>
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
return EXIT_SUCCESS;
}
EOF
mb2 -t $VENDOR-$DEVICE-$PORT_ARCH build-init
mb2 -t $VENDOR-$DEVICE-$PORT_ARCH build-shell gcc main.c -o testIf the compilation was successful you can test the executable by running the following command (this will run the executable using qemu as emulation layer, which is part of the mb2 setup):
mb2 -t $VENDOR-$DEVICE-$PORT_ARCH build-shell ./testThe above command should output “Hello, world!” on the console, this proves that the build tools can compile binaries and execute them for your architecture.
In this chapter, we will package the build results of Building the Android HAL as RPM packages and create a local RPM repository. From there, the RPM packages can be added to a local target and used to build libhybris and the QPA plugin. They can also be used to build the rootfs.
If the folders rpm, hybris/droid-configs, hybris-droid-hal-version-$DEVICE do not exist yet, create them as follows (example is for Nexus 5, adjust as appropriate and push to your GitHub home):
PLATFORM_SDK $
cd $ANDROID_ROOT
mkdir rpm
cd rpm
git init
git submodule add https://github.com/mer-hybris/droid-hal-device dhd
# Rename 'hammerhead' and other values as appropriate
sed -e "s/@DEVICE@/hammerhead/" \
-e "s/@VENDOR@/lge/" \
-e "s/@DEVICE_PRETTY@/Nexus 5/" \
-e "s/@VENDOR_PRETTY@/LG/" \
dhd/droid-hal-@[email protected] > droid-hal-hammerhead.spec
# Please review droid-hal-hammerhead.spec before committing!
git add .
git commit -m "[dhd] Initial content"
# Create this repository under your GitHub home
git remote add myname https://github.com/myname/droid-hal-hammerhead.git
git push myname master
cd -
mkdir -p hybris/droid-configs
cd hybris/droid-configs
git init
git submodule add https://github.com/mer-hybris/droid-hal-configs \
droid-configs-device
mkdir rpm
sed -e "s/@DEVICE@/hammerhead/" \
-e "s/@VENDOR@/lge/" \
-e "s/@DEVICE_PRETTY@/Nexus 5/" \
-e "s/@VENDOR_PRETTY@/LG/" \
droid-configs-device/droid-config-@[email protected] > \
rpm/droid-config-hammerhead.spec
# Please review rpm/droid-config-hammerhead.spec before committing!
git add .
git commit -m "[dcd] Initial content"
# Create this repository under your GitHub home
git remote add myname https://github.com/myname/droid-config-hammerhead.git
git push myname master
cd -
rpm/dhd/helpers/add_new_device.sh
# On Nexus 5 the output of the last command is:
# Creating the following nodes:
# sparse/
# patterns/
# patterns/jolla-configuration-hammerhead.yaml
# patterns/jolla-hw-adaptation-hammerhead.yaml
cd hybris/droid-configs
git add .
git commit -m "[dcd] Patterns and compositor config"
git push myname master
cd -
mkdir -p hybris/droid-hal-version-hammerhead
cd hybris/droid-hal-version-hammerhead
git init
git submodule add https://github.com/mer-hybris/droid-hal-version
mkdir rpm
sed -e "s/@DEVICE@/hammerhead/" \
-e "s/@VENDOR@/lge/" \
-e "s/@DEVICE_PRETTY@/Nexus 5/" \
-e "s/@VENDOR_PRETTY@/LG/" \
droid-hal-version/droid-hal-version-@[email protected] > \
rpm/droid-hal-version-hammerhead.spec
# Please review rpm/droid-hal-version-hammerhead.spec before committing!
git add .
git commit -m "[dvd] Initial content"
# Create this repository under your GitHub home
git remote add myname \
https://github.com/myname/droid-hal-version-hammerhead.git
git push myname masterNow to complete you local manifest, this is how it would be done for Nexus 5. Do it for your device by renaming accordingly:
# add the next 3 entries into .repo/local_manifests/hammerhead.xml
<project path="rpm/"
name="myname/droid-hal-hammerhead" revision="master" />
<project path="hybris/droid-configs"
name="myname/droid-config-hammerhead" revision="master" />
<project path="hybris/droid-hal-version-hammerhead"
name="myname/droid-hal-version-hammerhead" revision="master" />Once all these 3 repositories get upstreamed under https://github.com/mer-hybris create PR into an appropriate branch of the file .repo/local_manifests/hammerhead.xml to the https://github.com/mer-hybris/local_manifests repository.
The $ANDROID_ROOT/rpm/ dir contains the needed .spec file to make a set of RPM packages that form the core Droid hardware adaptation part of the hardware adaptation. It also builds a development package (ends with devel) that contains libraries and headers, which are used when building middleware components later on.
Before building the packages it is recommended to read extra Android base specific hints from https://github.com/mer-hybris/hadk-faq#android-base-specific-fixes
The next step has to be carried out in the Platform SDK chroot:
PLATFORM_SDK $
cd $ANDROID_ROOT
rpm/dhd/helpers/build_packages.sh --droid-hal
rpm/dhd/helpers/build_packages.sh --configs
rpm/dhd/helpers/build_packages.sh --mw
rpm/dhd/helpers/build_packages.sh --gg
rpm/dhd/helpers/build_packages.sh --versionThis will compile all the needed packages, patterns, middleware and put them under local repository. If anything gets modified, just re-run the appropriate part.
-
Installed (but unpackaged) file(s) found: Add those files to straggler section in your
rpm/droid-hal-$DEVICE.specbefore the %include ... line, for example:
%define straggler_files \
/init.mmi.boot.sh\
/init.mmi.touch.sh\
/init.qcom.ssr.sh\
/selinux_version\
/service_contexts\
%{nil}- Lastly, re-run
build_packages.sh --droid-hal
See Middleware for a list of all middleware components (not all middleware components are used by every device adaptation). Most of them will have already been built by the build_packages.sh --mw script, but if you need an extra one, rebuild with rpm/dhd/helpers/build_packages.sh --mw=GIT_URL.
Via the flexible system of patterns, you will be able to select only working/needed functions for your device.
The default set of packages results in a minimal and functional root filesystem
It is forbidden to add proprietary/commercial packages to your image, because royalty fees need to be paid or licence constraints are not allowing to redistribute them. Examples:
- jolla-xt9 (predictive text input)
- sailfish-eas (Microsoft Exchange support)
- aliendalvik (Android™ App Support)
- sailfish-maps
- any non-free audio/video codecs, etc.
The selection of packages for each hardware adaptation has to be put into a pattern file, so that creating the image as well as any system updates in the future can pull in and upgrade all packages related to the hardware adaptation.
To make an extra modification to a pattern, edit its respective file under hybris/droid-configs/patterns/. Take care and always use git status/stash commands. Once happy, commit to your GitHub home and eventually PR upstream.
For patterns to take effect on the image, run the following:
PLATFORM_SDK $
cd $ANDROID_ROOT
rpm/dhd/helpers/build_packages.sh --configsYou need to choose a Sailfish OS version you want to build
Important: Avoid building older releases unless you know what you’re doing - we do not guarantee backwards compatibility for old Sailfish OS versions! E.g., expect patterns to break as new HA packages get introduced etc.
Ensure you pick the same release as your target was in Installing Build Tools for Your Device. E.g., if target’s ssu lr versions begin with 4.5.0., build Sailfish OS update 4.5.0.19 (check for the latest, non “Early Access” Sailfish OS version)
Build a rootfs using RPM repositories and a kickstart file (NB: all errors are non-critical as long as you end up with a generated .zip image):
PLATFORM_SDK $
# Set the version of your choosing, latest is strongly preferred
# (check with "Sailfish OS version" link above)
export RELEASE=4.5.0.19
# EXTRA_NAME adds your custom tag. It doesn't support '.' dots in it!
export EXTRA_NAME=-my1
rpm/dhd/helpers/build_packages.sh --micOnce obtained the .zip file, sideload via your device’s recovery mode, or examine other particular ways of deploying to your device.
Jolla Store functionality can be enabled only if your device identifies itself uniquely - either via IMEI or (for non-cellular devices) WLAN/BT MAC address. Consult us on #sailfishos-porters IRC channel on oftc.net about details.
If creation fails due to absence of a package required by pattern, note down the package name.
If that package is critical (e.g. libhybris, qt5-qpa-hwcomposer-plugin etc.), build and add it to the local repo as explained in Additional Packages for Hardware Adaptation. Afterwards perform:
Otherwise if a package is not critical, and you accept to have less functionality (or even unbootable) image, you can temporarily comment it out from patterns in hybris/droid-configs/patterns and orderly perform:
Alternatively (or if you can’t find it among patterns) provide a line beginning with dash (e.g. -jolla-camera) indicating explicit removal of package, to your .ks %packages section (remember that regenerating .ks will overwrite this modification).
Most likely the partition your Platform SDK resides in, is mounted with nodev option. Remove that option from mount rules
You can execute commands to build and install packages under the build environment, inspect and debug any issues. The syntax is shown in Installing Build Tools for Your Device.
Note that mb2 uses a working copy of your original build target, which means you can experiment with mb2 build-shell at will, but once you have found a desired fix, make it permanent by recording the changes in your source code (e.g. do not leave installed packages with zypper in lying around, but add them to your .spec’s BuildRequires).
If you break your build environment via mb2 build-shell, you can reset it back to its clean state via mb2 -t $VENDOR-$DEVICE-$PORT_ARCH build-requires reset. This happens implicitly after re-running build_packages.sh.
Use mb2 ... build-requires diff if you want to know what you have done to your build environment with mb2 in terms of installed/removed packages.
mb2 ... build-shell is limited to launch only from directories where you previously ran commands like mb2 ... build or mb2 ... build-init. Such commands are run under $ANDROID_ROOT during the build of dhd, so you can run mb2 build-shell from $ANDROID_ROOT if you find no better place.
This varies from device to device. There are a few different boot loaders and flashing mechanisms used for Android devices:
- fastboot: Used by most Nexus devices
- odin: Used by most Samsung devices
For flashing fastboot-based devices, use fastboot (available in the Platform SDK), for odin-based devices, use Heimdall.
Long story short, you will have to assume that you cannot:
- See any framebuffer console
- See any error messages of any kind during bootup
- Get any information relayed from your startup process
- Set any kind of modified kernel command lines
Hence, we have to learn how to operate blind on a device. The good news is that when you have a working kernel, you can combine it with a init ramdisk and that Android’s USB gadget is built in to most kernel configurations. It is possible then for the ramdisk to set up working USB networking on most devices and then open up a telnet daemon.
The hybris-boot repository contains such an initrd with convenient USB networking, DHCP and telnet server, plus the ability to boot into a Sailfish OS system. The init system in the hybris-boot initrd will attempt to write information via the USB device serial number and model. So dmesg on the host could produce:
HOST $
dmesg # sample output:
...
[1094634.238136] usb 2-2: Manufacturer: Mer Boat Loader
[1094634.238143] usb 2-2: SerialNumber: Mer Debug setting up (DONE_SWITCH=no)
...However dmesg doesn’t report all changes in the USB subsystem and the init script will attempt to update the iSerial field with information so also do:
HOST $
lsusb -v | grep iSerial # sample output:
iSerial 3 Mer Debug telnet on port 23 on rndis0 192.168.2.15 - also running udhcpd However, if it says something like:
[1094634.238143] usb 2-2: SerialNumber: Mer Debug setting up (DONE_SWITCH=yes)connectivity will be available via telnet 192.168.2.15 2323 port.
DEVICE $
devel-su
# change Storage=volatile --> Storage=automatic in:
vi /etc/systemd/journald.conf
mkdir /var/log/journal
rebootSystemd suppresses journal, and some valuable info might get hidden. To prevent this, set RateLimitInterval=0
If device bootloops, there might be several reasons:
- If it immediately reboots (and especially if it later boots to recovery mode), SELinux is enabled, and all ports based on Android 4.4 (hybris-11.0) up to Android 9.0 (hybris-16.0) need to disable it. Add
CONFIG_SECURITY_SELINUX_BOOTPARAM=yto your kernel defconfig, andselinux=0to your kernel command line (usually inBOARD_KERNEL_CMDLINEunder$ANDROID_ROOT/device/$VENDOR/*/BoardConfig*.mk) - If it reboots after a minute or so, be quick and telnet into device, then do:
ln -s /dev/null /etc/systemd/system/ofono.service- Check if your /system is mounted by systemd (system.mount unit)
To ease debugging in unstable/halting/logs spamming early ports:
DEVICE $
systemctl mask droid-hal-init
systemctl mask user@100000Use USB networking to connect to the Internet from your Sailfish OS
Execute on your host as root. Use the interface which your host uses to connect to the Internet. It’s wlan0 in this example:
HOST $
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
echo 1 > /proc/sys/net/ipv4/ip_forwardExecute on the device:
TARGET $
route add default gw 192.168.2.X # <- host's usb0 IP
echo 'nameserver 208.67.222.222' > /etc/resolv.confA boot.img file is basically a combination of a Linux kernel and an initramfs as cpio archive. The Platform SDK offer the mkbootimg to build a boot image from a kernel and cpio archive. To split a boot image, use split_bootimg in Platform SDK.
In the Sailfish OS port, a boot image with Sailfish OS-specific scripts will be built automatically. These boot images are then available as hybris-boot.img (for booting into Sailfish OS) and hybris-recovery.img (for debugging via telnet and test-booting).
In order to be able to use Sailfish OS on the device, the parts that we built and assembled in the previous chapters now need to be flashed to the device. After flashing, Sailfish OS should boot on your device on the next reboot
- Android Recovery flashed to your device
- The stock firmware image (for your version and device)
- The Android base release (for your version and device)
- A Sailfish OS rootfs update .zip, created by mic
It is important that you start with a fresh stock image that matches the Android base release version you are going to flash (which in turn is dictated by the Sailfish OS image you are going to flash).
While the Android base (e.g. CyanogenMod) .zip contains all files in /system/ (e.g. libraries and libhardware modules), the stock image also contains firmware parts and flashables for partitions that are not included in the Android base .zip.
For example, if you are running stock 4.4.2 on a Nexus 4 (mako), and you are going to flash CM 10.1.3 and Sailfish OS to it, you have to first flash the stock 4.2.2 (note that this is 4.2, not 4.4) first, so that the firmware bits are matching the CM version
If you do not flash the right stock version (and therefore firmware), there might be some issues when booting into Sailfish OS:
- Problems accessing
/sdcard/in recovery (e.g.adb pushdoes not work) - WLAN, sensors, audio and other hardware not working
If you experience such issues, please make sure you first flash the stock system, ROM, followed by the Android base image, and finally the Sailfish OS update. Please also note that you can’t just take the latest stock ROM and/or Android base ROM - both versions have to match the Android version against which the Sailfish OS adaptation was built.
- Boot into Android Recovery
- Upload the CM release:
adb push cm-10.1.3-$DEVICE.zip /sdcard/ - Upload Sailfish OS:
adb push sailfishos-$DEVICE-devel-1.2.3.4.zip /sdcard/ - In the Recovery on the device:
- Clear data and cache (factory reset)
- Install the CM release by picking the CM image
- Install Sailfish OS by picking the SFOS image
- Reboot the device
This assumes you are booted into the Android base on your device, can adb shell to it to get a root shell and have your boot image and rootfs tarball ready.
Some of these approaches also work in Android Recovery (there’s an adbd running).
Replace sailfishos-devel-hammerhead.tar.bz2 with the name of your rootfs tarball:
PLATFORM_SDK $
adb push sailfishos-devel-hammerhead.tar.bz2 /sdcard/
adb shell
su
mkdir -p /data/.stowaways/sailfishos
tar --numeric-owner -xvf /sdcard/sailfishos-devel-hammerhead.tar.bz2 -C /data/.stowaways/sailfishosThe following example is for hammerhead, for other devices the output partition and filename is obviously different:
PLATFORM_SDK $
cd $ANDROID_ROOT
adb push out/target/product/hammerhead/hybris-boot.img /sdcard/
adb shell
su
dd if=/sdcard/hybris-boot.img of=/dev/block/mmcblk0p19PLATFORM_SDK $
cd $ANDROID_ROOT
# to smoke test a boot image without flashing it:
fastboot boot out/target/product/$DEVICE/hybris-boot.img
# to permanently flash an image to boot partition:
fastboot flash boot out/target/product/$DEVICE/hybris-boot.img
adb shell
su
dd if=/sdcard/hybris-boot.img of=/dev/block/mmcblk0p19You can interact with the Sailfish OS rootfs and carry out maintenance (editing files, installing packages, etc..) when booted into an Android system. You have to have your rootfs already installed/extracted. You can use Android’s WLAN connectivity to connect to the Internet and download updates:
PLATFORM_SDK $
adb shell
su
mount -o bind /dev /data/.stowaways/sailfishos/dev
mount -o bind /proc /data/.stowaways/sailfishos/proc
mount -o bind /sys /data/.stowaways/sailfishos/sys
chroot /data/.stowaways/sailfishos/ /bin/su -
echo "nameserver 8.8.8.8" >/etc/resolv.conf
...You can setup to upgrade a Sailfish OS device over the air, a.k.a. OTA update.
- Ensure your Sailfish OS version is at least 3.2.1 (3.4.0 for aarch64)
- Create file 20-mydomain.ini (rename “mydomain” as you see fit) under
$ANDROID_ROOT/ hybris/droid-configs/sparse/usr/share/ssu/repos.d/with the following content:
[release]
adaptation=https://mydomain.net/%(release)/%(vendor)-%(adaptation)/%(arch)/- Substitute https://mydomain.net/ with your Web server address (including subpath if exists)
- The
%(release)/%(vendor)-%(adaptation)/%(arch)/format is advised, because it’s the most future-proof. E.g. for the Nexus 5 this string would resolve to4.5.0.19/lge-hammerhead/aarch64/ - Commit the above change to droid-configs (including updating the submodule, which introduces timestamped versioning, so updates get picked up)
- Make new image and ensure devices are flashed which will be receiving future updates
- Make some changes to your adaptation (e.g. fix some HW issue) and rebuild the affected part via
build_packages.sh, so that version numbers increase
Before deploying any updates to production, they must be tested first.
Prerequisites:
- Web server (e.g. Apache) running on HOST and accessible within network
- Directory listing doesn’t need to be enabled
- Assuming Web server’s rootdir is /srv/http
Perform the following:
HOST $
. ~/.hadk.env
rm -rf /srv/http/sailfish-tmp-test-repo
cp -ar $ANDROID_ROOT/droid-local-repo/$DEVICE /srv/http/sailfish-tmp-test-repo
rm -rf /srv/http/sailfish-tmp-test-repo/repo
createrepo_c /srv/http/sailfish-tmp-test-repoSSH into your device and execute (substituting https://mydomain.net with the address to your Web server):
DEVICE $
ssu ar sfos-test https://mydomain.net/sailfish-tmp-test-repo
devel-su -p pkcon install zypper
devel-su zypper refresh sfos-test
devel-su zypper dup --from sfos-testCheck that all the packages you touched are to be updated or removed as expected. Afterwards you can press “Yes” to execute the update and check if the device functions as desired, also after reboot.
Once happy, clean up the testing environment:
DEVICE $
ssu rr sfos-test
HOST $
rm -rf /srv/http/sailfish-tmp-test-repoOnce successfully tested, deploy the stable packages to the release repo:
HOST $
. ~/.hadk.env
rm -rf /srv/http/$RELEASE/$VENDOR-$DEVICE/$PORT_ARCH
mkdir -p /srv/http/$RELEASE/$VENDOR-$DEVICE
cp -ar $ANDROID_ROOT/droid-local-repo/$DEVICE \
/srv/http/$RELEASE/$VENDOR-$DEVICE/$PORT_ARCH
rm -rf /srv/http/$RELEASE/$VENDOR-$DEVICE/$PORT_ARCH/repo
createrepo_c /srv/http/$RELEASE/$VENDOR-$DEVICE/$PORT_ARCHTo receive the update, each device will have to execute devel-su -p version --dup, and reboot when instructed.
You can add any other RPM binary packages to the local build repository (i.e. packages that were not created by running build_packages.sh). For example:
PLATFORM_SDK $
cd $ANDROID_ROOT
# Alternatively you can use `mb2 --output-dir ... build` instead of copying
cp -a path/to/custom-built.rpm droid-local-repo/$DEVICETo make the devices of your users pull this RPM package in, ensure some other package or pattern requires it, then test and deploy your repo as per instructions above.
If another official Sailfish OS update has been released since you last published your HW adaptation update, perform the following:
Update your SDK target device build environment (see how in the last paragraph of Setup the Platform SDK).
Alternatively, you can remove it and create a new one as per Installing Build Tools for Your Device.
Remove or backup your local build repository:
PLATFORM_SDK $
cd $ANDROID_ROOT
PREV_RELEASE=4.4.0.68 # adjust to the previous release version you were on
mv droid-local-repo/$DEVICE droid-local-repo/$DEVICE-$PREV_RELEASE
mkdir droid-local-repo/$DEVICEThen rebuild all packages and a new image by executing build_packages.sh.
Afterwards test the rebuilt repo. The actual testing sequence on the device will be different:
DEVICE $
ssu ar sfos-test https://mydomain.net/sailfish-tmp-test-repo
ssu dr adaptation0
ssu re 4.5.0.19 # adjust to the actual version
devel-su -p version --dup
ssu rr sfos-test
ssu er adaptation0Then reboot as and test device functionality.
Once satisfactory, publish your repo for all users.
Finally, to receive the update, each device will have to execute:
DEVICE $
ssu re 4.5.0.19 # adjust to the actual version
devel-su -p version --dupNOTE: The %(release) in your self-hosted repo (visible via ssu lr) will get updated automatically after ssure.
After devel-su -p version --dup has finished, reboot as instructed.
Running Sailfish OS on top of a Mer Hybris adaptation requires a few modifications to the underlying Android base. We maintain forks of some repos with those patches applied.
Our modifications are tracked by our own Hybris-specific repo manifest file. The below sections outline our modifications to these sources.
In order to work with libhybris, some parts of the lower levels of Android need to be modified:
-
bionic/
- Pass errno from bionic to libhybris (libdsyscalls.so)
- Rename
/dev/log/to/dev/alog/ - TLS slots need to be re-assigned to not conflict with glibc
- Support for
HYBRIS_LD_LIBRARY_PATHin the linker - Add
/usr/libexec/droid-hybris/system/libto the linker search path
- external/busybox/: Busybox is used in the normal and recovery boot images. We need some additional features like mdev and udhcpd
-
system/core/
- Make cutils and logcat aware of the new log location (
/dev/alog/) - Add
/usr/libexec/droid-hybris/lib-dev-alog/to theLD_LIBRARY_PATH - Force SELinux OFF since hybris does not utilise the relevant Android parts, and leaving SELinux support ON would then cause device to reboot to recovery
- Remove various init and init.rc settings and operations that are handled by systemd and/or Hybris on a Sailfish OS system
- Make cutils and logcat aware of the new log location (
- frameworks/base/: Only build servicemanager, bootanimation and androidfw to make the minimal Droid HAL build smaller (no Java content)
- libcore/: Don’t include JavaLibrary.mk, as Java won’t be available
All these modifications have already been done in the mer-hybris GitHub organisation of forks from various Android sources. If its android manifest is used, these patches will be included automatically.
In addition to these generic modifications, for some devices and SoCs we also maintain a set of patches to fix issues with drivers that only happen in Sailfish OS, for example:
- hardware/samsung/: SEC hwcomposer: Avoid segfault if registerProcs was never called
For the Kernel, some configuration options must be enabled to support systemd features, and some configuration options must be disabled, because they conflict or block certain features of Sailfish OS.
-
Required Configuration Options: See
$ANDROID_ROOT/hybris/hybris-boot/init-scriptfunctioncheck_kernel_config()for a list of required kernel options -
Conflicting Configuration Options:
CONFIG_ANDROID_PARANOID_NETWORK: This would make all network connections fail if the user is not in the group with ID 3003
As an alternative to checking the kernel options in the initramfs, the script $ANDROID_ROOT/hybris/mer-kernel-check can also be used to verify if all required configuration options have been enabled.
For supported devices, the kernel is built as part of mka hybris-hal with the right configuration.
For new devices, you have to make sure to get the right kernel configuration included in the repository. For this, clone the kernel repository for the device into mer-hybris and configure the kernel using hybris/mer-kernel-check.
Sailfish OS uses some kernel interfaces directly, bypassing the android HAL. Mainly this is used in places where the kernel API is stable enough and also used by Android. The other reasons for using kernel APIs directly include better features offered by standard kernel frameworks, differing middleware between Sailfish OS linux and Android, and lastly special features of Sailfish OS.
The default vibra framework that is used in full featured productized Sailfish OS devices is the force feedback API in kernel input framework. The kernel drivers should either use the ffmemless framework OR provide FF_PERIODIC and FF_RUMBLE support via as a normal input driver. In this chapter we go through the ffmemless aproach of adapting your kernel for Sailfish OS
This is a different method than what is used in community Sailfish OS ports, which utilize the android vibrator / timed-output API. The android vibrator plugins in Sailfish OS middleware have very reduced feature set, and are not recommended for commercial products.
In order to utilize the standard input framework force feedback features of Sailfish OS, the android timed output vibrator kernel driver needs to be converted to a ffmemless driver. The main tasks for this are:
- Enable
CONFIG_INPUT_FF_MEMLESSkernel config option - Disable
CONFIG_ANDROID_TIMED_OUTPUTkernel config option - Change maximum amount of ffmemless effects to 64 by patching ff-memless.c:
- http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/input/ff-memless.c#n41
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index 117a59a..fa53611 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -39,7 +39,7 @@ MODULE_AUTHOR("Anssi Hannula <[email protected]>");
MODULE_DESCRIPTION("Force feedback support for memoryless devices");
/* Number of effects handled with memoryless devices */
-#define FF_MEMLESS_EFFECTS 16
+#define FF_MEMLESS_EFFECTS 64
/* Envelope update interval in ms */
#define FF_ENVELOPE_INTERVAL 50- Optionally you can decrease ff-memless control interval so that fade and attack envelopes can be used in short haptic effects as well:
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index 89d3a3d..33eee2e 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -41,7 +41,7 @@ MODULE_DESCRIPTION("Force feedback support for memoryless devi
#define FF_MEMLESS_EFFECTS 64
/* Envelope update interval in ms */
-static int ff_envelope_interval = 50;
+static int ff_envelope_interval = 10;
module_param(ff_envelope_interval, int, S_IWUSR | S_IRUGO);
#define FF_EFFECT_STARTED 0- If your platform happens to already support a ffmemless based vibra driver, just enable it and fix any issues that you see. Otherwise go through the rest of the points below.
- Convert the android timed output vibra driver to support to ffmemless
- Add
“#include <linux/input.h>” - Create a ffmemless play function.
- Examples of ffmemless play functions / ffmemless drivers:
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/input/misc/arizona-haptics.c#n110
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/input/misc/max8997_haptic.c#n231
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/input/misc/pm8xxx-vibrator.c#n130
- At probe, create a ffmemless device with input_ff_create_memless
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/input.h#n531
- And register the resulting device with input_device_register.
- Remember to clean up the input device structure at driver exit
- The example ffmemless drivers above can be used for reference
- Add
The userspace configuration haptic feedback and effects is handled with ngfd configuration files, see more details in
Sailfish OS 2.0 introduces GStreamer v1.0 with hardware-accelerated video and audio encoding and decoding in Camera, Gallery and Browser, and deprecates GStreamer v0.10.
The GStreamer-droid bridge is part of the integral build process. If you need to modify its source code, then rebuild it via:
PLATFORM_SDK $
cd $ANDROID_ROOT
rpm/dhd/helpers/build_packages.sh --ggLaunch the Camera app. If if shows black screen and becomes non-responsive, enable the audiosystem-passthrough-dummy-af package in the patterns and rebuild droid-configs.
If you find some parameters (such as ISO speed or other 3A settings) are missing from camera app, then it’s possible that your camera device is designed to use an older version of the Camera HAL than the default. You can try forcing a HAL v1 connection by adding FORCE_HAL:=1 to env.mk in droidmedia.
- Ensure Android’s RIL running
ps ax | grep rild(expect one or two/system/bin/rild) - If RIL is not running, check why it is not launched from /init*.rc scripts
- If it’s launched, check where it fails with
/usr/libexec/droid-hybris/system/bin/logcat -b radio - Errors in RIL might look like this:
RIL[0][main] qcril_qmi_modem_power_process_bootup: ESOC node is not available
After online search this suggests firmware loading issues on Motorola Moto G. Compare with a healthy radio logcat after booting back into CM, not all lines starting with E/RIL... will point to a root cause!
- If it’s firmware loading problem, trace all needed daemons in CM and their loading order as well as all mounted firmware, modem, and baseband partitions.
- Once RIL is happy, then ofono can be launched. Unmask it if it was previously masked due to causing reboots in Bootloops.
- If you still get no signal indicator in UI, remove SIM PIN and retry
- Also install
ofono-testspackage and run/usr/lib/ofono/test/list-modems - Try to recompile latest ofono master branch from https://github.com/sailfishos/ofono
- If everything else fails, then stop and strace a failing daemon (either RIL or ofono) from command line manually
If the calling parties cannot hear one another, then the audiosystem-passthrough-dummy-af middleware package is required, which should be enabled in the patterns.
For bluetooth Sailfish OS uses BlueZ stack from linux.
TODO: bluetooth adaptation guide.
TODO: add detail about audio routing.
Typically WLAN drivers are external kernel modules in android adaptations. To set up WLAN for such devices, a systemd service file needs to be created that loads the kernel module at boot. In addition to this you need to check that firmware files and possible HW tuning files are installed in correct locations on the filesystem.
Sailfish OS WLAN adaptation assumes the driver is compatible with WPA supplicant. This means the WLAN device driver has to support cfg80211 interface. In some cases connman (the higher level connection manager in Sailfish) accesses directly the WLAN driver bypassing wpa_supplicant.
The version of currently used wpa_supplicant can be checked from here: https://github.com/sailfishos/wpa_supplicant
The version of used connman can be checked from here: https://github.com/sailfishos/connman
On some android WLAN drivers, the whole connectivity stack needs to be reset after WLAN hotspot use. For that purpose there is reset service in dsme, please see details how to set that up for your adaptation project in here: https://github.com/sailfishos/dsme/commit/c377c349079b470db38ba6394121b6d899004963
Currently there is no NFC middleware in Sailfish OS. Android HAL API support should be enough for future compatibility.
Ensure the test_gps command gets a fix after a while.
The necessary middleware is already built for you, just add geoclue-provider-hybris package into your patterns.
For audio, Sailfish OS uses PulseAudio as the main mixer. For audio routing ohmd is used
TODO: Add info about audio routing configuration TODO: Add more info in general
Sailfish OS sensor support is based upon Sensor Framework at: https://github.com/sailfishos/sensorfw
Hybris based systems can use the hybris sensor adaptor plugins, which uses existing android libhardware sensor adaptations to read sensor data and control.
It can also be configured for standard linux sysfs and evdev sensor interfaces.
It should be configured at /etc/sensorfw/primaryuse.conf, which links to a device specific conf file. Historically named sensord-<BOARDNAME>.conf. You can also use any conf file by specifying it on the commandline.
For hybris based platforms, this will be sensord-hybris.conf, and most likely will not have to be modified. A copy of this file is already among default configs: https://github.com/sailfishos/sensorfw/blob/master/config/sensord-hybris.conf If you do make modifications to it, add the file under $ANDROID_ROOT/hybris/droid-configs/sparse/etc/sensorfw/primaryuse.conf
There are already a few device specific conf files to look at if the device needs more configuration. Example of mixed hybris and evdev configuration https://github.com/sailfishos/sensorfw/blob/master/config/sensord-tbj.conf
Generally, if sensors are working on the android/hybris side, they will work in sensorfw and up to the Sailfish UI. libhybris comes with /usr/bin/test_sensors which can list those Android sensors found
Above Sensor Framework is QtSensors, which requires a configuration file at /etc/xdg/QtProject/Sensors.conf which is supplied with the sensorfw backend plugin in QtSensors and a copy of it is already among your default configs.
For Sailfish Core based systems, the QtSensors source code is at: https://github.com/mer-qt/qtsensors
Debugging output of sensorfwd can be increased one level during runtime by sending (as root) USR1 signal like so: kill -USR1 pgrep sensorfwd or specified on the commandline for startup debugging
Sending kill -USR2 pgrep sensorfwd will output a current status report.
Under the hood, Sailfish OS uses the android wake locks. Typically there is no need to change anything in the kernel side (assuming it works fine with android) for the power management to work, as long as all the device drivers are working normally.
The userspace API’s for platform applications is exposed via nemo-keepalive package. See more details here: https://github.com/sailfishos/nemo-keepalive
A standard linux kernel watchdog core driver support is expected. The device node should be in /dev/watchdog. It should be configured with following kernel options:
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_CORE=y
CONFIG_WATCHDOG_NOWAYOUT=y- NOTE 1: Please note that watchdog driver should disable itself during suspend.
- NOTE 2: Normally the watchdog period is programmed automatically, but if your driver does not support programming the period, the default kicking period is 20 seconds.
Sailfish OS is compatible with standard kernel multitouch input framework drivers. Protocol A is preferred. The main configuration needed is to symlink the correct event device node to /dev/touchscreen. To do this the best way is to set up a udev rule that checks the devices with evcap script and creates the link once first valid one is found. See more details for evcap here: https://github.com/mer-hybris/evcap
The udev rule can be put to file:
/lib/udev/rules.d/61-touchscreen.rules
The reason this is not done by default is that typically driver authors mark bit varying capabilities as supported and there could be multiple touch controllers on a device, so the final rule is best to be written in a device specific configs package.
NOTE: if you still have problems with touch, please check that lipstick environment has correct touch device parameter:
cat /var/lib/environment/compositor/droid-hal-device.conf
-
LIPSTICK_OPTIONS should have “
-plugin evdevtouch:/dev/touchscreen”
Sailfish OS supports waking up the device from suspend (unblanking the screen) via double tap gesture to the touchscreen. The touchscreen driver should either emulate KEY_POWER press / release or post a EV_MSC/MSC_GESTURE event with value 0x4 when double tap gesture is detected when waking up from suspend.
In order to avoid excess power drain when device is in pocket facing users skin, some sysfs should be exported to allow disabling the touch screen. The feature requires that the device has a working proximity sensor that can wake up the system when it is suspended (to be able to update touch screen state according to need). To configure MCE that handles this see MCE configuration
This chapter contains some background information about the middleware parts that are part of the Hardware Adapation. Using this info, it should be possible to customize and build the middleware parts for a given device.
TODO
/etc/mce/60-doubletap-jolla.ini
Configures the touchscreen kernel driver sysfs that can be used to disable and enable double tap to wake up feature. Example of its content:
# Configuration for doubletap wakeup plugin
[DoubleTap]
# Path to doubletap wakeup control file
ControlPath=/sys/bus/i2c/drivers/touch_synaptics/3-0020/double_tap_enable
# Value to write when enabling doubletap wakeups
EnableValue=1
# Value to write when Disabling doubletap wakeups
DisableValue=0TODO:
/etc/mce/60-mce-cpu-scaling-governor.ini
/etc/mce/60-mce-display-blank-timeout.conf
/etc/mce/60-mce-display-brightness.conf
/etc/mce/60-mce-possible-display-dim-timeouts.conf
/etc/mce/60-memnotify-jolla.conf
The Non-Graphical Feedback Daemon provides combined audio, haptic, and LED feedback for system events and alarms. These events include such things as ring tones, message tones, clock alarms, email notifications, etc.
From here on shortened to NGFD.
TODO: add more detail about configuring NGFD.
Sailfish OS uses NGFD to provide haptic feedback. We use a QtFeedback plugin to bridge it with NGFD. The NGFD plugin is for providing feedback for events and alarms, it interfaces directly with QtFeedback that can be used by 3rd-party applications.
When configuring haptics it is important to know if your device uses ffmemless or the LED/Droid based vibrator interface.
To determine if your device uses the LED/native interface check for /sys/class/timed_output/vibrator/enable or /sys/class/leds/vibrator/activate. The exact path for these might be a little different in some cases, e.g. instead of vibrator the path could contain foobar, foobar being the device name in this case. Check for down below Non-Graphic Feedback Daemon Native Vibrator Plugin for more.
If these files are not present it is very likely that your device uses ffmemless to control haptics. To verify if your device uses ffmemless install the mce-tools package and run evdev_trace -i. If the listing contains a device with the type EV_FF then your device uses ffmemless.
The qt5-feedback-haptics-ffmemless used before Sailfish OS 4.3 is deprecated in favor of the before mentioned QtFeedback plugin.
When migrating away from qt5-feedback-haptics-ffmemless /usr/lib/qt5/plugins/feedback/ffmemless.ini can be removed without further intervention.
You can copy the Configuration file of the specific plugin used by your device to tune it fit better to your device.
The reason we have possibility for device specific effects is that hardware mechanics and the vibra engines differ greatly device-by-device, and single settings will not give good effect on all devices.
Good guideline for VKB haptic is that it should be as short as possible, and vibrate at the resonance frequency of the device mechanics when vibra engine reaches top magnitude of the vibra effect. It should not feel like vibration, but like a single kick.
TODO
This is the main plugin handling vibra feedback for Sailfish OS for devices that use the ffmemless interface.
The default configuration file can be found in /usr/share/ngfd/plugins.d/50-ffmemless.ini
The default configuration files can be over-ridden with setting environment variable NGF_FFMEMLESS_SETTINGS.
To set the environment variables add environment config file to your config package that installs to. Replace with your with the name of your device. E.g. mako, hammerhead etc.
/var/lib/environment/nemo/60-<device>-vibra.conf
And that file should look like below:
NGF_FFMEMLESS_SETTINGS=/usr/share/ngfd/plugins.d/ngf-vibra-<device>.ini
Now you can use the file to tune force feedback effects suitable specifically for your device. For template to start making your own configuration files, just copy-paste the ngfd 50-ffmemless.ini default config files as the de- vice specific files and then edit only needed bits.
An alternative instead of using the environment variable is duplicating the 50-ffmemless.ini in the same folder with a different name such as 51-ffmemless.ini, NGFD will now pickup your configuration file instead of the stock configuration file.
This especially affects those devices using ffmemless CUSTOM vibration patterns, read the default 50-ffmemless.ini. To check if the device uses ffmemless custom vibration patterns check if evdev_trace contains a device that contains FF_CUSTOM.
This plugin uses the native kernel interface from the timed output driver or the led vibrator interface. The native plugin doesn’t require any configuration normally.
It is possible to set the path of the activation and duration controls as shown below if the plugin can’t find these on its own:
[droid-vibrator]
native.path = /sys/class/leds/<device>/duration
native.activate_path = /sys/class/leds/<device>/activateReplace with the name of device directory for your vibration device.
It is the preferred method if the ffmemless plugin isn’t used.
This is a secondary vibra plugin for demoing and quick ports. It works out of the box with android timed output drivers. The feature set is reduced compared to ffmemless plugin.
TODO
TODO - more information about how PA works
This Qt Platform Abstraction plugin makes use of the libhardware hwcomposer API to send rendered frames from the Wayland Compositor to the actual framebuffer. While for some older devices, just flipping the fbdev was enough, more recent devices actually require using hwcomposer to request flipping and for vsync integration.
The important environment variables are:
- EGL_PLATFORM: For the Wayland Compositor, this needs to be set to fbdev on devices with older hwcomposer versions, and to hwcomposer for hwcomposer version 1.1 and newer. For best results, first try fbdev, and if it doesn’t work, try hwcomposer instead. For the Wayland Clients, this always needs to be set to wayland.
- QT_QPA_PLATFORM: For the Wayland Compositor, this needs to be set to hwcomposer to use the plugin. Previously, eglfs was used, but the hwcomposer module replaces the old plugin on Sailfish OS on Droid. For Wayland Clients, this always needs to be set to wayland.
When starting up an application (e.g. the Wayland Compositor, lipstick), the systemd journal (journalctl -fa as user root) will show some details about the detected screen metrics, which will come from the framebuffer device:
HwComposerScreenInfo:251 - EGLFS: Screen Info
HwComposerScreenInfo:252 - - Physical size: QSizeF(57, 100)
HwComposerScreenInfo:253 - - Screen size: QSize(540, 960)
HwComposerScreenInfo:254 - - Screen depth: 32Also, it will print information about the hwcomposer module and the device. In this specific case, the hwcomposer version is 0.3:
== hwcomposer module ==
* Address: 0x40132000
* Module API Version: 2
* HAL API Version: 0
* Identifier: hwcomposer
* Name: Qualcomm Hardware Composer Module
* Author: CodeAurora Forum
== hwcomposer module ==
== hwcomposer device ==
* Version: 3 (interpreted as 30001)
* Module: 0x40132000
== hwcomposer device ==The source tree contains different implementations of hwcomposer backends, each one for a different hwcomposer API version (see hwcomposer/hwcomposer_backend.cpp). Based on that detection, one of the existing implementations is used. Right now, the following implementations exist:
-
hwcomposer_backend_v0: Version 0.x (e.g. 0.3) of the hwcomposer API. It can handle swapping of an EGL surface to the display, doesn’t use any additional hardware layers at the moment and can support switching the screen off. The VSync period is queried from the hwcomposer device, but it will fall back to 60 Hz if the information cannot be determined via the libhardware APIs. (
EGL_PLATFORM=fbdev) -
hwcomposer_backend_v10: Version 1.0 of the hwcomposer API. It supports one display device, handles VSync explicitly and uses a single hardware layer that will be drawn via EGL (and not composed via hwcomposer). Swapping is done by waiting for VSync and uses libsync-based synchronization of posting buffers. Switching the screen off is also supported, and sleeping the screen disables VSync events. Also, the same VSync period algorithm is used (try to query from libhardware, fall back to 60 Hz if detection fails). (
EGL_PLATFORM=fbdev) -
hwcomposer_backend_v11: Version 1.1, 1.2, 1.3, 1.4, and 1.5 of the hwcomposer API. Versions higher or equal than 1.3 only support physical displays, whereas 1.1 and 1.2 support also virtual displays. This requires libsync and hwcomposer-egl from libhybris. Most of the hwcomposer 1.0 API properties apply, with the exception that frame posting and synchronization happens with the help of libhybris’ hwcomposer EGL platform. (
EGL_PLATFORM=hwcomposer)
Instead of running the Wayland Compositor (lipstick) on top of the hwcomposer QPA plugin, one can also run all other Qt 5-based applications, but the application can only open a single window (multiple windows are not sup- ported, and will cause an application abort). For multiple windows, Wayland is used. This means that for testing, it is possible to run a simple, single-window Qt 5 application on the framebuffer (without any Wayland Compositor in between) by setting the environment variables EGL_PLATFORM and QT_QPA_PLATFORM according to the above.
TODO
rpm/dhd/helpers/build_packages.sh now is taking care of builds/rebuilds/local repo preparation and patterns.
Please compile any other required packages should a build/mic process indicate a dependency on them. Feel free to add/remove those packages to/from patterns to suit your port’s needs.
Follow the exact same compilation approach as with above packages. Known packages are:
- https://github.com/mer-hybris/unblank-restart-sensors - needed only by mako
- droid-hal-$DEVICE Contains RPM packaging and conversion scripts for converting the results of the Android HAL build process to RPM packages and systemd configuration files
- hybris-boot Script run during Android HAL build that will combine the kernel and a custom initrd to hybris-boot.img and hybris-recovery.img. Those are used to boot a device into Sailfish OS and for development purposes.
- hybris-installer Combines the hybris-boot output and the root filesystem into a .zip file that can be flashed via Android Recovery.
- libhybris Library to allow access to Bionic-based libraries from a glibc-based host system (e.g. hwcomposer, EGL, GLESv2, ..).
- qt5-qpa-hwcomposer-plugin Qt 5 Platform Abstraction Plugin that allows fullscreen rendering to the Droid- based hardware abstraction. It utilizes libhybris and the Android hwcomposer module.
-
mer-kernel-check A script that checks if the kernel configuration is suitable for Sailfish OS. Some features must be enabled, as they are needed on Sailfish OS (e.g. to support systemd), other features must be disabled, as they conflict with Sailfish OS (e.g.
CONFIG_ANDROID_PARANOID_NETWORK) at the moment
For consistency, certain hardware adaptation / middleware plugin packages have to be named after a certain pattern.
As in the other chapters of this guide, $DEVICE should be replaced with the device codename (e.g. mako for Nexus 4), and the asterisk (*) is used as wildcard / placeholder.
Packages that are arch-specific (e.g. aarch64), device-specific and contain $DEVICE in their name:
- The arch-specific HAL RPMs (built from droid-hal-device) should be named
droid-hal-$DEVICE(e.g. droid-hal-mako,droid-hal-mako-devel,droid-hal-mako-img-boot,droid-hal-mako-kernel,droid-hal-mako-kernel-modules,droid-hal-mako-kickstart-configuration,droid-hal-mako-patterns,droid-hal-mako-policy-settingsanddroid-hal-mako-pulseaudio-settings) - The package containing kickstart files for mic should be named
ssu-kickstarts-$DEVICE(e.g.ssu-kickstarts-mako) Package that are arch-independent (noarch), device-specific and contain$DEVICEin their name: - The arch-independent HAL RPMs (built from droid-hal-device) should be named:
droid-hal-$DEVICE-*(e.g.droid-hal-mako-img-recoveryanddroid-hal-mako-sailfish-config) - The SensorFW libhybris plugin configuration should be named
hybris-libsensorfw-qt5-configs(hybris-libsensorfw-qt5-configs) Packages that are arch-specific (e.g. aarch64), device-specific, but do not contain $DEVICE: - RPMs built from libhybris should be named
libhybris-*(e.g.libhybris-libEGL) - Plugins for the non-graphic feedback daemon should be named
ngfd-plugin-*(e.g.ngfd-plugin-droid-vibrator); as well as their Qt pluginqt5-feedback-haptics-droid-vibrator(qt5-feedback-haptics-droid-vibrator) - The QPA hwcomposer plugin should be named
qt5-qpa-hwcomposer-plugin(qt5-qpa-hwcomposer-plugin) - The PulseAudio support modules should be named
pulseaudio-modules-droid(pulseaudio-modules-droid) - The GStreamer plugins should be named
libgstreamer0.10-* and/orgstramer0.10-*(e.g.libgstreamer0.10-gralloc,libgstreamer0.10-nativebuffer,gstreamer0. 10-omx,gstreamer0.10-droideglsinkandgstreamer0.10-droidcamsrc) - The SensorFW libhybris plugin should be named
hybris-libsensorfw-qt5(hybris-libsensorfw-qt5)
-
droid-hal-$DEVICE-*providesdroid-hal-*(e.g.droid-hal-$DEVICE-pulseaudio-settingsprovidesdroid-hal-pulseaudio-settings)
The above “rules” are the current state of our hardware adaptation. Here are some things that should be improved there:
- Some arch-specific packages contain arch-independent config files or binary blobs - make them arch independent (noarch) instead
- Unify the GStreamer plugin naming (either
libgstreamer0.10-*orgstreamer0.10-*) to not have two naming schemes there - The PulseAudio settings package usually is called
pulseaudio-settings-$DEVICE(we currently havedroid-hal-$DEVICE-pulseaudio-settings, maybe this can be implemented as a Provides:?) - The Linux kernel modules are in
droid-hal-$DEVICE-kernel-modulesat the moment, in other hardware adaptations we usekmod-xyz-$DEVICE - The recovery partition in the image at the moment is
droid-hal-$DEVICE-img-recovery, but for other hardware adaptations we usejolla-recovery-$DEVICE
Before publishing the adaptation, at least the following features should be checked.
-
Thermal sensor configuration for dsme
- Even if we do not enforce any limits, CSD1 gets temperature info from dsme
- Quick test:
dbus-send --system --print-reply --dest=com.nokia.thermalmanager /com/nokia/thermalmanager com.nokia.thermalmanager.battery_temperature
-
memnotify patch to kernel + config for mce
- Memory pressure normal|warning|critical affects for example browser
- Quick test:
ls /etc/mce/*memnot*
-
Watchdog driver in kernel + verify it works with dsme
- We want the device to reboot if userspace gets hopelessly stuck
- Some android kernels use hardware watchdog for kernel stuck detection
- Quick test:
journalctl -b | grep 'dsme.*watchdog'
-
usb-moded works
- Detects charger and PC correctly
-
USB diag mode works (optional)
- Only needed for factory releases, and not even always for those
-
USB gadget driver in kernel + verify it works with buteo-mtp
- Android has some MTP logic imlemented at kernel and thus some FFS stuff we need is typically missing
-
ssu config files
- Verify ssu & ssu-sysinfo agree on results
-
Vibra driver in kernel
- Patterns choose android vibra, LED vibra or ff-memless (memoryless force-feedback devices)
- ff-memless needs adding kernel driver
-
Suspend works
- If the device does not suspend, standby time will drop considerably
- There is a CSD test for this (Hardware tests->All tests->System state)
-
Resume via iphb works
- Only “official” way we have for scheduled wakeups from suspend
-
Volume key probing & policy works
- Display off -> no ringing volume change should happen
- Display off -> audio playback volume should change
- Both vol keys down -> UI snapshot should happen
-
Power key works
- Long press power key menu
- Double presses
- Loooong press shutdown in dsme
- False double press reporting from a single press
-
Proximity sensor works in suspend
- We have built in assumption of having up-to-date p-sensor state
- NB: If device does not have PS -> that must be configured
-
Ambient light sensor works
- Long sensor power up time -> can break display power on brightness
- Kernel side filtering / odd delta reporting -> breaks auto adjustments
- Total darkness should report “zero lux”
-
LED works
- Check the accuracy of colours and brightness
- Blocking at sysfs write can make mce unresponsive
- All but RGB LEDs probably require custom pattern config
-
Proximity blanking during active call works
- Some ports have weird problems here
-
CSD config
- HW features
- Factory test set
- Run-in test set
- Masked/blacklisted tests
- abootsettings etc. when applicable
-
Double tap works
- There has been many devices where gestures are supported but touch driver uses odd concepts
- zram in kernel
-
Look out for suspicious logging during bootup / shutdown
- Faster/slower/just different -> odd things can/will happen
-
usb-moded vs Android USB stuff in /*.rc
- Device serial number is assumed to come from Android side logic
- Otherwise Android stuff should preferably not touch USB in any way
-
Touch reporting
- Seems many Android kernels have issues around display power cycling & finger on screen
-
Act dead mode
- What Android services are needed varies from one device to another
- Act dead alarms need to be verified too
-
Extra filesystems enabled in kernel where possible
- BTRFS, F2FS, UDF, NFS, CIFS etc.