Hacking Wowme U300Q Car Camera to Actually Work

I recently came across a Wowme U300Q car camera on an auction at aukro.cz . At first glance, it seemed like a promising piece of tech, but after trying to use it, I quickly realized there was a major flaw—it didn’t rotate recorded files and it was not just an issue with my piece, also reviews confirmed it as a global problem. For anyone familiar with dash cams, this is a critical issue because, without rotating files, the camera quickly runs out of storage and stops recording.

The Initial Problem: A Broken Camera

When I first set up the Wowme U300Q, I was hopeful. The hardware looked solid, and the camera itself seemed well-built. However, after some time of recording, it would crash randomly. When I checked the files, I noticed it stopped recording a while ago – there were no recordings with recent timestamp. The camera would blink indicating recording, running recording timer, but no files would be saved.

Exploring the Device

After connecting it to my PC, I ran some basic diagnostics. I used the lsusb and found it is identifying as Google device:

$ lsusb
...
Bus 002 Device 007: ID 18d1:0002 Google Inc.
...

So I tried adb shell and voila!

$ adb shell
* daemon not running; starting now at tcp:5037
* daemon started successfully


BusyBox v1.27.2 () built-in shell (ash)

------run profile file-----
_____ _ __ _
|_ _||_| ___ _ _ | | |_| ___ _ _ _ _
| | _ | || | | |__ | || || | ||_'_|
| | | || | || _ | |_____||_||_|_||___||_,_|
|_| |_||_|_||_|_| Tina is Based on OpenWrt!
----------------------------------------------
Tina Linux (Neptune, 5C1C9C53)
----------------------------------------------
root@tina:/#

I poked around the device a bit and discovered that it was running on an Allwinner chipset—something that could be worked with.

root@tina:/# cat /proc/mtd 
dev: size erasesize name
mtd0: 00100000 00001000 "uboot"
mtd1: 002c0000 00001000 "boot"
mtd2: 00ae0000 00001000 "rootfs"
mtd3: 00080000 00001000 "overlay"
mtd4: 00020000 00001000 "env"
mtd5: 00020000 00001000 "bootlogo"
mtd6: 00010000 00001000 "private"
mtd7: 00090000 00001000 "UDISK"
root@tina:/# mount
/dev/root on /squashfs type squashfs (ro,relatime)
devtmpfs on /dev type devtmpfs (rw,relatime,size=40552k,nr_inodes=10138,mode=755)
/proc on /proc type proc (rw,relatime)
tmpfs on /tmp type tmpfs (rw,relatime)
sys on /sys type sysfs (rw,relatime)
/dev/root on /squashfs type squashfs (ro,relatime)
/dev/mtdblock3 on /overlay type jffs2 (rw,relatime)
overlay on / type overlay (rw,relatime,lowerdir=/squashfs,upperdir=/overlay/upperdir,workdir=/overlay/workdir)
tmpfs on /run type tmpfs (rw,relatime)
devpts on /dev/pts type devpts (rw,relatime,gid=5,mode=620,ptmxmode=000)
/dev/mtdblock7 on /mnt/UDISK type jffs2 (rw,relatime)
/dev/mmcblk0 on /mnt/extsd type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro)
/dev/pts on /dev/pts type devpts (rw,relatime,mode=600,ptmxmode=000)
none on /sys/kernel/config type configfs (rw,relatime)
adb on /dev/usb-ffs/adb type functionfs (rw,relatime)
none on /sys/kernel/debug type debugfs (rw,relatime)
root@tina:/# cat /proc/cpuinfo
processor : 0
model name : ARMv7 Processor rev 5 (v7l)
BogoMIPS : 31.57
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xc07
CPU revision : 5

processor : 1
model name : ARMv7 Processor rev 5 (v7l)
BogoMIPS : 31.57
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xc07
CPU revision : 5

Hardware : sun8iw16
Revision : 0000
Serial : 0000000000000000

Firmware backup

To dive deeper into the device, I needed to back up the firmware for case when something went wrong. Fortunately, there was a useful method to back up Allwinner devices using a special SD card image. This process was outlined on the Linux Sunxi wiki: Boot into FEL mode and then backup over USB. All went smooth and I saved 4MB flash binary.

Main binary

Now I was ready to do some experiments. I have found out that the main process handling everything is called /usr/bin/sdvcam .

So to gather some logs which would persist over reboot, I run it like this:

root@tina:/# /usr/bin/sdvcam >/mnt/UDISK/app.out 2>/mnt/UDISK/app.err &

I let it run until it crashed. Then I started to inspect the logs.

W0905 21:17:46.511580  1781 main_recorder.cpp:610]          <InitRecorder> m_filename is /mnt/extsd/video/20240905_211746.mp4
E0905 21:17:46.512944 1781 main_recorder.cpp:630] <InitRecorder> record time: 120000, bitrate: 10485760,file allocate size 173015040
E0905 21:17:46.514299 1781 recorder.cpp:831] <allocRecorderFile> allocRecorderFile rename file name ,file name /mnt/extsd/video/20240905_211746.mp4
E0905 21:17:46.515655 1781 recorder.cpp:841] <allocRecorderFile> ReNameFilelen 0,filenamelen 36
E0905 21:17:46.533033 1781 recorder.cpp:855] <allocRecorderFile> fatal error! Failed to fallocate size 173015040, (No space left on device)
E0905 21:17:46.535569 1781 recorder.cpp:858] <allocRecorderFile> allocate file success
E0905 21:17:46.541994 1781 VideoEnc_Component.c:4128] <VideoEncSaveBSFile> user set the same SaveBSFile => filename:, enable:0, start_time:0, end_time:0
E0905 21:17:46.543442 1781 VideoEnc_Component.c:4163] <VideoEncUpdateProcSet> user set the same VeProcSet => enable:1, freq:30, BTTime:1000, FRTime:1000
E0905 21:17:46.591112 1936 TextEnc_Component.c:46] <TextComponentThread> TextEncoder TextEncComponentThread start run...
E0905 21:17:46.594789 1936 TextEnc_Component.c:396] <TextComponentThread> TextEnc_Comp not ind StateExecuting
W0905 21:17:46.596601 1781 VideoEnc_Component.c:1824] <CedarvVideoEncInit> user set invalid gopSize[0], use idr interval[30] as default.
W0905 21:17:46.618526 1781 preview_window.cpp:1307] <Update> handle msg:20
W0905 21:17:46.619169 1802 EyeseeRecorder.cpp:1923] <dataCallbackTimestamp> avsync_drp:-1-690215240-0-1920-1080
W0905 21:17:46.620746 1781 preview_window.cpp:1459] <Update> [habo]--->start to record !!!!
W0905 21:17:46.623062 1781 preview_window.cpp:1215] <RecordStatusTimeUi> ---RecordStatusTimeUi mstart = 1
E0905 21:17:46.624222 1781 status_bar_window.cpp:467] <RecordStatusTimeUi> mstart: 1
W0905 21:17:46.653061 1802 VideoEnc_Component.c:5101] <VideoEncEmptyThisBuffer> avsync_first video frame pts[690254632]us,tm1[690255447]us, vSize[1920x1080]
W0905 21:17:46.664505 1781 newPreview.cpp:2158] <TakePicforVideothumb> p_CamId: 0
W0905 21:17:46.667140 1781 camera.cpp:1544] <TakePicture> do take picture chn: 1 main_enc_chn_:0 sub_enc_chn_:1
W0905 21:17:46.669394 1781 preview_window.cpp:1307] <Update> handle msg:2314
E0905 21:17:46.678493 1781 osd_manager.cpp:1166] <AttchCarIdRegion> record 0 region_id 1
E0905 21:17:46.693383 1781 newPreview.cpp:1037] <HandleGUIMessage> PREVIEW_RECORD_BUTTON end
E0905 21:17:46.695008 1781 newPreview.cpp:1039] <HandleGUIMessage> PREVIEW_RECORD_BUTTON msg status is done,set msg status false
E0905 21:17:46.713250 1781 promptBox.cpp:132] <ShowPromptBox> strlen: 28
E0905 21:17:46.739377 1941 VideoEnc_Component.c:790] <map_v4l2_colorspace_to_VENC_COLOR_SPACE> fatal error! unsupported v4l2 color space[0x0]!
W0905 21:17:46.760557 1941 VideoEnc_Component.c:5894] <ComponentThread> wait Venc idleOutFrameList full:255-0-1-256
W0905 21:17:46.761505 1809 CallbackNotifier.cpp:1040] <savePictureThread> Be careful! Free memory too small! bufsize=12KB, MemTotal=81268KB, MemFree=1728KB, Buffers=9700KB, Cached=31616KB
W0905 21:17:46.763778 1941 VideoEnc_Component.c:5896] <ComponentThread> wait Venc idleOutFrameList full_done
W0905 21:17:46.763893 1799 camera.cpp:2493] <onPictureTaken> pic_file_ is : /mnt/extsd/video/20240905_211746_ths.jpg
E0905 21:17:46.771696 1799 camera.cpp:2520] <onPictureTaken> write data filed(No space left on device)
E0905 21:19:36.849349 1857 media_file_manager.cpp:818] <GetLastFileFallocateSizeByType> get video fallocate size = 63242240
E0905 21:19:36.968855 1857 recorder.cpp:831] <allocRecorderFile> allocRecorderFile rename file name ,file name /mnt/extsd/video/20240905_211936.mp4
E0905 21:19:36.970453 1857 recorder.cpp:841] <allocRecorderFile> ReNameFilelen 0,filenamelen 36
E0905 21:19:36.975098 1857 recorder.cpp:855] <allocRecorderFile> fatal error! Failed to fallocate size 173015040, (No space left on device)
E0905 21:19:36.977082 1857 recorder.cpp:858] <allocRecorderFile> allocate file success
W0905 21:19:47.209141 1939 RecRenderSink.c:1583] <RecSinkThread> avsync_rc_swfv:1920-120532-120534-120532-120000
W0905 21:19:47.210770 1939 RecRenderSink.c:743] <RecSinkMuxerClose> avsync_muxer_close:120532-120534-120532-120534-1920
W0905 21:19:47.309959 1857 newPreview.cpp:1570] <Update> revice MSG_RECORD_FILE_DONE event
W0905 21:19:47.311659 1857 preview_window.cpp:1307] <Update> handle msg:22
E0905 21:19:47.311808 1939 cedarx_stream_file.c:678] <cdx_write_fd_file> Stream[0xc26650] write error [-1]!=[36](No space left on device)
W0905 21:19:47.312944 1857 preview_window.cpp:1491] <Update> [habo]--->record file done!!!!
E0905 21:19:47.314582 1939 cedarx_stream_file.c:694] <cdx_write_fd_file> fatal error! write error is[28], writeNum[-1], don't write again.
W0905 21:19:47.317230 1857 status_bar_window.cpp:508] <ResetRecordTime> mRecordTime: 120, need reset to 0
E0905 21:19:47.321061 1939 FsWriter.c:95] <fileWriter> Stream[0xc26650]fwrite error [0]!=[36](No space left on device)
W0905 21:19:47.327523 1857 newPreview.cpp:2158] <TakePicforVideothumb> p_CamId: 0
E0905 21:19:47.331774 1939 cedarx_stream_file.c:678] <cdx_write_fd_file> Stream[0xc26650] write error [-1]!=[65536](No space left on device)
W0905 21:19:47.331899 1857 camera.cpp:1544] <TakePicture> do take picture chn: 1 main_enc_chn_:0 sub_enc_chn_:1
E0905 21:19:47.333247 1939 cedarx_stream_file.c:694] <cdx_write_fd_file> fatal error! write error is[28], writeNum[-1], don't write again.
E0905 21:19:47.335939 1939 FsWriter.c:95] <fileWriter> Stream[0xc26650]fwrite error [0]!=[65536](No space left on device)
E0905 21:19:47.337778 1939 cedarx_stream_file.c:678] <cdx_write_fd_file> Stream[0xc26650] write error [-1]!=[65536](No space left on device)
E0905 21:19:47.339397 1939 cedarx_stream_file.c:694] <cdx_write_fd_file> fatal error! write error is[28], writeNum[-1], don't write again.
E0905 21:19:47.340636 1939 FsWriter.c:95] <fileWriter> Stream[0xc26650]fwrite error [0]!=[65536](No space left on device)
E0905 21:19:47.402639 1939 cedarx_stream_file.c:678] <cdx_write_fd_file> Stream[0xc26650] write error [-1]!=[65536](No space left on device)
E0905 21:19:47.403070 2086 VideoEnc_Component.c:790] <map_v4l2_colorspace_to_VENC_COLOR_SPACE> fatal error! unsupported v4l2 color space[0x0]!
E0905 21:19:47.404249 1939 cedarx_stream_file.c:694] <cdx_write_fd_file> fatal error! write error is[28], writeNum[-1], don't write again.
E0905 21:19:47.407522 1939 FsWriter.c:95] <fileWriter> Stream[0xc26650]fwrite error [0]!=[65536](No space left on device)
W0905 21:19:47.410507 1809 CallbackNotifier.cpp:1040] <savePictureThread> Be careful! Free memory too small! bufsize=11KB, MemTotal=81268KB, MemFree=1904KB, Buffers=3692KB, Cached=36572KB
W0905 21:19:47.410023 2086 VideoEnc_Component.c:5894] <ComponentThread> wait Venc idleOutFrameList full:255-0-1-256
W0905 21:19:47.438671 1799 camera.cpp:2493] <onPictureTaken> pic_file_ is : /mnt/extsd/video/20240905_211936_ths.jpg
E0905 21:19:47.444708 1799 camera.cpp:2520] <onPictureTaken> write data filed(No space left on device)
W0905 21:19:47.439332 2086 VideoEnc_Component.c:5896] <ComponentThread> wait Venc idleOutFrameList full_done
E0905 21:19:47.481510 1939 cedarx_stream_file.c:678] <cdx_write_fd_file> Stream[0xc26650] write error [-1]!=[65536](No space left on device)
E0905 21:19:47.483206 1939 cedarx_stream_file.c:694] <cdx_write_fd_file> fatal error! write error is[28], writeNum[-1], don't write again.
E0905 21:19:47.484477 1939 FsWriter.c:95] <fileWriter> Stream[0xc26650]fwrite error [0]!=[65536](No space left on device)
E0905 21:19:47.562337 1939 cedarx_stream_file.c:678] <cdx_write_fd_file> Stream[0xc26650] write error [-1]!=[65536](No space left on device)
E0905 21:19:47.564474 1939 cedarx_stream_file.c:694] <cdx_write_fd_file> fatal error! write error is[28], writeNum[-1], don't write again.
E0905 21:19:47.566025 1939 FsWriter.c:95] <fileWriter> Stream[0xc26650]fwrite error [0]!=[65536](No space left on device)

As you can see, it reports no space left. I tried to find some of these log strings on github and found one project: https://github.com/lindenis-org/lindenis-v536-softwinner and this was some find! I would guess at least 80% of the code is used in my device.

It took me some time to study the code and what is called from where to find out that there in fact is a mechanism to rotate files on low space condition. According to logs, it seemed to be called but it was not freeing any space.

This space checking was confirmed when I found out that there is strace ! available on the device and I run it on the app:

root@tina:/# strace -ff -p 776 2>&1 | grep tmp
[pid 798] access("/tmp/stop_watchdog", F_OK <unfinished ...>
[pid 798] access("/tmp/stop_watchdog", F_OK) = -1 ENOENT (No such file or directory)
[pid 798] access("/tmp/stop_watchdog", F_OK) = -1 ENOENT (No such file or directory)
[pid 1018] open("/tmp/size_video_F.txt", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666 <unfinished ...>
[pid 798] access("/tmp/stop_watchdog", F_OK) = -1 ENOENT (No such file or directory)
[pid 776] open("/tmp/size_video_F.txt", O_RDONLY|O_LARGEFILE) = 35
[pid 1019] execve("/bin/sh", ["sh", "-c", "rm /tmp/size_video_F.txt -f"], [/* 22 vars */] <unfinished ...>
[pid 1020] execve("/bin/rm", ["rm", "/tmp/size_video_F.txt", "-f"], [/* 22 vars */] <unfinished ...>
[pid 1020] lstat64("/tmp/size_video_F.txt", <unfinished ...>
[pid 1020] unlink("/tmp/size_video_F.txt" <unfinished ...>
[pid 1023] open("/tmp/size_event_F.txt", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666 <unfinished ...>
[pid 776] open("/tmp/size_event_F.txt", O_RDONLY|O_LARGEFILE) = 35
[pid 1024] execve("/bin/sh", ["sh", "-c", "rm /tmp/size_event_F.txt -f"], [/* 22 vars */] <unfinished ...>
[pid 1025] execve("/bin/rm", ["rm", "/tmp/size_event_F.txt", "-f"], [/* 22 vars */] <unfinished ...>
[pid 1025] lstat64("/tmp/size_event_F.txt", <unfinished ...>
[pid 1025] unlink("/tmp/size_event_F.txt" <unfinished ...>
[pid 776] stat64("/tmp/sqlite/sunxi.db-journal", <unfinished ...>
[pid 776] stat64("/tmp/sqlite/sunxi.db-wal", 0xbea54290) = -1 ENOENT (No such file or directory)
[pid 1028] open("/tmp/size_video_F.txt", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 1
[pid 776] open("/tmp/size_video_F.txt", O_RDONLY|O_LARGEFILE <unfinished ...>
[pid 1029] execve("/bin/sh", ["sh", "-c", "rm /tmp/size_video_F.txt -f"], [/* 22 vars */] <unfinished ...>
[pid 1030] execve("/bin/rm", ["rm", "/tmp/size_video_F.txt", "-f"], [/* 22 vars */]) = 0
[pid 1030] lstat64("/tmp/size_video_F.txt", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
[pid 1030] unlink("/tmp/size_video_F.txt") = 0

After this, I needed to see if the contents of size_*.txt are correct but they were being deleted as you can see above. So I needed to patch the binary.

Ghidra has a very good support for Linux ELF so it was a natural choice. I loaded the binary and searched for the rm call. Then I patched the string and exported resulting binary as you can see below.

Next I uploaded the binary to the device:

danman@silverhorse:/storage/Projects/wowme$ adb push sdvcam.patched /mnt/extsd/
sdvcam.patched: 1 file pushed. 3.5 MB/s (4786960 bytes in 1.303s)

And run it:

root@tina:/# /mnt/extsd/sdvcam.patched >/mnt/UDISK/app.out 2>/mnt/UDISK/app.err

The result was that the temp file remained but empty:

root@tina:/mnt/extsd/video# cat /tmp/size_event_F.txt 
root@tina:/mnt/extsd/video#

Which meant the size check was failing.

Unfortunatelly, this part of code was not identical to the sources so I had to spend some time investigating in ghidra. Eventually, I made some sense out of it and I patched the path used for disk usage check:

Exported and tested the binary again and…

W0910 13:50:40.090088  3312 status_bar_window.cpp:508]      <ResetRecordTime> mRecordTime: 120, need reset to 0
W0910 13:50:40.095002 3312 newPreview.cpp:2158] <TakePicforVideothumb> p_CamId: 0
W0910 13:50:40.096786 3312 camera.cpp:1544] <TakePicture> do take picture chn: 1 main_enc_chn_:0 sub_enc_chn_:1
E0910 13:50:40.162842 1896 VideoEnc_Component.c:790] <map_v4l2_colorspace_to_VENC_COLOR_SPACE> fatal error! unsupported v4l2 color space[0x0]!
W0910 13:50:40.173454 1896 VideoEnc_Component.c:5894] <ComponentThread> wait Venc idleOutFrameList full:255-0-1-256
W0910 13:50:40.174084 3263 CallbackNotifier.cpp:1040] <savePictureThread> Be careful! Free memory too small! bufsize=22KB, MemTotal=81268KB, MemFree=2008KB, Buffers=6668KB, Cached=33736KB
W0910 13:50:40.197017 3253 camera.cpp:2493] <onPictureTaken> pic_file_ is : /mnt/extsd/video/20240910_135029_ths.jpg
W0910 13:50:40.197794 1896 VideoEnc_Component.c:5896] <ComponentThread> wait Venc idleOutFrameList full_done
E0910 13:52:30.157230 3312 media_file_manager.cpp:818] <GetLastFileFallocateSizeByType> get video fallocate size = 131203072
E0910 13:52:30.297047 3312 media_file_manager.cpp:982] <DeleteFileByOrder> delete file name /mnt/extsd/video/20240905_212158.mp4
E0910 13:52:30.303483 3312 media_file_manager.cpp:1753] <GetThumbPicName> thumb pic name:/mnt/extsd/video/20240905_212158_ths.jpg
E0910 13:52:30.436877 3312 recorder.cpp:831] <allocRecorderFile> allocRecorderFile rename file name ,file name /mnt/extsd/video/20240910_135230.mp4
E0910 13:52:30.438905 3312 recorder.cpp:841] <allocRecorderFile> ReNameFilelen 0,filenamelen 36
E0910 13:52:30.463142 3312 recorder.cpp:858] <allocRecorderFile> allocate file success
W0910 13:52:39.960764 3396 RecRenderSink.c:1615] <RecSinkThread> avsync_ch_a:4941786000-4941750582-1920
W0910 13:52:39.962682 3396 RecRenderSink.c:1653] <RecSinkThread> avsync_cal:1920-4941817248--1-1
W0910 13:52:39.998631 3396 RecRenderSink.c:1653] <RecSinkThread> avsync_cal:1920-4941850581-4941817248-2
W0910 13:52:40.038055 3396 RecRenderSink.c:1653] <RecSinkThread> avsync_cal:1920-4941883914-4941817248-3

An old file got deleted! After some time, several more files got deleted which meant the problem was fixed:

root@tina:/# grep delete /mnt/UDISK/app.err 
W0910 12:30:09.813452 3340 media_file_manager.cpp:1525] <DoDBUpdateByCamIdEx> some file would be delete or insert: ret:0 ret_db:31
W0910 12:30:09.836272 3340 media_file_manager.cpp:1525] <DoDBUpdateByCamIdEx> some file would be delete or insert: ret:0 ret_db:31
W0910 12:30:09.842162 3340 media_file_manager.cpp:1525] <DoDBUpdateByCamIdEx> some file would be delete or insert: ret:0 ret_db:31
E0910 13:52:30.297047 3312 media_file_manager.cpp:982] <DeleteFileByOrder> delete file name /mnt/extsd/video/20240905_212158.mp4
E0910 13:54:30.781258 3312 media_file_manager.cpp:982] <DeleteFileByOrder> delete file name /mnt/extsd/video/20240905_212348.mp4
E0910 13:54:30.917243 3312 media_file_manager.cpp:982] <DeleteFileByOrder> delete file name /mnt/extsd/video/20240905_212549.mp4
E0910 13:56:31.356421 3312 media_file_manager.cpp:982] <DeleteFileByOrder> delete file name /mnt/extsd/video/20240905_212749.mp4

What remained was to run the binary automatically. One way could be to patch the root squashfs and write it to the flash. I chose a simpler way to create a symlink to sdcard to point to patched binary stored on SD card.

root@tina:/# rm /usr/bin/sdvcam 
root@tina:/# ln -s /mnt/extsd/sdvcam.patched /usr/bin/sdvcam

Conclusion

By diving into the internals of the Wowme U300Q and tweaking the firmware, I was able to resolve the issue that made it essentially useless out of the box. If you have a similar camera or any other Allwinner-based devices, I hope this guide helps you get it working as intended. Feel free to share your experiences or ask questions in the comments below! I still have 2 extra pieces of this camera for sale for anyone willing to experiment. If you want one, feel free to contact me.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.