高通平台 Android9 adb shell “hwclock -w“ 报错

article/2025/10/6 23:35:33

hwclock -w 报错

文章目录

  • `hwclock -w` 报错
    • 问题现象
    • 分析
      • 1. hwclock命令分析
      • 2. `/dev/rtc0`驱动节点分析
    • 修改设备树后`hwclock -w`报错没有了,但是系统会重启,原因未知

问题现象

sdm660_64:/ # hwclock -w
hwclock: ioctl 4024700a: Invalid argument

分析

1. hwclock命令分析

hwclock命令是toybox的内建命令,可以修改toybox代码来调试

进入external/toybox目录下修改toybox/toys/other/hwclock.c

diff --git a/toybox/toys/other/hwclock.c b/toybox/toys/other/hwclock.c
index 1d313e3..5d907aa 100644
--- a/toybox/toys/other/hwclock.c
+++ b/toybox/toys/other/hwclock.c
@@ -82,13 +82,25 @@ void hwclock_main()dirtree_read("/sys/class/rtc", rtc_find);if (!TT.fname) TT.fname = "/dev/misc/rtc";}
+    xprintf("fd=%d,TT.fname%s\n", fd, TT.fname);if (fd == -1) fd = xopen(TT.fname, flag);
+    xprintf("fd=%d,TT.fname%s\n", fd, TT.fname);// Get current time in seconds from rtc device. todo: get subsecond timeif (!w) {char *s = s;+      xprintf("RTC_RD_TIME\n");xioctl(fd, RTC_RD_TIME, &tm);
+      xprintf("tm_sec=%d\n", tm.tm_sec);
+      xprintf("tm_min=%d\n", tm.tm_min);
+      xprintf("tm_hour=%d\n", tm.tm_hour);
+      xprintf("tm_mday=%d\n", tm.tm_mday);
+      xprintf("tm_mon=%d\n", tm.tm_mon);
+      xprintf("tm_year=%d\n", tm.tm_year);
+      xprintf("tm_wday=%d\n", tm.tm_wday);
+      xprintf("tm_yday=%d\n", tm.tm_yday);
+      xprintf("tm_isdst=%d\n", tm.tm_isdst);if (TT.utc) s = xtzset("UTC0");if ((time = mktime(&tm)) < 0) error_exit("mktime failed");if (TT.utc) {
@@ -108,7 +120,17 @@ void hwclock_main()/* The value of tm_isdst is positive if daylight saving time is in effect,* zero if it is not and negative if the information is not available.* todo: so why isn't this negative...? */
+    xprintf("RTC_SET_TIME\n");tm.tm_isdst = 0;
+    xprintf("tm_sec=%d\n", tm.tm_sec);
+    xprintf("tm_min=%d\n", tm.tm_min);
+    xprintf("tm_hour=%d\n", tm.tm_hour);
+    xprintf("tm_mday=%d\n", tm.tm_mday);
+    xprintf("tm_mon=%d\n", tm.tm_mon);
+    xprintf("tm_year=%d\n", tm.tm_year);
+    xprintf("tm_wday=%d\n", tm.tm_wday);
+    xprintf("tm_yday=%d\n", tm.tm_yday);
+    xprintf("tm_isdst=%d\n", tm.tm_isdst);xioctl(fd, RTC_SET_TIME, &tm);} else if (toys.optflags & FLAG_s) {tzone.tz_minuteswest = timezone / 60 - 60 * daylight;

执行编译命令

make toybox -j4

将本地编译的toybox push到手机里面

# adb push toybox /system/bin/toybox2# adb shell
sdm660_64:/ # toybox2 hwclock -w
fd=-1,TT.fname/dev/rtc0
fd=3,TT.fname/dev/rtc0
RTC_SET_TIME
tm_sec=49
tm_min=45
tm_hour=19
tm_mday=24
tm_mon=7
tm_year=121
tm_wday=2
tm_yday=235
tm_isdst=0
hwclock: ioctl 4024700a: Invalid argument

由此可以判定是/dev/rtc0这个驱动节点有问题。并且是在进行ioctl RTC_SET_TIME时发生的问题。

2. /dev/rtc0驱动节点分析

观察进行ioctl RTC_SET_TIME时发生了什么。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qa8YNNY6-1629809627988)(https://note.youdao.com/yws/res/b/WEBRESOURCE7b9c259a0e11b0e7db40166ff22225eb)]

这里可以看到,调用到了rtc_set_time函数

修改如下代码,增加debug log

diff --git a/msm-4.4/drivers/rtc/interface.c b/msm-4.4/drivers/rtc/interface.c
index 9cad172..7bf4d88 100644
--- a/msm-4.4/drivers/rtc/interface.c
+++ b/msm-4.4/drivers/rtc/interface.c
@@ -61,19 +61,25 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm){int err;+    dev_warn(&rtc->dev, "tm value: %d-%d-%d %d:%d:%d\n",
+        tm->tm_year + 1900, tm->tm_mon + 1,
+        tm->tm_mday, tm->tm_hour, tm->tm_min,
+        tm->tm_sec);err = rtc_valid_tm(tm);if (err != 0)return err;err = mutex_lock_interruptible(&rtc->ops_lock);
+    dev_warn(&rtc->dev, "mutex_lock_interruptible,err=%d\n", err);if (err)return err;if (!rtc->ops)err = -ENODEV;
-       else if (rtc->ops->set_time)
+       else if (rtc->ops->set_time) {
+        dev_warn(&rtc->dev, "err = rtc->ops->set_time(rtc->dev.parent, tm);\n");err = rtc->ops->set_time(rtc->dev.parent, tm);
-       else if (rtc->ops->set_mmss64) {
+    } else if (rtc->ops->set_mmss64) {time64_t secs64 = rtc_tm_to_time64(tm);err = rtc->ops->set_mmss64(rtc->dev.parent, secs64);
@@ -82,6 +88,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)err = rtc->ops->set_mmss(rtc->dev.parent, secs64);} elseerr = -EINVAL;
+    dev_warn(&rtc->dev,"ifxxx err=%d\n", err);pm_stay_awake(rtc->dev.parent);mutex_unlock(&rtc->ops_lock);
diff --git a/msm-4.4/drivers/rtc/qpnp-rtc.c b/msm-4.4/drivers/rtc/qpnp-rtc.c
index bafcebb..8baf15d 100644
--- a/msm-4.4/drivers/rtc/qpnp-rtc.c
+++ b/msm-4.4/drivers/rtc/qpnp-rtc.c
@@ -113,6 +113,7 @@ qpnp_rtc_set_time(struct device *dev, struct rtc_time *tm)value[2] = (secs >> 16) & 0xFF;value[3] = (secs >> 24) & 0xFF;+       dev_err(dev, "Seconds value to be written to RTC = %lu\n", secs);dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);

修改后的rtc_set_time函数

int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{int err;dev_warn(&rtc->dev, "tm value: %d-%d-%d %d:%d:%d\n",tm->tm_year + 1900, tm->tm_mon + 1,tm->tm_mday, tm->tm_hour, tm->tm_min,tm->tm_sec);err = rtc_valid_tm(tm);if (err != 0)return err;err = mutex_lock_interruptible(&rtc->ops_lock);dev_warn(&rtc->dev, "mutex_lock_interruptible,err=%d\n", err);if (err)return err;if (!rtc->ops)err = -ENODEV;else if (rtc->ops->set_time) {dev_warn(&rtc->dev, "err = rtc->ops->set_time(rtc->dev.parent, tm);\n");err = rtc->ops->set_time(rtc->dev.parent, tm);} else if (rtc->ops->set_mmss64) {time64_t secs64 = rtc_tm_to_time64(tm);err = rtc->ops->set_mmss64(rtc->dev.parent, secs64);} else if (rtc->ops->set_mmss) {time64_t secs64 = rtc_tm_to_time64(tm);err = rtc->ops->set_mmss(rtc->dev.parent, secs64);} elseerr = -EINVAL;dev_warn(&rtc->dev,"ifxxx err=%d\n", err);pm_stay_awake(rtc->dev.parent);mutex_unlock(&rtc->ops_lock);/* A timer might have just expired */schedule_work(&rtc->irqwork);return err;
}
EXPORT_SYMBOL_GPL(rtc_set_time);

刷机后复现问题,抓取log

# adb shell
sdm660_64:/ # logcat -b kernel | grep -i rtc
01-01 07:28:27.330     0     0 I msm_serial c170000.serial: uartclk = 1843200
01-01 07:28:27.364     0     0 I msm_serial c16f000.serial: uartclk = 19200000
01-01 07:28:27.384     0     0 I msm_serial c1b0000.serial: uartclk = 19200000
01-01 07:28:28.790     0     0 I qcom,qpnp-rtc 800f000.qcom,spmi: qcom,pm660@0:qcom,pm660_rtc: rtc core: registered qpnp_rtc as rtc0
01-01 07:28:29.515     0     0 I qcom,qpnp-rtc 800f000.qcom,spmi: qcom,pm660@0:qcom,pm660_rtc: setting system clock to 1970-01-01 07:28:29 UTC (26909)
08-24 20:07:46.101     0     0 W rtc0    : tm value: 2021-8-24 20:7:46
08-24 20:07:46.101     0     0 W rtc0    : mutex_lock_interruptible,err=0
08-24 20:07:46.105     0     0 W rtc0    : ifxxx err=-22
08-24 20:15:03.147     0     0 W rtc0    : tm value: 2021-8-24 20:15:3
08-24 20:15:03.147     0     0 W rtc0    : mutex_lock_interruptible,err=0

mutex_lock_interruptible,err=0ifxxx err=-22这两个log,但是没有err = rtc->ops->set_time(rtc->dev.parent, tm);

说明没有走这个if语句

else if (rtc->ops->set_time) {dev_warn(&rtc->dev, "err = rtc->ops->set_time(rtc->dev.parent, tm);\n");err = rtc->ops->set_time(rtc->dev.parent, tm);

这个rtc->ops->set_time似乎是空的

但是根据上面log中的qcom,qpnp-rtc两行log(这里再列在下面方便表述),高通的qcom,qpnp-rtc驱动已经注册了rtc0

01-01 07:28:28.790     0     0 I qcom,qpnp-rtc 800f000.qcom,spmi: qcom,pm660@0:qcom,pm660_rtc: rtc core: registered qpnp_rtc as rtc0
01-01 07:28:29.515     0     0 I qcom,qpnp-rtc 800f000.qcom,spmi: qcom,pm660@0:qcom,pm660_rtc: setting system clock to 1970-01-01 07:28:29 UTC (26909)

根据高通的qpnp_rtc驱动代码看

image

static int qpnp_rtc_probe(struct platform_device *pdev)
{const struct rtc_class_ops *rtc_ops = &qpnp_rtc_ro_ops;...//省略if (rtc_dd->rtc_write_enable == true)rtc_ops = &qpnp_rtc_rw_ops;...//省略/* Register the RTC device */rtc_dd->rtc = rtc_device_register("qpnp_rtc", &pdev->dev,rtc_ops, THIS_MODULE);if (IS_ERR(rtc_dd->rtc)) {dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n",__func__, PTR_ERR(rtc_dd->rtc));rc = PTR_ERR(rtc_dd->rtc);goto fail_rtc_enable;}...//省略
}

这个rtc_dd->rtc_write_enable很关键,如果是true.set_time = qpnp_rtc_set_time才会被注册

image

根据上面的代码可以看出,当设备树中的qcom,qpnp-rtc-write被设置为true时,满足rtc_dd->rtc_write_enable == true的条件。

按如下方式修改设备树,即可

diff --git a/msm-4.4/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/msm-4.4/arch/arm/boot/dts/qcom/msm-pm660.dtsi
index 56f8bfb..09b64eb 100755
--- a/msm-4.4/arch/arm/boot/dts/qcom/msm-pm660.dtsi
+++ b/msm-4.4/arch/arm/boot/dts/qcom/msm-pm660.dtsi
@@ -168,7 +168,7 @@compatible = "qcom,qpnp-rtc";#address-cells = <1>;#size-cells = <1>;
-                       qcom,qpnp-rtc-write = <0>;
+                       qcom,qpnp-rtc-write = <1>;qcom,qpnp-rtc-alarm-pwrup = <0>;qcom,pm660_rtc_rw@6000 {

修改设备树后hwclock -w报错没有了,但是系统会重启,原因未知


http://chatgpt.dhexx.cn/article/ReCb3G56.shtml

相关文章

Android top命令、ps命令、busybox命令

top命令 usage: top [-Hbq] [-k FIELD,] [-o FIELD,] [-s SORT] [-n NUMBER] [-m LINES] [-d SECONDS] [-p PID,] [-u USER,]Show process activity in real time.-H Show threads -k Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID) -o Show FIELDS (def PID,USER,PR,N…

OpenHarmony啃论文俱乐部—盘点开源鸿蒙引用的三方开源软件[1]

目录这里写自定义目录标题 OpenHarmony third_party三方库&#xff1a;学术研究和参与开源的结合third_party_openh264third_party_ninjathird_party_gnthird_party_markupsafethird_party_toyboxthird_party_gstreamerthird_party_ffmpegthird_party_mtdevthird_party_flutter…

Android缺少awk工具的几种解决方法

在日常测试中&#xff0c;我们会用到各种各样的Android平台&#xff0c;用于测试存储设备的性能。其中&#xff0c;我们依赖到Android平台自身的工具&#xff0c;通过编写shell脚本来实现测试存储设备的性能。   而awk工具(shell命令)在shell脚本中会经常用到&#xff0c;一般…

toybox 和 busybox 的作用

来自知乎&#xff1a;程序员秘书 ##前言## 我们在做android开发时&#xff0c;经常会有在板子系统里要修改文件内容对比验证问题&#xff0c;或者要操作特殊的shell命令操作看些信息&#xff0c;等等一些需求。但是往往会因为刷到板子的系统里默认没有/不支持相关的命令&…

欢乐听:一个简洁的瀑布流模式的音乐分享站

欢乐听 一个简洁的瀑布流模式的音乐分享站。

分享5个高质无损音乐网站,歌曲很丰富,爱听歌的小伙伴有耳福了

生活中很多人都离不开音乐&#xff0c;散步的时候听音乐&#xff0c;等待的时候听着音乐&#xff0c;心情不好的时候听音乐&#xff0c;不管走到哪&#xff0c;有音乐的陪伴一点也不寂寞&#xff0c;不同音乐的旋律给我们带来不同的心情&#xff0c;今天小编就给爱听音乐的小伙…

【音乐】收藏的300多首抖音神曲,MP3音乐分享,近一年的抖音歌曲

今天给大家分享N多&#xff08;300&#xff09;首抖音神曲。抖音大家都知道&#xff0c;各种火&#xff0c;各种原因&#xff0c;其中的BGM(背景音乐)更是起到了至关重要&#xff08;画龙点睛&#xff09;的作用&#xff0c;不知道是哪个大神搞的&#xff0c;去年我搞视频的时候…

搭建一个点歌QQ机器人,另外还能看美女

目录 前言具体实现1、爆照2、生日书3、获取歌词和分享音乐 完整项目下载地址&#xff08;配置了python环境&#xff09;完整项目下载地址&#xff08;电脑没有python环境&#xff09; 前言 完整项目&#xff0c;包括框架、代码和详细使用说明可以去社区下载&#xff08;下载完…

基于java的音乐网站的设计与实现

欢迎添加微信互相交流学习哦&#xff01; 项目源码&#xff1a;https://gitee.com/oklongmm/biye 基于java的音乐网站的设计与实现 摘 要 随着互联网和宽带上网的普及&#xff0c;网络传输以其特有的快速、高效、便捷的传输方式越来越被人们接受。在当今社会的影响下&…

android wifi传输音乐,让你通过WiFi分享手机上的歌曲,音乐共享软件MyStream十一发布Android版...

MyStream原来是 iOS上的音乐共享应用&#xff0c;十一期间&#xff0c;它将跨出iOS平台&#xff0c;首次推出Android版音乐共享服务。 MyStream和主流的Pandora、Spotify、Turntable.fm、Songza这些音乐分享服务并不一样。它将手机上的本地音乐通过WiFi或蓝牙和周围的设备进行音…

竞品分析:网易云音乐和QQ音乐,音乐类app的战场

文章从产品的角度分别分析两款产品的行业市场、功能、业务模式以及运营策略&#xff0c;进一步了解两款产品的差异与不同。 一、产品概况 1. 产品概述及版本 网易云音乐是一款专注于发现与分享的音乐产品&#xff0c;依托专业音乐人、DJ、好友推荐及社交功能&#xff0c;为用…

网易云音乐竞品分析

概述 1.原因 个人平时使用网易云较多&#xff0c;正好想学学竞品分析怎么写。因此&#xff0c;想通过梳理市场最新报告和数据表现&#xff0c;了解在线音乐行业的现状和市场情况&#xff1b;分析网易云音乐目前的市场地位、功能设计、UI设计等方面&#xff0c;与相关竞品进行对…

音乐平台程序源码分享

简介&#xff1a; 这是一个音乐分享平台源码&#xff0c;用户可以自行上传音乐分享&#xff0c;源码自适应手机&#xff0c;使用很方便。 安装说明&#xff1a; 演示环境&#xff1a;宝塔PHP5.5 mysql5.6 Apache 2.4.46&#xff0c;把程序上传到根目录&#xff0c;然后修改数…

分享两个音乐播放地址

下歌吧音乐下载平台 http://music.y444.cn/ 搜索时候如果没有想要的&#xff0c;可以切换线路搜索一下 MYFREEMP3 MYFREEMP3 一个音乐下载以及播放网站 下载后的音乐名称需要直接更改一下&#xff0c;可以下载歌曲的歌词等 http://tools.liumingye.cn/music/?pagesearch…

基于web的音乐分享网站的设计与实现

欢迎添加微信互相交流学习哦&#xff01; 项目源码&#xff1a;https://gitee.com/oklongmm/biye2 音乐分享网站的设计与实现 摘 要 随着社会的发展时代的前进&#xff0c;IT行业的发展也是日新月异&#xff0c;对人类的生产和生活方式产生了很大影响。网络传播以其特有的快…

把自己录制的mp3音乐分享到朋友圈

参考&#xff1a;https://www.zhihu.com/question/345647212 录了首歌&#xff0c;想上传至微信朋友圈&#xff0c;发现还没那么简单。 mp3音乐文件上传到网易云音乐后&#xff0c;无法使用分享功能&#xff0c;所以无法分享到朋友圈。 可通过以下步骤解决。 一、将mp3文件发…

#pragma comment

原因:突然看到#pragma comment,不知其意思.感觉自己是个渣渣.所以写了一篇博客. #pragma comment 简单来说就是链接了一个文件&#xff0c;它可以是compiler&#xff0c;exestr&#xff0c;lib&#xff0c;linker文件. 例如&#xff1a; #include<WinSock2.h> #pragma…

预处理 #pragma 命令详解

关注、星标公众号&#xff0c;不错过精彩内容 素材来源&#xff1a;网络 编辑整理&#xff1a;strongerHuang 预处理指令 #pragma 相信程序员都知道&#xff0c;但在所有的预处理指令中&#xff0c;#pragma 指令可能是最复杂的了&#xff0c;它的作用是设定编译器的状态或者是指…

#pragma DATA_SECTION与#pragma CODE_SECTION的使用

&#xff08;一&#xff09;#pragma DATA_SECTION 利用CCS进行DSP编程时&#xff0c;如果不指定变量的存储位置&#xff0c;那么编译器会自动给变量分配存储位置&#xff0c;但是&#xff0c;有些时候&#xff0c;需要将某个变量存放到某个特定的位置&#xff0c;这个时候就可…

#pragma用法大全

一、#pragma 1.1 #pragma message message能够在编译信息输出窗口中输出相应的信息&#xff0c;这对于源代码信息的控制是非常重要的。 #pragma message("test message!")1.2 #pragma code_seg 格式如&#xff1a; #pragma code_seg( [ [ { push | pop}, ] [ iden…