Working camera and bluetooth for LineageOS on the Amazon Echo Show 5 (1st and 2nd gen) and Echo Show 8 (1st gen)
This repository makes the front camera fully functional on unofficial LineageOS 18.1 for the Amazon Echo Show 5 (1st gen, 2nd gen) and Echo Show 8 (1st gen) . The stock ROM port ships no camera stack at all; with this work applied, the device gets:
| Feature | Status |
|---|---|
| Camera enumeration (front, correct orientation) | working |
| Live preview with correct colors | working |
Still capture (takePicture, camera2/CameraX) |
working, full 1600x1200 JPEG |
| Video mode sensor timing | working |
| Lens shading correction (factory calibration) | working |
| Auto exposure | working |
| Adaptive auto white balance | working, with a calibrated correction |
| Black level | corrected (the stock tuning left a 30% grey floor) |
The stock port leaves Bluetooth
completely broken on these devices: the adapter crash-loops every ~8
seconds on enable (the A2DP sink overlay ships as a runtime RRO, so its
services resolve as disabled while the profile list expects them), and
every BLE scan fails with SCAN_FAILED_INTERNAL_ERROR because the
android.hardware.bluetooth_le feature is never declared.
patches/0017-device-tree-bluetooth-enablement.patch fixes both defects
and keeps A2DP sink working; the patch header carries the full analysis.
The patch currently covers crown and cronos, where it is tested and
verified (build-side and on hardware after a reflash: adapter holds ON,
sink services running, both features declared). Whether checkers needs
the same treatment is not yet known; its tree carries the same A2DP sink
overlay, so if it shows the same symptoms the patch shows exactly what to
change in its tree.
camera-demo-720p.mp4
Everything here was reverse-engineered against a live device; the complete investigation, including every dead end, is in docs/findings.md. It is long, but if you maintain a MediaTek device port it is probably the most useful file in the repository.
The Echo Show ships an Android 7.1 (API 25) camera stack on an Android 9 era kernel and the LineageOS port runs Android 11 userspace on that kernel. Nothing agrees with anything: the blobs need symbols Android 11 removed, an older display framework than the ROM ships, a cmdq event encoding the kernel no longer speaks, and Amazon's kernel struct layouts rather than upstream MediaTek's. On top of that, the ROM's kernel selected the 1st gen camera sensor (OV9734) while the 2nd gen device has an OV02B10, so a sensor driver had to be ported, and all of MediaTek's image tuning (white balance, black level) is for the wrong sensor. Each of those is fixed here, layer by layer.
| Device | Codename | Sensor | Status |
|---|---|---|---|
| Echo Show 5 (2nd Generation) | cronos |
OV02B10 | working, verified end to end |
| Echo Show 8 | crown |
OV9734 | working, verified end to end - apply patches/0014 for the sensor flip |
| Echo Show 5 | checkers |
OV9734 | working, community verified - needs the pinned libdpframework build the install scripts now select |
On the OV9734 devices apply only the kernel struct patch (0001), the sensor flip (0014)
and the two privacy-latch patches (0015, 0016) - their sensor
driver is already in the tree and selected - and skip the two color
corrections in step 9, which exist only to undo cronos running an OV02B10
against OV9734 tuning. Three OV9734 bring-ups ran neither and got correct
color, crown under natural daylight included, so those devices need no
calibration at all.
OV9734 devices need patches/0014 for the sensor flip. Their driver
selects its mirror setting on CONFIG_CAMERA_MULTIMODAL, which is
default n and set by no Echo Show defconfig, so the flip Amazon intended
for these devices is never compiled in and the sensor reads out inverted.
ro.camera.sensor_orientation cannot correct it. Patch 0014 makes the
vertical flip unconditional, and is photo-confirmed on both crown and
checkers: upright picture, correct color, no calibration needed; see
docs/INSTALL.md step 3.
OV9734 devices should also take patches/0015 and patches/0016 for the
privacy latch. On crown and checkers the button Android reports as the
power key is physically the privacy mute button (linux,code = <116> on the
amazon-gating node), so a long press both opens the power menu and engages
the hardware latch that cuts camera power. The latch survives a reboot and
software cannot clear it, and the camera driver never reads it, so it powers
the sensor into a dead rail: the camera stays broken until the device is
unplugged from mains. 0015 makes the driver read the latch and refuse the open
cleanly; 0016 keeps the camera enumerated while the latch is engaged, so
clearing the shutter restores it without a cameraserver restart or a reboot.
Both are validated on crown. See issue #4.
-
An Echo Show 5 or 8 already running R0rt1z2's unofficial LineageOS 18.1 port from amazon-oss/releases - amonet-unlocked, with TWRP intact. If you cannot boot TWRP, stop: some of these steps can brick a device that has no recovery path.
-
amonet 2.0.1 or newer. This is required, not a recommendation. Everything here is written for and tested on 2.x only; amonet 1.x is retired and its instructions have been removed.
scripts/flash-boot.shdetects a 1.x device and refuses to write to it.Upgrade if you have not. Two reasons:
The device gets its full 2 GB of RAM. amonet 1.x left these devices running on 1 GB; 2.x gives you all of it. Measured on
crownafter the upgrade,MemTotalis 1933452 kB (the remainder of the 2 GB is reserved carveout). On a device this size that is the difference between a usable system and one that thrashes, and it is reason enough on its own.The boot layout changed and the two are mutually unbootable. 1.x kept an exploit header in the first two blocks of the boot partition; 2.x removed the microloader entirely and boot became an ordinary Android boot image. Writing either layout onto the other generation hangs the device at the vendor logo.
Do not use amonet 2.0.0: it has a bug that leaves TWRP not properly updated when upgrading from a 1.x unlock, which is exactly the path you are on. 2.0.1 fixes it.
-
A Linux host with
adbandpython3, and a USB cable. USB is what matters: TWRP has no networking, so the flashing steps need it. Network adb (adb connect <ip>:5555) is convenient for the rest but optional. -
A LineageOS 18.1 build environment (needed to build the patched boot image and the patched system libraries). Set up the source tree per the amazon-oss instructions;
patches/local-manifest-fixes.xmlcontains the manifest fixes this work needed.
docs/INSTALL.md is the complete step-by-step guide - every command from a stock LineageOS install to a working, color-calibrated camera, plus troubleshooting. The overview below is the map; the guide is the route.
There are three layers. They must all be applied; each fixes failures the next layer would otherwise hit.
- Kernel (boot image): Amazon struct layouts, the OV02B10/OV9734 driver, sensor timing fixes. Requires building and flashing a boot image.
- ROM system libraries (device tree + AOSP patches): camera provider declaration, front-camera feature declaration, sensor orientation, two AOSP camera fixes. Requires building the ROM (or at minimum the affected libraries) with the patches applied.
- Vendor blobs and on-device tuning: the proprietary camera stack
(fetched from a public firmware dump, never shipped here) and the
patched private display framework go into the vendor tree before the
build; the
LD_PRELOADshim and the two tuning corrections are applied to the device afterwards, because they are built against, or patch, what is on the device.
Three things go into kernel/amazon/mt8163-4.9, in order:
patches/0001-imgsensor-use-the-Amazon-struct-layouts-on-all-echo-show.patch(every Echo Show device)patches/ov02b10_mipi_raw-driver.tar.gzunpacked intodrivers/misc/mediatek/imgsensor/src/mt8163/- the complete OV02B10 driver, with all its fixes already included (cronos only)patches/0004-imgsensor-ov02b10-driver-support.patch- sensor IDs, sensor list entry, defconfig (cronos only)
Do not additionally apply 0007/0008/0010 (already inside the driver tarball; they document how the fixes were developed), do not apply 0002 (a conflicting alternative to 0001), and do not edit the defconfig by hand - 0004 sets the verified configuration. 0003 is debug logging only.
Build the boot image (mka bootimage), then flash it with
scripts/flash-boot.sh <adb-serial>.
On amonet 2.x the boot partition is an ordinary Android boot image, so the
build's boot.img is written to it verbatim. The flash script backs the
partition up first, verifies the transfer by hash, and reads the partition
back afterwards. It also checks the recovery partition and refuses outright
if the device is still on 1.x, whose layout is mutually unbootable with this
one.
If the device is not up far enough for adb, fastboot does the same job with
no booted system and no root. fastbrick leaves the device there:
fastboot flash boot out/target/product/<device>/boot.img
fastboot reboot
Note the argument order: fastboot flash <partition> <file>. Omitting the
partition fails with "unknown partition".
Backups under backups/ predating the 2.x upgrade are unbootable. They
are full partition dumps, so anything captured on 1.x carries the old
exploit header and will hang the device at the vendor logo. Three devices
were bricked on boot layout, the last one exactly this way. After changing
the unlock, reflash from the build tree, never from an older backup.
Apply:
patches/0005-camera-device-1.0-cookie-fallback-and-ANativeWindowBuffer-preview.patch
patches/0006-camera-flatten-tolerate-zero-size-String8-from-legacy-HALs.patch
patches/0011-device-tree-camera-enablement.patch
0005 and 0006 patch AOSP camera code the tree builds
(camera.device@1.0-impl, libcamera_client); 0011 carries all the device
tree changes (provider declaration, packages, front-camera feature, sensor
orientation, HAL1 native handle flag).
patches/README.md explains what each change is for.
Not camera related but required on crown and cronos:
patches/0017-device-tree-bluetooth-enablement.patch fixes Bluetooth,
which is otherwise completely broken there (the adapter crash-loops on
enable and BLE scans fail). Tested and verified on both; whether
checkers needs it too is not yet known. The patch header carries the
analysis; docs/INSTALL.md step 4 applies it with the
others.
The blob list also has to be declared and the vendor makefiles regenerated
(device/amazon/<device>/setup-makefiles.sh) - appending to
proprietary-files.txt alone does nothing, because the build reads the
generated vendor/amazon/<device>/*.mk.
Into the vendor tree, before building the ROM:
scripts/fetch-camera-blobs.sh # 45 blobs from the public dump
scripts/install-blobs-to-tree.sh <tree> # place them at their declared paths
scripts/install-private-dpframework.sh <tree> # API 25 display framework: private
# soname + 3 binary patches
scripts/patch-shim-needed.sh <tree> # add the shim to the blobs' DT_NEEDEDOnto the device, after flashing the ROM:
shims/libcmdqevent/build.sh <serial> # built against the device's own bionic
scripts/install-cmdq-event-shim.sh <serial> # cmdq event translation + AWB correction
scripts/patch-awb-d65.sh <serial> # neutralize the double white balance
scripts/patch-obc-pedestal.sh <serial> # correct the black level for the OV02B10
adb -s <serial> rebootscripts/install-camera.sh <serial> <tree> pushes the vendor-tree blobs,
provider libraries, shim and manifest directly, for iterating without a
full reflash.
The blobs come from the public amazon_cronos_dump firmware dump. This repository contains no proprietary code; the scripts fetch, patch, and install it on your own device.
From a cold boot, with no manual steps:
adb shell 'pm list features | grep camera' # camera.any + camera.front, NO plain "camera"
adb shell 'dumpsys media.camera | grep Orientation' # 0
adb shell 'logcat -d | grep -cE "startStream fail|deque DISPO fail"' # 0Open the camera app: live preview, then take a photo - it should produce a full resolution 1600x1200 JPEG in about a second. In a fully dark room a photo should be essentially black (that is the black-level fix; without it you get a grey-cyan haze).
The MediaTek tuning in the blobs is for the OV9734 sensor, not the OV02B10, so adaptive white balance lands with an illuminant-dependent bias. The shim corrects it by rescaling the AWB algorithm's output, interpolated between two calibrated anchors (daylight and warm LED), keyed on the algorithm's own blue gain. Four 512-based properties control it, re-read every 64 frames so tuning needs no restart:
persist.camera.awbtrim.r cool (daylight) anchor, red
persist.camera.awbtrim.b cool anchor, blue
persist.camera.awbtrim.r.warm warm (2600K) anchor, red
persist.camera.awbtrim.b.warm warm anchor, blue
Defaults are in shims/libcmdqevent/camera-bringup.rc, calibrated against
a grey surface on one device. To touch up for your unit: point the camera
at anything grey or white, take snapshots, and adjust in steps of 2 or 3
(the color matrix amplifies a change here several times over in the
rendered image, so small steps):
- image too magenta: lower
.r(or.r.warmunder warm light) - image too green: raise it
- same logic for blue with
.b/.b.warm
- Scene-to-scene color variance of roughly +-10%. The blob's AWB output wobbles a few percent between sessions on identical scenes and the color matrix amplifies it. Inherent to the closed algorithm.
- Dim mixed lighting can render greenish. When the AWB classifier finds no recognizable illuminant it falls back to its reference gains, which bypass part of the correction. A handler for this state is planned.
- Low-sun color gradient on aged units. Direct low sunlight through the front glass produces a cyan-to-magenta gradient across the frame (IR leakage through the aged IR-cut filter plus internal veiling glare). It is not visible in midday diffuse daylight or under artificial light. No global correction can fix it, and the front glass cannot be cleaned from outside.
- Single client. The legacy HAL1 stack allows one camera client at a time.
Learned the hard way; both of these can take the device down completely.
- Never SIGKILL or
stopcameraserver while the ISP is streaming. It leaves the memory management unit pointed at freed buffers and the resulting bus violation storm livelocks the entire device - no adb, no ping, no watchdog. Useadb reboot, oram force-stopthe camera app first and give it two seconds. - Only flash boot images with
scripts/flash-boot.shorfastboot flash boot. Both take the build's plainboot.img. The script additionally refuses a 1.x device and verifies the write. - Never restore a boot backup captured before the 2.x upgrade. It is a full partition dump in the retired 1.x layout and will not boot. Reflash from the build tree instead.
| Path | What it is |
|---|---|
| docs/INSTALL.md | Step-by-step installation, verification, calibration, troubleshooting |
| docs/findings.md | The full investigation, in order, with every dead end kept and marked |
| docs/building.md | Getting the LineageOS tree for these devices to actually build |
| docs/handoff-takepicture.md | Worked example of debugging one bug end to end (the capture stall) |
| patches/ | Kernel and AOSP patches, numbered in application order |
| shims/libcamera_shim/ | Source shim closing the 11-symbol gap between the API 25 blobs and Android 11 |
| shims/libcmdqevent/ | LD_PRELOAD shim: cmdq event-id translation, AWB output correction, diagnostic tracers |
| scripts/ | Fetching, patching, installing, flashing, calibration |
| tools/cmdq-trace/ | On-device diagnostic tools (ioctl tracers, ISP register/IRQ probes, sensor register poke) |
This work sits on top of R0rt1z2's LineageOS ports for the MT8163 Amazon devices, which is what makes any of it possible:
| Releases (flashable ROMs) | amazon-oss/releases |
| Echo Show 5 2nd gen build | lineage-18.1-cronos-v0.3 |
| Manifests for building | amazon-oss/local_manifests |
| Device tree | android_device_amazon_cronos |
| Common device tree | android_device_amazon_mt8163-common |
| Kernel | android_kernel_amazon_mt8163 |
| Maintainer | R0rt1z2 |
The patches here are written against those trees. Nothing in this repository replaces the port - it adds the camera to it.
The crown diagnosis by CesarAmores
(writeup)
mapped the HAL1 shim crash chain and established that the stock blobs are
2017-era camera1 code. R0rt1z2 maintains the LineageOS ports these devices
run (amazon-oss) and documented the
original kernel/blob mismatch in
releases#5. The stock
firmware dump is maintained at
el-vertedero/amazon_cronos_dump.
Original code (shims, scripts, tools) is MIT. Kernel patches are GPL-2.0; AOSP patches are Apache-2.0. See LICENSE. No proprietary binaries are distributed in this repository.
