alarm学习总结Word下载.docx

上传人:b****4 文档编号:16674576 上传时间:2022-11-25 格式:DOCX 页数:11 大小:175.78KB
下载 相关 举报
alarm学习总结Word下载.docx_第1页
第1页 / 共11页
alarm学习总结Word下载.docx_第2页
第2页 / 共11页
alarm学习总结Word下载.docx_第3页
第3页 / 共11页
alarm学习总结Word下载.docx_第4页
第4页 / 共11页
alarm学习总结Word下载.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

alarm学习总结Word下载.docx

《alarm学习总结Word下载.docx》由会员分享,可在线阅读,更多相关《alarm学习总结Word下载.docx(11页珍藏版)》请在冰豆网上搜索。

alarm学习总结Word下载.docx

软件更新题型服务是否被打开)alarm_enabled这个全局量用来标记alarm设备是否被使能;

使能它的地方在

当我们从ui界面设置一些不同类型的alarm服务的时候,与其类型相对应的mask值会被赋给alarm_enabled这个全局量;

例如,如果上层应用下发的alarm设备有三种,其type值分别为1,2,3,那么其mask值分别为10,100,1000.这样根据alarm_enable的每一位是否为1,就可以判断出其对应的alarm设备是否被使能;

3与from_old_alarm_set里使能标志位对应,这里的操作清除了该标志位的mask值,对于已经触发回调函数的alarm设备,其状态应该从使能变成禁止,等待下次使能;

同样在清除闹钟时也会禁止alarm设备使能标志位;

4Alarm_pending这个全局量也用来存储各个类型alarm设备的mask值,当某一类型的alarm触发其回调函数时,表示这类alarm到期了,因此将这类alarm设备对应的mask值赋给alarm_pending,当上层得知这类alarm到期后,alarm_pending的值被清掉;

简单的说alarm_pending

的作用就是将底层到期的alarm事件告知上层;

5Wake_lock_timeout(&

alarm_wake_lock,5*HZ)该操作是给系统加5秒的alarm_wake_lock锁,即当前有alarm设备到期,需要触发上层应用,此时不允许系统休眠;

关于alarm_triggered回调函数:

代码里的注释说这个function是alarm结构体的回调函数,但仔细看看就能发现,alarm结构体不具备调用这个回调函数的条件,简单的说alarm设备在底层被初始化成定时器,而android_alarm.h中声明的structalarm里没有定时器相关信息,而从函数alarm_dev_init(void)初始化到现在也没看见任何起定时器的地方,因此structalarm.function是当alarm设备的时间到期时,会从别的地方调用过来,层层调用到alarm_triggered这个函数;

看到这里alarm设备对上层的接口是初始化完成了,可以确定的是alarm到期时,也是通过alarm_triggered将alarm.type相对应的mask值写入alarm_pending中,给上层查询;

2)第二个初始化函数__initalarm_driver_init(void)

同样作为__init函数,在内核初始化后会被自动执行;

1:

Hrtimer_init的第一个参数timer即structalarm_queue.timer;

hrtimertimer定义在kernel\include\linux中

这里的初始化工作相当于为每个类型的alarm设备初始化其相应的定时器,timer作为alarm设备的初始化信息,包括了expirestime、timer.function、rb_node;

初始化了定时器,注册了回调函数;

那么这里的time.function应该就是alarm定时器到期时所调用的回调函数了;

2:

注册回调函数alarm_timer_triggered;

判断当前定时器是否已经停止;

若停止,将定时器停止时的stop_time赋值给now,若没停止,则获取系统当前的时间,赋值给now,

若alarm的到期时间还在now时间之前,break,

3:

判断满足条件后,对维护alarm定时器的红黑树进行操作,删除掉过期的节点,保持first指针指向最先到期的节点;

4:

之后调用structalarm.function,这个function被第一个初始化函数__initalarm_dev_init(void)初始化成alarm_triggered();

由此可见,第二个初始化函数完成了alarm底层定时器的初始化操作,并且注册了回调函数alarm_timer_triggered(),在定时器到期后,回调函数会调用alarm_triggered;

将到期的alarm设备的mask值写入alarm_pending,给上层查询;

 

各种类型的alarm(提醒)服务被按类型初始化成定时器;

alarm_dev_init的作用就是针对每一类型的alarm服务初始化其对应的定时器hrtimer_init;

kernel管理这些定时器来确定当前的alarm是否到期;

二、设置alarm服务

Alarm服务的设置都是通过调用AlarmManagerService.java里的set方法将相应的时间和alarm的类型设置到kernel中;

Type即我们设置的alarm类型,在kernel里有不止一种的alarmtype的类型,闹钟服务只是其中的一种,因此在设置闹钟时间时,需要匹配对应的type;

alarmSeconds即平台层需要下发的时间了;

在android中java和c之间还有一个jni层,用来将java的方法与kernel的操作联系起来;

和闹钟有关的jni操作在com_android_server_AlarmMangerService.cpp中;

包括init,和set的方法都在这里与cpp对应起来了,因此调用set方法就会调用到jni的相应函数,

在函数android_server_AlarmManagerService_set()中会有如下调用:

ioctl(fd,ANDROID_ALARM_SET(type),&

ts);

&

ts结构体包括了设置的闹铃时间;

ANDROID_ALARM_SET(type)就是设置闹钟的命令了;

这个ioctl的操作在java中init方法中匹配上的:

open(“/dev/alarm”,O_RDWR);

因此set方法调用的ioctl操作就会对应到/dev/alarm注册的ioctl操作;

这个操作是在alarm-dev.c中注册的;

此时用户通过APK设置的闹钟时间和设置闹钟的操作就传到了kernel层;

2在alarm-dev.c中设置alarm类型会对应到alarm_ioctl中的caseANDROID_ALARM_SET;

alarm_start_range将用户空间得到的时间更新到ktime定时器中;

该函数的第一个参数&

alarms[alarm_type]是第一个初始化函数__initalarm_dev_init(void)中初始化的结构体structalarm;

第二个参数和第三个参数一样,是时间参数;

这个函数更新的是structalarm中的时间变量softexpires和expires,这两个成员被初始化成相同的值;

这样一个alarm设备就设置完成了;

这个时间被作为该alarm设备定时器到期的时间,在到期后调用回调函数alarm_timer_triggered()--alarm_triggered();

关于alarm定时器时间的更新:

从上边的流程可以看到ui界面设置一个alarm服务,在kernel只会更新到结构体structalarm,但该结构体并没有

和定时器相关的信息,而成员变量softexpires和expires何时被赋值给ktime定时器的?

这个是通过structalarm中成员rbnodenode来实现的;

层所有的alarm定时器都被维护成一个红黑树,那么每个类型alarm设备对应的红黑树的节点号也是可查询的;

Structhrtimer维护了相应红黑树节点定时器的信息,因此structalarm通过更新相应node的成员信息,就可以更新到hrtimer结构体中定时器的到

期时间了;

三、查询alarm是否到期

底层驱动在alarm设备到期后只会将alarmtypemask的值赋给alarm_pending,而上层是通过不断轮询alarmpending判断哪种类型的alarm到期了;

Alarmthread任务起来后,会一直调用函数waitforalarm(mDescriptor);

该函数在jni层被匹配成;

因此该服务对应到kernel就是alarm_ioctl会被一直调用,命令为android_alarm_wait;

将alarm_pending的值赋给rv,rv作为alarm_ioctl的返回值;

因此当alarm_triggered被触发时,alarm_pending就会被赋予相应的mask值;

所以当上层发命令轮询时,这个alarm_pending的值就会被当成返回值返回;

result=waitforalarm(mDescriptor);

result的值就是alarm_pending的值;

在获取到相应alarm_pending的值后,开始和上层alarm服务的mask值相匹配:

1若result的值匹配到poweroff_wakeup_mask上层就知道了此时闹钟到期了,就会调用相关的apk提醒用户;

Nv关机闹钟补丁分析

大多数的网站上都在说android手机不支持关机闹钟,关机闹钟的部分接口,调用需要根据具体的pmic芯片资料进行添加;

添加后是可以支持的;

Oscar项目使用tps6586xpmic芯片,该芯片支持rtc中断进行系统唤醒;

因此在此项目上可以实现关机闹铃;

NV的工程师给我们提供了支持关机闹钟的补丁,里边的修改如下:

1)tps6586x_rtc_probe

-/*1kHztickmode,enabletickcounting*/

+/*1kHztickmode,enabletickcounting,

+enablepoweroffalarm.

+*/

err=tps6586x_update(tps_dev,RTC_CTRL,

-RTC_ENABLE|OSC_SRC_SEL|((pdata->

cl_sel<

<

CL_SEL_POS)&

-CL_SEL_MASK),

-RTC_ENABLE|OSC_SRC_SEL|PRE_BYPASS|CL_SEL_MASK);

+RTC_ENABLE|OSC_SRC_SEL|RTC_RSVDC00|

+((pdata->

CL_SEL_MASK),

+RTC_ENABLE|OSC_SRC_SEL|RTC_RSVDC00|PRE_BYPASS|CL_SEL_MASK);

Proc函数中的修改如NV补丁中的log所示,增加了使能poweroffalarm的操作;

tps6586x_updata(dev,reg,val,mask);

由此可见此函数的第三个参数是用来写rtc_ctrl寄存器的值,其中:

#defineRTC_RSVDC00BIT(0)即1<

0;

……同理可以计算出其他位寄存器的值;

这里可以确定rtc_ctl寄存器里B0位值为1:

使能RTC_ALARM2寄存器;

这组寄存器可以产生唤醒系统的中断;

B3位为0;

rtc_count的计数频率为1KHZ;

即1024次计数为1秒;

这里可以对比下tps6586x中关于rtc寄存器的说明:

2)tps6586x_rtc_set_alarm

该函数将从kernel传下来的闹钟时间与系统时间进行比较,并计算出差值ticks,若差值大于0;

那么将ticks设置到rtc_alarm寄存器里;

NV给的补丁修改了设置的寄存器:

-err=tps6586x_writes(tps_dev,RTC_ALARM1_HI,sizeof(buff),buff);

+err=tps6586x_writes(tps_dev,RTC_ALARM2_HI,sizeof(buff),buff);

这里询问了NV的工程师,他们给出的答复如下:

OnlyRTC_ALARM2canautomaticallywakethePMUfromtheSLEEPstateoncetheRTC_COUNTvalueequalsthevaluestoredintheRTC_ALARM2Registers

因此设置关机闹钟应该将ticks写入到rtc_alarm2寄存器中;

函数tps6586x_writes将从RTC_ALARM2_Hi的高地址开始写入buff里所存储的ticks值;

这里的ticks值经过如下换算存入buff:

+buff[0]=(ticks>

>

8)&

0xff;

+buff[1]=ticks&

可见存入buff的值也是从高位开始的;

还有一点需要说明:

ticks的值在计算过程中经过了这样的操作:

ticks=(unsignedlonglong)seconds<

10;

......

ticks>

=12

换算成二进制后,最后两位被遗弃了:

这里可以参照下NV补丁中的注释:

/*

+TPS658621Cdatasheetupdate:

+ALM2[15:

0]iscomparedtoRTC[27:

12]regardlessifthe

+pre-scalerisenabledordisabled.

Rtc_count

39

38

37

27

12

11

10

9

2

1

Count以1024HZ的频率计时,那么

在计满1024次时,即count的

第10每秒增加1位;

这样从第

10位开始count所增加的位数就可

ALM2以转换成秒数了

15

ALM2寄存器一共16位,它会和COUNT的[27:

12]位进行比较,这里有个地方需要注意下,由于从第10位开始就是每秒递增计数了,而ALM2寄存器比较是从count的12位开始的,因此在将ticks的值写入ALM2的时候会舍弃2位;

也就有了如上的移位操作了;

舍弃了低2位的秒数,这样会带来3秒的比较误差;

RTC中断的产生会提前3秒;

这样是否有影响?

RTC_ALARM中断是用来在关机时唤醒系统的,并且在唤醒后将此次RTC开机事件报给上层,由上层调用闹钟的相关APK,来使能闹铃;

这么一个开机启动闹铃的过程本来就需要耗费时间;

因此提前了3秒产生中断也刚好在开机的过程中弥补掉了;

这样ALM2寄存器的16位可以表示到2^16<

2大约是72.8hours即ticks_max=72.8hours

通过以上修改,使能了ALM2寄存器,确定了计数频率,这样在设置闹钟的时候就可以把闹铃时间设置到RTC寄存器中,从而在时间到时产生可以唤醒系统的中断;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1