ERROR

HOW TO CREATE A TWRP DEVICE TREE

January 16th 2021
January 4th 2021
Alexenferman

Have you ever wanted to build a TWRP recovery for your device without porting, but you don't know how to create a basic device tree? Today I will show you how to create a basic device tree for your device allowing you to build a TWRP recovery image for your device. Keep in mind as a dislaimer that this is a basic device tree, and there is no guarantee TWRP will work the first time. You may need to add things from a similar device tree to fix bugs, errors, etc... Let's get started!

PREPARING TO BUILD A DEVICE TREE

What you will need

To begin creating a device tree for your device, you will need the following things:
  • A bootloader unlocked Android device
  • The stock recvoery from the phone you are building for. It can also be an older TWRP or CWM recovery compatible with the device.
  • A Linux PC
  • When creating a device tree, you may also use a Windows based computer. However, when building TWRP, you can only use a Linux PC or Virtual Machine.
  • A Github or Gitlab account (optional)
  • A notepad application

Getting basic specifications of the device

To create a device tree, we must get some basic specifications. Download apps such as CPU-Z, AIDA64 or HWinfo to view the specs of your device and take a note of the following things:
  • SoC Model - (Ex. Snapdragon 210)
  • Architecture - (Ex. arm)
  • Device Model - (Ex. ZTE Avid Plus)
  • Manufacturer - (Ex. ZTE)
  • Model - (Ex. Z828)
  • Brand - (Ex. zte)
  • Board/Codename - (Ex. achill)
  • Platform - (Ex. msm8909)

Extracting the stock recovery image

To get more information about the device such as the Kernel CMDLINE, offsets and more, we must extract the stock boot image. You can use multiple tools to acomplish the same job, but I will be using mktool as it is open source and very easy to use.
Download the Binaries from the releases section
Extract the ZIP file somewhere in the /home/user folder.
Place the recovery.img in the "input" folder.
Using the terminal, navigate to the mktool folder and open the program using the java -jar mktool.jar command.
After that, go to the "Unpack" tab, select your boot image, and click on "Unpack Image"
Take a note of the output of the console at the bottom. You will need it later.
BOARD_KERNEL_CMDLINE androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x3F ehci-hcd.park=3 
androidboot.bootdevice=7824900.sdhci lpm_levels.sleep_disabled=1 earlyprintk
BOARD_KERNEL_BASE 80000000
BOARD_NAME 
BOARD_PAGE_SIZE 2048
BOARD_HASH_TYPE sha1
BOARD_KERNEL_OFFSET 00008000
BOARD_RAMDISK_OFFSET 02000000
BOARD_SECOND_OFFSET 00f00000
BOARD_TAGS_OFFSET 00000100
BOARD_DT_SIZE 7116800
Also, you will find the extracted files from the recovery image in the "/extracted" folder.
extracted
     |
     configs
     | `-recovery.img-base
     |   recovery.img-board
     |   recovery.img-cmdline
     |   recovery.img-dt
     |   etc...
     |
     ramdisk
     | `- init.rc
     |    ueventd.rc
     |	  fstab.qcom
     |	  default.prop
     |	  etc...
     |
     recovery.img-zImage

CREATING THE DEVICE TREE

To create a device tree, you must create the following files:

Android.mk

Add the following lines to the Android.mk file.
LOCAL_PATH := $(call my-dir)

ifeq ($(TARGET_DEVICE), #codename#)
include $(call all-subdir-makefiles,$(LOCAL_PATH))
endif
Replace the #CODENAME# with the Board/Codename spec we noted previously. In my case, it's "achill".

AndroidProducts.mk

Add the following lines to the AndroidProducts.mk file.
PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/omni_#CODENAME#.mk
Replace the #CODENAME# with the Board/Codename spec we noted previously. In my case, it's "achill", so omni_achill.mk

BoardConfig.mk

BoardConfig is more complicated to create. Follow the intructions carefully.
Add the following lines to the BoardConfig.mk file.
DEVICE_PATH := device/#Brand#/#Codename#
Replace the #CODENAME# with the Board/Codename and #Brand# with the Brand spec we noted previously. In my case, it's "device/zte/achill".
Next, add the following lines:
# For building with TWRP minimal manifest
ALLOW_MISSING_DEPENDENCIES := true
# Architecture (arm)                         # Architecture (arm64)
TARGET_ARCH := arm                           TARGET_ARCH := arm64
TARGET_ARCH_VARIANT := armv7-a-neon          TARGET_ARCH_VARIANT := armv8-a
TARGET_CPU_ABI := armeabi-v7a          OR    TARGET_CPU_ABI := arm64-v8a
TARGET_CPU_ABI2 := armeabi                   TARGET_CPU_ABI2 :=
TARGET_CPU_VARIANT := generic                TARGET_CPU_VARIANT := generic
Depending on your device architecture determined from the specs (arm or arm64), chose the correct one.
Next, add the following lines:
# Assert
TARGET_OTA_ASSERT_DEVICE := #Codename#
Replace the #CODENAME# with the Board/Codename spec we noted previously. In my case, it's "achill", so "TARGET_OTA_ASSERT_DEVICE := achill"
Next, add the following lines:
# File systems
BOARD_HAS_LARGE_FILESYSTEM := true
BOARD_SYSTEMIMAGE_PARTITION_TYPE := ext4
BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE := ext4
TARGET_USERIMAGES_USE_EXT4 := true
TARGET_USERIMAGES_USE_F2FS := true
NOTE: If you are building for a very old phone, it may not be using EXT4 for its partitions.
# Kernel
BOARD_KERNEL_CMDLINE := #Cmdline#
Enter the kernel cmdline we found after extracting the Recovery Image. Go here to see its value
Next, add the following line:
TARGET_PREBUILT_KERNEL := $(DEVICE_PATH)/prebuilt/#Image Type#
You will see a kernel file in the extracted folder. Remove the "recovery.img-" string from the filename and you should see a filename such as zImage, Image.gz or zImage-dtb. Replace the #Image Type# with the approrpriate Kernel filename.
TARGET_PREBUILT_DT := $(DEVICE_PATH)/prebuilt/dt.img
Only add this if there is a recovery.img-dt in the /extracted/configs folder.
Next, add the following lines:
BOARD_KERNEL_BASE := 0x80000000
BOARD_KERNEL_PAGESIZE := 2048
BOARD_RAMDISK_OFFSET := 0x02000000
BOARD_KERNEL_TAGS_OFFSET := 0x00000100
Enter the kernel base, pagesize, etc... we found after extracting the Recovery Image. Go here to see the values.
Next, add the following lines:
BOARD_FLASH_BLOCK_SIZE := 131072 # (BOARD_KERNEL_PAGESIZE * 64)
BOARD_MKBOOTIMG_ARGS += --ramdisk_offset $(BOARD_RAMDISK_OFFSET)
BOARD_MKBOOTIMG_ARGS += --tags_offset $(BOARD_KERNEL_TAGS_OFFSET)
BOARD_MKBOOTIMG_ARGS += --dt $(TARGET_PREBUILT_DT)
Only add the last line if there is a recovery.img-dt in the /extracted/configs folder.
Next, add the following lines:
# Platform
TARGET_BOARD_PLATFORM := #Platform#
Replace the #Platform# with the Platform spec we noted previously. In my case, it's "msm8909", so "TARGET_BOARD_PLATFORM := msm8909".
Next, add the following lines:
# Hack: prevent anti rollback
PLATFORM_SECURITY_PATCH := 2099-12-31
PLATFORM_VERSION := 16.1.0
These lines will set the Security patch of the recovery to 2099, so the stock ROM will not overwrite the custom recovery with the stock one.
Next, add the default TWRP flags. You may refer to this documentation if you wish or need to add more TWRP Flags. Using TWRP flags, you can add or remove features in TWRP such as extra languages, horizontal screen, themes etc...
# TWRP Configuration
TW_THEME := portrait_hdpi
TW_EXTRA_LANGUAGES := true #Only if you need it
TW_SCREEN_BLANK_ON_BOOT := true
TW_INPUT_BLACKLIST := "hbtp_vm"

device.mk

Add the following lines to the device.mk file.
LOCAL_PATH := device/#Brand#/#Codename#
Replace the #CODENAME# with the Board/Codename and #Brand# with the Brand spec we noted previously. In my case, it's "device/zte/achill".

omni_#Codename#.mk

Replace the #CODENAME# with the Board/Codename spec we noted previously. In my case, it's "achill", so omni_achill.mk
Add the following lines to the omni_#Codename#.mk file.
# Inherit from those products. Most specific first.
$(call inherit-product-if-exists, $(SRC_TARGET_DIR)/product/embedded.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/full_base_telephony.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/languages_full.mk)

# Inherit from device
$(call inherit-product, device/#Brand#/#Codename#/device.mk)

# Inherit some common Omni stuff.
$(call inherit-product, vendor/omni/config/common.mk)
$(call inherit-product, vendor/omni/config/gsm.mk)

# Device identifier. This must come after all inclusions
PRODUCT_DEVICE := #Codename#
PRODUCT_NAME := omni_#Codename#
PRODUCT_BRAND := #Brand#
PRODUCT_MODEL := #Model#
PRODUCT_MANUFACTURER := #Brand#
PRODUCT_RELEASE_NAME := #Brand# #Model#
Replace the #CODENAME# with the Board/Codename, #Brand# with the Brand and #Model# with the Model spec we noted previously. In my case, it's achill, zte and Z828.

vendorsetup.sh

Add the following lines to the vendorsetup.sh file.
add_lunch_combo omni_#Codename#-userdebug
add_lunch_combo omni_#Codename#-eng
Replace the #CODENAME# with the Board/Codename spec we noted previously. In my case, it's achill.

recovery.fstab

Go to your extracted recovery image.
Navigate to /ramdisk/etc
You should see a file called "recovery.fstab"
This is mine:
/dev/block/bootdevice/by-name/sbl1         /sbl1           emmc
/dev/block/bootdevice/by-name/rpm          /rpm            emmc
/dev/block/bootdevice/by-name/tz           /tz             emmc
/dev/block/bootdevice/by-name/persist      /persist        ext4
/dev/block/bootdevice/by-name/aboot        /emmcboot       emmc 
/dev/block/bootdevice/by-name/modem        /modem          emmc  
/dev/block/bootdevice/by-name/config       /persistent     emmc 
/dev/block/bootdevice/by-name/echarge      /echarge        emmc   
/dev/block/bootdevice/by-name/splash       /splash         emmc   
/dev/block/bootdevice/by-name/carrier      /carrier        ext4    
/dev/block/bootdevice/by-name/system       /system         ext4   
/dev/block/bootdevice/by-name/cache        /cache          ext4    
/dev/block/bootdevice/by-name/userdata     /data           ext4   
/dev/block/mmcblk1p1                       /sdcard         vfat    
/dev/block/bootdevice/by-name/boot         /boot           emmc   
/dev/block/bootdevice/by-name/recovery     /recovery       emmc 
/dev/block/bootdevice/by-name/misc         /misc           emmc   
Remove any partitions you don't want to touch, such as /emmcboot, /sbl1, /tz, then change the order (if necessary) of the coloumns. It should look similar to this:
# mount point       fstype    device                                  flags
/persist            ext4      /dev/block/bootdevice/by-name/persist   flags=display="Persist"
/persist_image      emmc      /dev/block/bootdevice/by-name/persist   flags=display="Persist image";backup=1;flashimg=1
/system             ext4      /dev/block/bootdevice/by-name/system    flags=backup=1
/system_image       emmc      /dev/block/bootdevice/by-name/system    flags=display="System image";backup=1;flashimg=1
/cache              ext4      /dev/block/bootdevice/by-name/cache                                   
/data               ext4      /dev/block/bootdevice/by-name/userdata                                
/boot               emmc      /dev/block/bootdevice/by-name/boot                                    
/recovery           emmc      /dev/block/bootdevice/by-name/recovery  flags=backup=1
/sdcard             vfat      /dev/block/mmcblk1p1 
/misc               emmc      /dev/block/bootdevice/by-name/misc  
Replace the #CODENAME# with the Board/Codename spec we noted previously. In my case, it's achill.

prebuilt folder

Create a folder called "prebuilt".
Go to your extracted recovery image. You will see a file named: "recovery.img-zImage" or "recovery.img-image.gz-dtb" or "recovery.img-zImage-dtb".
Rename the file, and remove the "recovery.img-" prefix from the filename. The end result should look like this: "zImage", "image.gz-dtb" or "zImage-dtb".
Copy the newly renamed file to the prebuilt folder.
device tree
     |
     Android.mk
     AndroidProducts.mk
     BoardConfig.mk
     device.mk
     etc...
     |
     prebuilt
       `- zImage
          dt.img //ONLY IF THE KERNEL NAME IS "zImage"
NOTE: If the Kernel name is "zImage", you should copy the file called "recovery.img-dt" found in the /configs folder in your extracted recovery to the /prebuilt folder of the device tree. Rename it to "dt.img".

recovery/root folder

Create a folder called "recovery".
Inside the recovery folder, create another folder called "root"
Copy all the files (Not folders!) from the /ramdisk folder of extracted recovery to the recovery / root folder of the device tree.
Be careful, as you have to remove some of the files. There is no one answer to this question, as it is always different from device to device. However, I have put this list of which files should you keep or remove from the recovery/root folder. Use your judgment to see which files you should add or not add.
device tree
   |
   Android.mk
   etc...
   |
   recovery
    `-root                    SHOULD YOU ADD IT?
        `-init                NO       
          init.qcom.usb.sh    YES 
          sepolicy            NO
          init.class_main.sh  YES          
          init.rc             YES           
          service_contexts    NO
          default.prop        YES   
          property_contexts   NO   
          file_contexts       NO 
          init.qcom.early.sh  YES
          ueventd.qcom.rc     YES
          fstab.qcom          YES
          init.qcom.sh        YES               
          seapp_contexts      NO    
          ueventd.rc          YES
          init.qcom.fixup.sh  YES  
          selinux_version     NO    
          verity_key          NO
And there you go! You have created your very own TWRP device tree!
Unfortunately, there is not a 100% guarantee that this device tree will create a functionnal TWRP image, so we recommend searching on Github for a device similar to yours (Same Chipset) and compare the contents of it to see if you missed anything.
For older MTK devices, you might need a custom mkbootimg which you will find in a similar device tree, if required.
See the final result of the device tree I created here.

You are done!

If you have any questions, or need help creating your device tree, leave a comment below!

Error.

COMMENTS

Avatar
Show Comments