ro.boot.wificountrycode was set in two places: androidboot.wificountrycode=US on the kernel cmdline (mkimg.sh extlinux heredoc) and ro.boot.wificountrycode=00 in vendor.prop. Because ro.* properties are set-once and init processes the cmdline first, the cmdline always won and the vendor.prop value silently lost (init logs 'Read-only property was already set' every boot). Worse, the vendor.prop value was 00 (world regulatory domain), a landmine that would activate if the cmdline param were ever dropped. Remove the cmdline param and set vendor.prop to US so the country code lives in exactly one place, delivered via vendor.img instead of a hand-maintained boot heredoc. Note this only feeds the Android framework (WifiCountryCode); the kernel side additionally needs regulatory.db to actually apply it (fixed separately by embedding it via CONFIG_EXTRA_FIRMWARE in the kernel).
195 lines
6.9 KiB
Bash
Executable file
195 lines
6.9 KiB
Bash
Executable file
#!/bin/bash
|
|
#
|
|
# Copyright (C) 2025 Venkata Atchuta Bheemeswara Sarma Darbha
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
# Create an RK3588 GPT AOSP image (no changes to original sector/start/size values).
|
|
# - Writes U-Boot at sector 64
|
|
# - Creates GPT with named partitions so Android creates /dev/block/by-name/*
|
|
# - Copies boot/system/vendor images (dd)
|
|
# - Creates metadata/userdata ext4 and sets proper GPT & fs labels
|
|
# - Uses kpartx to map partitions and cleans up reliably
|
|
#
|
|
set -euo pipefail
|
|
IFS=$'\n\t'
|
|
|
|
DEVICE_PATH=device/rockchip/tart
|
|
KERNEL_PATH=device/rockchip/tart-kernel
|
|
KERNEL_BUILD_OUT=${ANDROID_PRODUCT_OUT}/obj/KERNEL_OBJ
|
|
|
|
# Helper: print error and cleanup
|
|
exit_with_error() {
|
|
echo "ERROR: $*" >&2
|
|
cleanup || true
|
|
exit 1
|
|
}
|
|
|
|
cleanup() {
|
|
|
|
if [ -n "${LOOPDEV:-}" ]; then
|
|
if sudo kpartx -l "${IMAGE_PATH}" >/dev/null 2>&1; then
|
|
sudo kpartx -d "${IMAGE_PATH}" || true
|
|
fi
|
|
fi
|
|
}
|
|
|
|
trap cleanup EXIT
|
|
|
|
: "${TARGET_PRODUCT:?TARGET_PRODUCT environment variable is not set. Run lunch first.}"
|
|
: "${ANDROID_PRODUCT_OUT:?ANDROID_PRODUCT_OUT environment variable is not set. Run lunch first.}"
|
|
|
|
for PART in boot system vendor; do
|
|
if [ ! -f "${ANDROID_PRODUCT_OUT}/${PART}.img" ]; then
|
|
exit_with_error "Missing partition image: ${ANDROID_PRODUCT_OUT}/${PART}.img — run 'make ${PART}image' first."
|
|
fi
|
|
done
|
|
|
|
UBOOT_BIN=${KERNEL_PATH}/u-boot-rockchip.bin
|
|
if [ ! -f "${UBOOT_BIN}" ]; then
|
|
exit_with_error "Missing U-Boot: ${UBOOT_BIN}"
|
|
fi
|
|
|
|
LINEAGE_VERSION=$(build/soong/bin/get_build_var LINEAGE_VERSION)
|
|
if [ -z "${LINEAGE_VERSION}" ]; then
|
|
exit_with_error "LINEAGE_VERSION is empty. Run 'lunch' first and ensure the build environment is configured."
|
|
fi
|
|
IMGSIZE=19456MiB
|
|
IMAGE_PATH="${ANDROID_PRODUCT_OUT}/lineage-${LINEAGE_VERSION}.img"
|
|
|
|
if [ -f "${IMAGE_PATH}" ]; then
|
|
echo "Overwriting existing image: ${IMAGE_PATH}"
|
|
sudo rm -f "${IMAGE_PATH}"
|
|
fi
|
|
|
|
echo "Creating image file ${IMAGE_PATH} (${IMGSIZE})..."
|
|
sudo fallocate -l "${IMGSIZE}" "${IMAGE_PATH}"
|
|
sync
|
|
|
|
echo "Writing U-Boot to sector 64..."
|
|
# write u-boot binary to offset 64*512 = sector 64
|
|
sudo dd if="${UBOOT_BIN}" of="${IMAGE_PATH}" seek=64 bs=512 conv=notrunc status=progress
|
|
sync
|
|
|
|
echo "Partitioning image using sfdisk (GPT) with explicit partition NAMES..."
|
|
|
|
PART_TABLE=$(
|
|
cat <<EOF
|
|
label: gpt
|
|
unit: sectors
|
|
|
|
# Partition 1: boot (FAT32)
|
|
${IMAGE_PATH}1 : start=32768, size=262144, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, name="boot"
|
|
|
|
# Partition 2: system (EXT4)
|
|
${IMAGE_PATH}2 : start=303104, size=6291456, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="system"
|
|
|
|
# Partition 3: vendor (EXT4) -- 512M (was 384M; grown to keep headroom for the
|
|
# broad USB WiFi firmware bundle, which left the old 384M partition full)
|
|
${IMAGE_PATH}3 : start=6596608, size=1048576, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="vendor"
|
|
|
|
# Partition 4: metadata (EXT4)
|
|
${IMAGE_PATH}4 : start=7645184, size=32768, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="metadata"
|
|
|
|
# Partition 5: userdata (EXT4)
|
|
${IMAGE_PATH}5 : start=7677952, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="userdata"
|
|
EOF
|
|
)
|
|
|
|
# Use a temporary file for sfdisk input so variable interpolation is safe
|
|
echo "${PART_TABLE}" | sudo sfdisk "${IMAGE_PATH}"
|
|
sync
|
|
|
|
echo "Mapping partitions using kpartx..."
|
|
|
|
KPARTX_OUT=$(sudo kpartx -av "${IMAGE_PATH}")
|
|
echo "${KPARTX_OUT}"
|
|
|
|
LOOPDEV=$(echo "${KPARTX_OUT}" | awk '/add map/ {dev=$3} END { sub(/p[0-9]+$/, "", dev); print dev }')
|
|
if [ -z "${LOOPDEV}" ]; then
|
|
exit_with_error "kpartx failed to map partitions or to return a loop device name."
|
|
fi
|
|
echo "Mapped image as /dev/mapper/${LOOPDEV}p* (base loop: ${LOOPDEV})"
|
|
|
|
# Wait for device nodes to appear
|
|
sleep 1
|
|
if [ ! -b "/dev/mapper/${LOOPDEV}p1" ]; then
|
|
echo "Waiting a bit longer for /dev/mapper/${LOOPDEV}p1 to appear..."
|
|
sleep 1
|
|
fi
|
|
if [ ! -b "/dev/mapper/${LOOPDEV}p1" ]; then
|
|
exit_with_error "Device mapper nodes not found (e.g. /dev/mapper/${LOOPDEV}p1). Check kpartx output."
|
|
fi
|
|
|
|
# --- Copy images into partitions ---
|
|
echo "Creating FAT32 filesystem on p1 (boot partition)..."
|
|
sudo mkfs.vfat -F 32 -n "boot" "/dev/mapper/${LOOPDEV}p1"
|
|
|
|
# Mount the boot partition and copy kernel/boot files
|
|
BOOT_MOUNT=$(mktemp -d)
|
|
sudo mount "/dev/mapper/${LOOPDEV}p1" "${BOOT_MOUNT}"
|
|
if [ -f "${KERNEL_BUILD_OUT}/arch/arm64/boot/Image" ]; then
|
|
sudo cp ${KERNEL_BUILD_OUT}/arch/arm64/boot/Image "${BOOT_MOUNT}/"
|
|
sudo cp ${KERNEL_BUILD_OUT}/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-ultra.dtb "${BOOT_MOUNT}/"
|
|
else
|
|
sudo cp ${KERNEL_PATH}/Image "${BOOT_MOUNT}/"
|
|
sudo cp ${KERNEL_PATH}/rk3588-orangepi-5-ultra.dtb "${BOOT_MOUNT}/"
|
|
fi
|
|
sudo mkdir -p "${BOOT_MOUNT}/extlinux"
|
|
sudo tee "${BOOT_MOUNT}/extlinux/extlinux.conf" >/dev/null <<'EXTLINUX_EOF'
|
|
label LineageOS Android TV
|
|
kernel /Image
|
|
fdt /rk3588-orangepi-5-ultra.dtb
|
|
initrd /ramdisk.img
|
|
append console=ttyS2,1500000 no_console_suspend root=/dev/ram0 rootwait androidboot.hardware=tart androidboot.selinux=permissive androidboot.boot_devices=fe2c0000.mmc androidboot.console=ttyS2
|
|
EXTLINUX_EOF
|
|
sudo cp ${KERNEL_PATH}/boot.scr "${BOOT_MOUNT}/"
|
|
sudo cp ${KERNEL_PATH}/android-sdcard.dtbo "${BOOT_MOUNT}/"
|
|
sudo cp "${ANDROID_PRODUCT_OUT}/ramdisk.img" "${BOOT_MOUNT}/"
|
|
sudo cp ${KERNEL_PATH}/config.txt "${BOOT_MOUNT}/"
|
|
sudo umount "${BOOT_MOUNT}"
|
|
rmdir "${BOOT_MOUNT}"
|
|
|
|
echo "Writing system image to p2 (raw dd)."
|
|
# Use conv=notrunc so we don't shrink partition image area; status=progress for visibility
|
|
sudo dd if="${ANDROID_PRODUCT_OUT}/system.img" of="/dev/mapper/${LOOPDEV}p2" bs=1M conv=notrunc status=progress
|
|
|
|
echo "Writing vendor image to p3 (raw dd)."
|
|
sudo dd if="${ANDROID_PRODUCT_OUT}/vendor.img" of="/dev/mapper/${LOOPDEV}p3" bs=1M conv=notrunc status=progress
|
|
|
|
sync
|
|
|
|
# --- Ensure filesystem labels and types are correct ---
|
|
# Note: dd'ing system/vendor may already contain an internal FS label; we force the GPT
|
|
# partition name above and set the filesystem label to match as a guard.
|
|
echo "Setting filesystem labels on p2 (system) and p3 (vendor) and creating metadata/userdata..."
|
|
|
|
# Try to set ext4 label on system; if it isn't an ext4, warn but continue.
|
|
set +e
|
|
sudo e2label "/dev/mapper/${LOOPDEV}p2" system 2>/dev/null
|
|
E2_RC=$?
|
|
if [ "${E2_RC}" -ne 0 ]; then
|
|
echo "Warning: /dev/mapper/${LOOPDEV}p2 does not appear to be ext4 or e2label failed. Continuing."
|
|
fi
|
|
sudo e2label "/dev/mapper/${LOOPDEV}p3" vendor 2>/dev/null || echo "Warning: e2label on vendor failed (maybe not ext4)."
|
|
|
|
set -e
|
|
|
|
# Create/format metadata and userdata partitions and set filesystem labels
|
|
sudo mkfs.ext4 -F -L metadata "/dev/mapper/${LOOPDEV}p4"
|
|
sudo mkfs.ext4 -F -L userdata "/dev/mapper/${LOOPDEV}p5"
|
|
sync
|
|
|
|
# Final sanity: list by-name symlinks
|
|
echo "Partition mapping summary (kpartx):"
|
|
sudo ls -l /dev/mapper/"${LOOPDEV}"* || true
|
|
|
|
# Unmap now that we have set labels
|
|
sudo kpartx -d "${IMAGE_PATH}" || true
|
|
# fix ownership
|
|
sudo chown "${USER}:${USER}" "${IMAGE_PATH}"
|
|
|
|
echo "✅ Created ${IMAGE_PATH} with GPT partition names and filesystem labels."
|
|
echo "You should now be able to write this image to your SD/NVMe and boot RK3588. "
|
|
|
|
sudo sfdisk -l "${IMAGE_PATH}"
|
|
exit 0
|