初探酷走Android行车记录仪

酷走记录仪

博客有段时间没有更新了,提前说好这不是一般的行车记录仪评测文章,我现在开的 SUV 上并没有装记录仪,只是同事刚好送了一个厂商已倒闭的记录仪,看到这款采用 Intel Atom 处理器的行车记录仪有点兴趣,准备初步研究下。

酷走行车记录仪由深圳汉普云联科技生产,具体型号为 KZV201,网上关于此行车记录仪的评测文章还是有一些的,之前 京东众筹 上的链接应该还在,想了解的朋友们可以看看。

这里我就不做具体介绍了,外观图也就不上了。初步了解此记录仪使用 Intel SOFIA Atom x3 处理器,因此集成了 3G 上网功能(带 SIM 卡插槽),支持 2.4 GHz Wi-Fi 网络、蓝牙 4.0、GPS 及 FM 发射功能。酷走记录仪虽然号称支持 1080p 全高清视频录制,然而实际测试录像效果也是比较一般,另外采用 Android 5.0 系统也挺少见。

由于机身没有任何物理按键,所有功能都要通过手机 App 连接行车记录仪 Wi-Fi 热点来完成,这也是相当坑的地方:由于厂家已经不提供支持更新了,目前手机 App 里不少功能缺失,最基本的 SIM 卡(专用物联网卡)数据流量充值功能都不能使用;手机 App 连修改记录仪系统时间的功能都没有提供(可能厂家考虑的是自动通过 SIM 卡数据流量进行时间同步),导致目前记录仪的时间都不正确。

Web 接口使用

为了摆脱随时可能会完全崩掉的手机 App,我就需要知道基本的管理接口和视频调阅接口。

记录仪自带的 Wi-Fi 热点使用固定的 192.168.43.1 IP 地址(别指望能修改了),手机或者电脑连接酷走的 Wi-Fi 热点之后就可以 ping 通记录仪地址了,下面我贴出来的例子都是在 Chromebook 上测试的,首先我用 Linux 自带的 nc 命令来扫一下记录仪开放的端口:

(xenial)zzm@localhost:~$ nc -znv 192.168.43.1 20-20000 2>&1 | grep 'succeeded'
Connection to 192.168.43.1 53 port [tcp/*] succeeded!
Connection to 192.168.43.1 5556 port [tcp/*] succeeded!
Connection to 192.168.43.1 8080 port [tcp/*] succeeded!
Connection to 192.168.43.1 8886 port [tcp/*] succeeded!

显然 53 是 Wi-Fi 热点自带的 DNS 服务器端口,看起来 8080 就是 Web 接口的端口了,我在安装了酷走 App 的手机上运行 tcpdump 程序进行抓包就可以分析 8080 端口的请求了。

用户登录

首先是用户登录请求:

chronos@localhost ~/Downloads $ curl -v "http://192.168.43.1:8080/term?act=user_login&user=\{%22email%22:null,%22emailVerifyCode%22:null,%22emailVerifyCodeValidtime%22:null,%22emailVerifyStatus%22:0,%22iconUuid%22:null,%22id%22:0,%22lastLoginTime%22:null,%22name%22:null,%22nickname%22:null,%22password%22:null,%22phone%22:null,%22phoneLoginCode%22:null,%22phoneLoginCodeValidtime%22:null,%22realName%22:null,%22regTime%22:null,%22uuid%22:%222F06A8D7CA314388B58DC46719702844%22\}&password=8888&termtype=3&force=false"
*   Trying 192.168.43.1...
* TCP_NODELAY set
* Connected to 192.168.43.1 (192.168.43.1) port 8080 (#0)
> GET /term?act=user_login&user={%22email%22:null,%22emailVerifyCode%22:null,%22emailVerifyCodeValidtime%22:null,%22emailVerifyStatus%22:0,%22iconUuid%22:null,%22id%22:0,%22lastLoginTime%22:null,%22name%22:null,%22nickname%22:null,%22password%22:null,%22phone%22:null,%22phoneLoginCode%22:null,%22phoneLoginCodeValidtime%22:null,%22realName%22:null,%22regTime%22:null,%22uuid%22:%222F06A8D7CA314388B58DC46719702844%22}&password=8888&termtype=3&force=false HTTP/1.1
> Host: 192.168.43.1:8080
> User-Agent: curl/7.60.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Set-Cookie: JSESSIONID=1lqydpb54hnunwlfbfj8eqkzi;Path=/
< Set-Cookie: TONG_TOKEN_ID=a2664fc77f2d4c2abf90bea58e3bb6bf;Path=/;Expires=Tue, 29-Feb-2000 00:26:30 GMT
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Content-Type: text/plain;charset=UTF-8
< Access-Control-Allow-Methods: GET, POST
< Access-Control-Allow-Credentials: true
< Transfer-Encoding: chunked
< Server: Jetty(i-jetty 1.0.27)
< 
* Connection #0 to host 192.168.43.1 left intact
{"data":"a2664fc77f2d4c2abf90bea58e3bb6bf","elapsedTime":94,"message":"鉴权通过!","responseCode":100}

注意

上面 curl 命令中的括号做了转义防止 curl 请求错误,实际请求地址中并没有反斜杠,另外请求地址中的 %22 就是双引号,如果在浏览器中访问也可以直接把 %22 换成双引号。

可以看到记录仪 Web 服务器是基于 Jetty 写的,GET 请求地址中的 userpassword 参数不能缺少,password 就是记录仪的管理密码(默认:8888),user 参数是个 JSON 对象,基本所有参数都可以使用 null,除了 uuid 参数表示登录用户(可以随机生成一串 UUID),重复发送登录请求将会报错。

最值得关注的是返回 Cookie 数据中的 JSESSIONID=1lqydpb54hnunwlfbfj8eqkzi 值,后面所有 Web 请求都会用到这个会话 ID。

查看设备信息

基础设备信息也可以使用 curl 附带 JSESSIONID Cookie 值进行查询,下面其它的请求就不详细列出来了:

curl -v -b "JSESSIONID=1lqydpb54hnunwlfbfj8eqkzi" "http://192.168.43.1:8080/term?act=device_info&appID=null"

设备信息输出如下:

GET /term?act=device_info&appID=null HTTP/1.1
Host: 192.168.43.1:8080
Cookie: JSESSIONID=73jb4a4t1urf1un1krkwn6drr

HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Credentials: true
Transfer-Encoding: chunked
Server: Jetty(i-jetty 1.0.27)

{"data":{"hotName":null,"hotPassword":null,"hwVerion":"4","imei":"XXXXXXX","osVersion":"2.2.3","password":null,"productCode":null,"randomCode":null,"sn":"KXXXXXX","swVersion":"1.0.27","videoPassword":null},"elapsedTime":9,"message":null,"responseCode":100}

查看记录仪配置请求:

GET /term?act=query_termconfiginfo HTTP/1.1

{"data":{"hotName":"KUZO_KXXXXXX","hotPassword":"password","hwVerion":"4","imei":"XXXXXXX","osVersion":"2.2.3","password":"8888","productCode":null,"randomCode":null,"sn":"KXXXXXX","swVersion":"1.0.27","videoPassword":""},"elapsedTime":14,"message":"Success!","responseCode":100}

查看 SIM 卡 ICCID(返回值在 data 中):

GET /term?act=query_sim_iccid HTTP/1.1

{"data":"XXXXXXX","elapsedTime":14,"message":null,"responseCode":100}

查看 FM 发射状态(这个 POST 请求没有附带任何参数):

POST /term?act=query_fm_open_status HTTP/1.1
Content-Length: 0

{"data":false,"elapsedTime":35,"message":null,"responseCode":100}

查看 GPS 状态:

GET /term?act=query_gps_status HTTP/1.1

{"data":{"position":{"accuracy":14.33,"altitude":15.030368,"angle":337.0591,"crs":1,"gpsTime":"20181023180046","latitude":31.907135402870722,"longitude":118.77761111400555,"speed":0.0},"positionFix":true,"positionType":1,"satellitesInUse":5,"satellitesInView":6},"elapsedTime":3,"message":null,"responseCode":100}

可以看到这里能直接查询到 GPS 的当前经纬度以及精确度,还能看到卫星的使用情况,比较讽刺的是这边 GPS 时间都得到了,记录仪系统在网络不可用的情况下却没考虑使用 GPS 时间。

查询存储状态(装了 TF 卡之后就能看到存储卡容量状态了):

GET /term?act=query_storage_info HTTP/1.1

{"data":{"TFExist":true,"TFTotalCapacity":63847890944,"TFUsedCapacity":6595575808,"internalTotalCapacity":3918114816,"internalUsedCapacity":2259316736},"elapsedTime":3,"message":null,"responseCode":100}

查询 3G 移动网络状态:

GET /term?act=query_3g_status HTTP/1.1

{"data":{"dialUpSuccess":false,"intensity":0,"mnc":"01","type":"3G"},"elapsedTime":19,"message":null,"responseCode":100}

音乐管理

此记录仪支持通过手机 App 上传音乐到记录仪的存储卡,然后通过蓝牙进行播放控制,列举音乐接口:

GET /term?act=list_music HTTP/1.1

{"data":[{"fileSize":4008624,"id":0,"length":0,"md5":"e8b1a4e5-0a4d-4c1f-b6bf-44052507fc37","name":null,"path":"/mnt/media_rw/sdcard1/Kuzo/Music/2F06A8D7CA314388B58DC46719702844/2/13/e8b1a4e5-0a4d-4c1f-b6bf-44052507fc37.mp3","singer":null,"userUuid":"2F06A8D7CA314388B58DC46719702844","uuid":"e8b1a4e5-0a4d-4c1f-b6bf-44052507fc37"}],"elapsedTime":7,"message":"Success!","responseCode":100}

查询最大音量(最大级别为 15):

GET /term?act=query_max_volume HTTP/1.1

{"data":15,"elapsedTime":5,"message":null,"responseCode":100}

查看当前音量:

GET /term?act=query_volume HTTP/1.1

{"data":10,"elapsedTime":9,"message":"15 15","responseCode":100}

视频管理

首先按小时段列举视频,请忽略不正确的系统时间:

GET /term?act=list_video_hour HTTP/1.1

{"data":["20000115230000","20000116000000","20000116010000","20000116020000","20000116030000"],"elapsedTime":171,"message":null,"responseCode":100}

指定开始和结束的小时时间段列举视频:

GET /term?act=list_poi&start_time=20000116030000&end_time=20000116040000 HTTP/1.1

{"data":[],"elapsedTime":9,"message":null,"responseCode":100}

列举某个小时的所有视频,可以看到存储卡里视频的完整路径:

GET /term?act=list_video_db&hour_time=20000116030000 HTTP/1.1

{"data":[{"createTime":"20000116030127","id":42,"length":120009,"lockType":0,"name":"2000-01-16_03-01-27.mp4","path":"/mnt/media_rw/sdcard1/Kuzo/Video/2000/1/16/3/2000-01-16_03-01-27.mp4","sn":null,"uuid":"a6035028ded14482936c1580aba8e298","videoType":0},{"createTime":"20000116030327","id":43,"length":119940,"lockType":0,"name":"2000-01-16_03-03-27.mp4","path":"/mnt/media_rw/sdcard1/Kuzo/Video/2000/1/16/3/2000-01-16_03-03-27.mp4","sn":null,"uuid":"291a4796c1274dfea99a978c84ca33d0","videoType":0}],"elapsedTime":986,"message":null,"responseCode":100}

获取某个视频文件的封面截图,此请求直接返回 jpg 图像数据:

GET /term?act=snapshot&name=2000-01-16_03-21-26.mp4&time=0 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: image/jpeg
Accept-Ranges: bytes
Content-Length: 42351
Content-Disposition: attachment;filename=2000-01-16_03-19-26_0.jpg
Server: Jetty(i-jetty 1.0.27)

指定开始和结束时间段获取历史轨迹,由于记录仪的 GPS 是一直开启的,还好轨迹还算比较准确,这里轨迹数据比较长我就不详细贴出来了:

GET /term?act=query_history_track&start_time=20181013180104&end_time=20181013180304&len=121 HTTP/1.1

最后是最关键的下载录像接口,通过 name 参数指定视频文件名即可:

GET /term?act=get_video&name=2000-01-16_03-19-26.mp4 HTTP/1.1
User-Agent: Lavf/57.56.100
Accept: */*
Range: bytes=0-
Connection: close
Host: 192.168.43.1:8080
Icy-MetaData: 1

HTTP/1.1 206 Partial Content
Content-Type: application/octet-stream
Accept-Ranges: bytes
Content-Length: 61722040
Content-Disposition: attachment;filename=2000-01-16_03-19-26.mp4
Content-Range: bytes 3104-61722039/61722040
Connection: close
Server: Jetty(i-jetty 1.0.27)

有点奇葩的就是这个下载录像的请求却并没有验证用户会话 ID,因此你也可以通过任何一款播放器指定地址直接远程回放录像:

http://192.168.43.1:8080/term?act=get_video&name=2000-01-16_03-19-26.mp4

实时视频接口

通过 tcpdump 抓包就会发现记录仪的实时视频预览是通过上面扫描出来的 8886 端口,记录仪提供 RTSP 形式的实时预览接口:

rtsp://192.168.43.1:8886?videoapi=mc2&transport=tcp

需要注意的是记录仪自带的 RTSP 服务器似乎只支持 TCP 流传输,如果使用 VLC 播放器,则需要将 Live555 流传输选项改为:RTP over RTSP (TCP) 才能正常播放。

厂家可能出于预览流畅性考虑 RTSP 并没有直接提供 1080p 的视频,然而我通过 VLC 播放器进行 RTSP 实时预览还是存在两至三秒的延时,在 Chromebook 下切换使用 VXG Media Player 插件进行实时预览则不存在延时问题。

总结

目前该行车记录仪使用下来还存在几个主要问题:

  • SIM 卡无法联网的情况下系统时间没办法修改;
  • 手机 App 提供的记录仪通过扫码连接外部 Wi-Fi 或者手机热点的功能无法工作,如果可以的话系统时间同步应该就不是问题;
  • 记录仪硬件上有降噪麦克风,而且支持通过蓝牙的语音对讲功能(只用于目前手机 App 里基本不可用的结伴出行组队),但是视频录像却不支持音频录制,同样 RTSP 实时视频中也没有带音频流。

这些问题只能后面有空的话再抽时间看看能否进入记录仪的 Android 系统进行修改了,祝大家玩的开心。

  1. 依云:

    curl 有个参数禁用特殊字符的,好像是 -g。一个个地转义多累啊。

  2. Uranus Zhou:

    直接拷贝的抓包数据里的地址,嘿嘿;
    不过之前测试 curl 的 -g 参数时才了解地址里的大括号在 bash 上还需要再加转义。

  3. I BULI:

    您好,请问这款设备如何重置呀?网上已经搜不到这个厂商提供的相关资料了,我尝试安装酷走APP1.5.3安卓版本提示SDK版本过低,无法正常运行。

  4. Uranus Zhou:

    按照 酷走Android行车记录仪研究 这篇文章里的介绍可以使用 adb 调试哦,
    另外安装 Vysor 软件之后,就可以通过 adb 连接行车记录仪了。

    连接之后,就可以进入 Android 界面,可以在设置里进行重置咯。





*