This guide is a step-by-step explanation of the process of porting a new device to Replicant 4.0.
A general good advice when porting a new device to Replicant is to look at how things are done on other devices and look at the commits that were made.
If your device fails to comply with one of these requirements, it won't be possible to port Replicant to it.
If you don't know about whether your device complies or not, you'll probably learn it along the way.
First of all, you'll have to find out the device's codename that was given by its manufacturer. Wikipedia usually has that information on the device's article. For instance, the codename for the European version of the Nexus S given by Samsung is i9023. This codename will help in the process of getting informations about the device.
Then, a second codename (that can turn out the be the same as the previous one) is given to the device at Android-level. If your device is supported by CyanogenMod, you can find it out from the CyanogenMod Wiki or on CyanogenMod download page. For instance, the Nexus S codename is: crespo
.
It is useful to have a general idea of what kind of hardware is present in the phone. From the Wikipedia and CyanogenMod pages about the device, it's already possible to know what System on a Chip (SoC) it uses and a couple other details.
To learn more details, you can consider looking for a teardown of the device (for instance on iFixit), that will reveal what chips are used on the device. Looking at the kernel defconfig for the device will also help a lot, you can also try to find the service manual for the device.
You can then compare that to the devices that are already supported in Replicant to get an idea of what will possibly work.
One very important step is to find out if the device is Tivoized: that means that even though the manufacturer releases the kernel source code for the device, the bootloader checks the kernel signature and will refuse to start it if it's not properly signed by the manufacturer. In other words, if you build the kernel yourself, the device will refuse to run it since it's not signed by the manufacturer. Since the Linux kernel is released under the GPLv2, there are no specific dispositions to counter Tivoization, and so porting the device to Replicant is pointless as it will require a prebuilt and signed kernel from the manufacturer.
This is not an easy information to find out, but the developers involved in the CyanogenMod port will probably know that information. It's a good idea to just ask them.
To install the future Replicant image on the device, you have to find out how the device can be flashed with a new operating system. The CyanogenMod Wiki has install guides for the supported devices and you'll probably find install guides for non-official CM ports as well. It is very important to understand the flashing procedure as it will have to be documented on the Replicant wiki.
There are basically two ways of flashing a new operating system:The key information to get before starting the port is the list of the non-free components that are required by CyanogenMod.
The easiest way to do this is to spot the device repository in CyanogenMod repos and look for the extract-files.sh
or proprietary-blobs.txt
file on the ics
branch.
There is usually a link to the device repository from the CyanogenMod Wiki
For instance, the list of non-free components for the Nexus S is extract-files.sh
From that list, spot what is related to what hardware component (audio, camera, sensors, gps, modem, etc): that gives an idea of the amount of work required to add support for the phone.
android_device_vendor_device
.android_device_vendor_devices-common
.android_kernel_samsung_devices
.You can find the device-specific repo from the device's page on the CyanogenMod Wiki.
Make sure you check out the branches that match the CM 9.0 version (the branch may be called ics
).
Once you have cloned the device-specific repo for your device and checked out the correct branch, refer to the cm.dependencies
file to find what repos are left to clone.
Clone these repos in the correct locations and remove the prefix (e.g. android_device_samsung_crespo
must be cloned in device/samsung/
and renamed to crespo
).
If your cloned the kernel source for your device, it is likely that the kernel build is already integrated, so you can skip the next sections below.
Once you have the kernel sources, read the instructions to find out which defconfig to use.
Since manufacturers usually don't release the git history along with the files, you'll need to recreate a git repo:git add -A
) and commit (git commit
) with a message explaining what you just imported (e.g. "GT-I9000 GB Opensource Update 2")Now that you have a git repo, you can move it to the Replicant code tree, under the name: kernel/vendor/devices
(e.g. kernel/samsung/aries
).
Make sure to make the devices
name match the devices
in android_device_vendor_devices-common
if the kernel is shared across these devices or to match the device
in android_device_vendor_device
.
Some devices are still using a prebuilt kernel. Even though the CyanogenMod team is trying to avoid that, it remains in many repos.
For such devices, you will need to remove the prebuilt binaries and the instructions to copy the prebuilt kernel and its modules.
In the device repository (device/vendor/device
) and common repository for your device (if any), remove the prebuilt kernel and modules (usually called kernel
and module.ko
(replace module with the name of a module) or a modules
directory).
Remove the instructions to copy these prebuilts on the makefiles. Remove instructions such as:
PRODUCT_COPY_FILES += \ $(LOCAL_KERNEL):kernel LOCAL_KERNEL := $(LOCAL_PATH)/kernel
TARGET_PREBUILT_KERNEL
as well as the instructions to copy the prebuilt modules.
The BoardConfig.mk
(or BoardConfigCommon.mk
in the common directory for your device) will most likely hold a line like:
TARGET_PREBUILT_KERNEL := device/samsung/p5/kernel
Now that the device repository has no prebuilt instructions, you can add the instructions to build the kernel. In the BoardConfig.mk
file, add the following lines:
TARGET_KERNEL_SOURCE := kernel/samsung/p3 TARGET_KERNEL_CONFIG := samsung_p5_defconfig
You need to find out which type of kernel image your device uses. Asking people who know about that is the best idea.
This is the easiest case to handle: just make sure the CONFIG_INITRAMFS_SOURCE
option in the kernel defonfig is left blank or undefined:
CONFIG_INITRAMFS_SOURCE=""
Building a zImage with a built-in initramfs requires the following steps:
In the kernel defconfig, define the CONFIG_INITRAMFS_SOURCE
option that way:
CONFIG_INITRAMFS_SOURCE="../../root"
Once this is done, duplicate the defconfig and add the _recovery
prefix before the _defconfig
ending (e.g. herring_recovery_defconfig
), edit that file and replace CONFIG_INITRAMFS_SOURCE
with:
CONFIG_INITRAMFS_SOURCE="../../recovery/root"
Back to the device repository, edit the BoardConfig.mk
file and add the following line:
TARGET_KERNEL_RECOVERY_CONFIG := samsung_p5_recovery_defconfig
_recovery_defconfig
ending).
Still in the device repository, create a bootimg.mk
file containing the following:
LOCAL_PATH := $(call my-dir) $(INSTALLED_BOOTIMAGE_TARGET): $(INSTALLED_KERNEL_TARGET) $(ACP) $(INSTALLED_KERNEL_TARGET) $@ $(INSTALLED_RECOVERYIMAGE_TARGET): $(INSTALLED_RECOVERY_KERNEL_TARGET) $(ACP) $(INSTALLED_RECOVERY_KERNEL_TARGET) $@
Edit the BoardConfig.mk
file and add the following line:
BOARD_CUSTOM_BOOTIMG_MK := device/vendor/device/bootimg.mk
device/vendor/device/
to the correct path to your device's repository.
Follow the previous instructions (zImage with built-in initramfs) and set the BOARD_USES_UBOOT
variable in the BoardConfig.mk
file:
BOARD_USES_UBOOT := true
Now that the repos are cloned, you need to modify some makefiles to cope with Replicant paths.
In the device repository (device/vendor/device
), modify the file called cm.mk
and replace the vendor/cm/
occurrences by vendor/replicant/
. Other makefiles may need that as well (in any case, build will fail very early if you missed one). In that same cm.mk
file, change the PRODUCT_NAME variable by replacing the cm
prefix with replicant
(e.g. change PRODUCT_NAME := cm_crespo to PRODUCT_NAME := replicant_crespo).
Now that your device files are ready, you can declare a new build target: these are held in vendor/replicant/jenkins-build-targets
.
Modify that file and add a line (at the end) with the PRODUCT_NAME you set and the -eng
suffix (e.g. replicant_crespo-eng
).
From now on, everything should be ready to start a build. To check for errors or missed occurrences, start a terminal in the Replicant tree root and lunch:
source build/envsetup.sh lunch replicant_device-eng
Adapt replicant_device-eng from what you added to the jenkins-build-target
(e.g. replicant_crespo-eng
).
If an error occurs, it will explicitly report it and you'll need to fix it before doing anything.
If everything works correctly, you should see something like:
============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=4.0.4 TARGET_PRODUCT=replicant_crespo TARGET_BUILD_VARIANT=eng TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a HOST_ARCH=x86 HOST_OS=linux HOST_BUILD_TYPE=release BUILD_ID=IMM76L ============================================
You must repeat these steps everytime before building anything on a freshly-opened terminal.
Remember:
source build/envsetup.sh lunch replicant_device-eng
Now that everything is set-up, you can build the first image to test on your device: the recovery image.
The build target is recoveryimage, so all you have to do is:
make -j9 recoveryimage
This should trigger the kernel build and the recovery initramfs build and in the end, produce the out/target/product/device/recovery.img
file.
Once your image is built (it takes some time), flash it to the recovery partition of your device (if any). It's a good idea to look at the CyanogenMod installation guide to find out how to install that recovery image.
There is usually also a key combination to hold to boot directly to recovery: hopefully, your recovery image will start.
It is time to build a complete set of Replicant images. This includes at least the system and kernel images. Depending on the installation method, an userdata image might be needed too.
Let's start by building the boot image, that is both the kernel and the Android initramfs. The build target is bootimage:
make -j9 bootimage
In the end, the out/target/product/device/boot.img
file will be produced.
It is time for you to take a good look at the installation process. Mainly, about whether the images will be flashed using the bootloader or recovery.
Since CyanogenMod uses the zip installation method, that we do not want to use, you're on your own here.
It will be easy to find out the filesystem for the different partitions if the device already runs CyanogenMod:
$ adb shell mount rootfs / rootfs ro,relatime 0 0 tmpfs /dev tmpfs rw,nosuid,relatime,mode=755 0 0 devpts /dev/pts devpts rw,relatime,mode=600 0 0 proc /proc proc rw,relatime 0 0 sysfs /sys sysfs rw,relatime 0 0 none /acct cgroup rw,relatime,cpuacct 0 0 tmpfs /mnt/asec tmpfs rw,relatime,mode=755,gid=1000 0 0 tmpfs /mnt/obb tmpfs rw,relatime,mode=755,gid=1000 0 0 none /dev/cpuctl cgroup rw,relatime,cpu 0 0 /dev/block/mtdblock2 /system yaffs2 ro,relatime 0 0 /dev/block/mtdblock3 /cache yaffs2 rw,nosuid,nodev,relatime 0 0 /dev/block/mtdblock5 /radio yaffs2 rw,relatime 0 0 /dev/block/mmcblk0p2 /data ext4 rw,nosuid,nodev,noatime,nodiratime,barrier=1,data=ordered,noauto_da_alloc 0 0 /dev/block/mtdblock6 /datadata yaffs2 rw,relatime 0 0 /dev/block/mtdblock4 /efs yaffs2 rw,relatime 0 0 /sys/kernel/debug /sys/kernel/debug debugfs rw,relatime 0 0 /dev/block/vold/179:1 /mnt/sdcard vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0702,dmask=0702,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0 /dev/block/vold/179:1 /mnt/secure/asec vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0702,dmask=0702,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0 tmpfs /mnt/sdcard/.android_secure tmpfs ro,relatime,size=0k,mode=000 0 0
So we can deduce that system is yaffs2 and data is ext4. Don't bother about the other partitions and mount-points, only /system and /data matter for now.
You have to modify the BoardConfig.mk
file on the main device repository (it might be delegated to BoardConfigCommon.mk
on the common repos).
To build ext4 system and userdata images, make sure you have:
TARGET_USERIMAGES_USE_EXT4 := true
TARGET_USERIMAGES_USE_EXT4 := false
If the images have to be flashed using recovery, you must make sure they are built in yaffs2 format, with the default page and spare sizes.
Make sure to remove the following lines from BoardConfig.mk
(even though the values might be different):
BOARD_NAND_PAGE_SIZE := 4096 BOARD_NAND_SPARE_SIZE := 128
TARGET_USERIMAGES_USE_EXT4 := false
Even though the images are built as yaffs2, it doesn't mean that the filesystem on the device will be yaffs2: you have to set the correct filesystem, amongst: ext4, yaffs2 in the built image file name.
That means you have to change the target images names. This is done by adding the following line (adapted for your device) on BoardConfig.mk
:
BOARD_CUSTOM_USERIMG_MK := device/vendor/device/userimg.mk
userimg.mk
file on the device main repository, with the following contents (adapt the target name):
INSTALLED_SYSTEMIMAGE_TARGET := $(PRODUCT_OUT)/system.ext4.img $(INSTALLED_SYSTEMIMAGE_TARGET): $(INSTALLED_SYSTEMIMAGE) @echo -e ${CL_INS}"Install system fs image: $@"${CL_RST} $(hide) mv $(INSTALLED_SYSTEMIMAGE) $(INSTALLED_SYSTEMIMAGE_TARGET) systemimage: $(INSTALLED_SYSTEMIMAGE_TARGET)
Building the system is the longest task. The build target is systemimage:
make -j9 systemimage
You might encounter build errors due to the lack of non-free libs. You'll need to find clean workarounds for that. Removing options from BoardConfig.mk
can help solve the situation.
For instance, the following error:
make: *** No rule to make target `out/target/product/i9300/obj/lib/libTVOut.so', needed by `out/target/product/i9300/obj/EXECUTABLES/mediaserver_intermediates/LINKED/mediaserver'. Stop.
BOARD_USE_SECTVOUT
to false:BOARD_USE_SECTVOUT := false
Once the systemimage is built, you have to build the userdataimage if you're going to flash using the bootloader:
make -j9 userdataimageWhen all the images are built, you're ready for flashing the images.
md5sum system.ext4.img boot.img > checksum.md5
If everything was correctly setup, this should succeed. The best way to make sure it booted is to run adb logcat
and wait for an output.
That early, it is very likely that graphics will be broken, so don't expect anything to show up on the screen: only adb is a reliable way of knowing whether it worked.
Keep in mind that all the make (and such) commands must be run in a terminal where lunch has been executed before.
Once you have a Replicant image installed on the device, there is no need to rebuild a whole image everytime you make a change (but it's a good idea to do it from time to time): you can instead rebuild only a single module by using (where module is the module's name):
make module
Even better, you can build the module that sits in the current directory by simply using mm
. To push the new library to the device, use adb push
(you'll need to adb remount
the first time).
Moreover, instead of rebooting, you can kill the Android applications (zygote
, surfaceflinger
, rild
) depending on what you are working on.
For instance for audio:
adb shell killall zygote
adb shell killall surfaceflinger
adb shell killall rild
Be sure to always look what's going on in logs.
For the main buffer:
adb logcat
adb logcat -b radio
Generally speaking, libEGL is non-free while gralloc and hwcomposer might be free software (but they often rely on non-free blobs). On most Replicant-supported phones, we use the default gralloc, the software libEGL and no hwcomposer. We modified the gralloc so that is uses RGB565 on framebuffer, which turns out to be faster than any other format we tried.
However, to have a fluid-enough experience, you need to disable most hardware-accelerated features of Android to enable Software GL.
This is done by modifying the cm.mk
Makefile on the device repository. Add the following lines after the others inherit calls:
# Inherit Software GL configuration. $(call inherit-product, vendor/replicant/config/software_gl.mk)
Moreover, you might need to add the Software GL configuration on the egl.cfg
file, that is located somewhere in the device repository (perhaps under config/
).
Add the following line at the beginning of the file (if it's not there already):
0 0 android
This will prevent surfaceflinger from doing a SEGFAULT.
To find out whether your device uses ALSA or not, look if you have the /dev/snd/pcmC0D0c
and /dev/snd/pcmC0D0p
nodes available. A non-standard interface aside might be indicated by the presence of the /dev/snd/hwC0D0
node.
If your device is standard ALSA, you can use the tinyalsa-audio library (located under hardware/tinyalsa-audio
) with a configuration file (an example of such a file is available at device/samsung/galaxys2/configs/tinyalsa-audio.xml
). You can find the propers controls to set on which scenario by running tinymix
(found under external/tinyalsa
) with the non-free blob in place in the different scenarios.
If your device involves a non-standard interface or if it completely relies a non-standard interface, there is no readily available guide to find out how it works, but you can start by looking at the kernel driver and adding debug prints (with printk) there and figure out what is going on.
Remember to add the working audio module to the build targets (on the makefiles in the device repo).
In order to support telephony, messaging (SMS) and other network-related features (data as well), you need to make the modem work with Replicant. The modem is often called the radio in Android terminology.
The modem uses a protocol to communicate with the CPU. You need to find out which protocol the modem for your device is using. There are several possible cases:To find out which protocol your phone uses, it is a good idea to look at the radio log buffer in CyanogenMod and try to find out from the messages (it may be verbose).
The protocol itself is implemented in the RIL (Radio Interface Layer): it is a good idea to take a look at the non-free ril the device uses (get its path with getprop rild.libpath
).
If the modem uses the AT protocol, there are many available RIL implementations out there: Android has a reference-ril (hardware/ril/reference-ril
) that implements AT and there is the hayes-ril library (located under hardware/ril/hayes-ril/
) that makes it easier for you to add support for your device. Though, it is possible that the modem of your device implements undocumented commands, so you'll have to figure these out: the radio log might help a lot if it's verbose, else you'll have to trace the RIL somehow.
If the protocol is not AT, it might still be supported: the FreeSmartphone.Org (FSO) project implements some undocumented protocols. You can also look at oFono.
If your phone was manufactured by Samsung, there is a very good chance that it uses the Samsung-IPC protocol, which is implemented in libsamsung-ipc and Samsung-RIL. You will need to add support for your device in libsamsung-ipc (Samsung-RIL is device-independent: all the abstraction is done by libsamsung-ipc), which may be more or less easy depending on whether your modem type is already supported. In any case, you'll need to trace the RIL to find out. There may also be a separate daemon (often called cbd) that is in charge of the modem bootup (that's the biggest part you need to figure out), so that's the thing to trace.
If the protocol implementation is nowhere to be found, you'll have to write a free implementation yourself if you want to have free software support for the modem. It's a good idea to ask around whether other people from other communities, such as XDA or CyanogenMod, would be interested in helping you.
After finding a RIL that may work, add it to the build targets (in the device makefiles) and specify the path to the RIL with rild.libpath
(it is often already declared in system.prop in the device repo).
Once the RIL is working, you may need the audio module cooperation to have sound during calls. For instance with Samsung-RIL, you need to use an Audio-RIL-Interface that implements the Samsung-RIL-Socket interface.
It is very likely that your device requires loaded firmwares for some components of the hardware. These are non-free programs that run separately from the CPU, on other chips. Since Replicant respects its users' freedom, no non-free firmwares are shipped with Replicant. It is possible that CyanogenMod includes shareable non-free firmwares in its tree: you must remove them.
Sometimes, components will crash (and may restart in an endless loop) when attempting to load a firmware that is not shipped with Replicant: you have to spot the code that loads the firmware and make it properly handle the case where the firmware is not available.
Though, you should keep in mind that some users may want to use that firmware, so you have to make the firmware loading possible. There are some exceptions to this however, especially when this involves blocking a free software alternative (this is the case with OMX media decoding). Moreover, firmwares should always be located under /system/vendor/firmware/
so that they are easy to spot and remove when the user decides to get rid of them (after installing them previously).
For instance, the WiFi firmwares path (often declared in the BoardConfig.mk
file) have to be changed with the /system/vendor/firmware
prefix. The bluetooth firmware path is often declared in the init files (such as init.herring.rc
). Make sure to document the new firmwares locations on the wiki: see the Developer guide.
The Linux kernel comes with its own share of firmware: you have to get rid of them too. Mostly, this is about removing the firmwares
directory and modifying the Makefile
to make it avoid firmwares.
Since the procedure is nearly exactly the same on all kernels, here is a reference commit for the changes to add to Makefile
: Removed non-free firmwares and related instructions