Alarm调用流程 activiti 调用子流程
涉及代码;
./packages/apps/DeskClock/src/com/android/deskclock/Alarms.java
./frameworks/base/core/java/android/app/AlarmManager.java
./frameworks/base/services/java/com/android/server/AlarmManagerService.java
./frameworks/base/services/jni/com_android_server_AlarmManagerService.cpp
./kernel/kernel/drivers/rtc/alarm-dev.c
./kernel/kernel/include/linux/android_alarm.h
./kernel/kernel/drivers/rtc/alarm.c
./kernel/kernel/drivers/rtc/interface.c
./kernel/kernel/drivers/rtc/rtc-pcf8563.c
./packages/apps/DeskClock/src/com/android/deskclock/AlarmReceiver.java
./kernel/arch/arm/configs/mmp2_android_defconfig
./kernel/kernel/kernel/.config
点击Clock 应用程序,然后设置新闹钟,会调到Alarms.java 里面的
public static long setAlarm(Context context, Alarm alarm) {
....
setNextAlert(context);
....
}
然后这里面也会调用到
public static void setNextAlert(final Context context) {
if (!enableSnoozeAlert(context)) {
Alarm alarm =calculateNextAlert(context);//new 一个新的alarm
if (alarm != null) {
enableAlert(context, alarm, alarm.time);
} else {
disableAlert(context);
}
}
}
然后继续调用到
private static void enableAlert(Context context, final Alarm alarm,final long atTimeInMillis) {
.......
am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis,sender); //这里是RTC_WAKEUP,这就保证了即使系统睡眠了,都能唤醒,闹钟工作(android平台关机闹钟好像不行)
.....
}
然后就调用到了AlarmManager.java 里面方法
public voidset(int type, long triggerAtTime, PendingIntent operation) {
try {
mService.set(type, triggerAtTime, operation);
} catch (RemoteException ex) {
}
}
然后就调用到了AlarmManagerService.java 里面方法
public void set(int type, long triggerAtTime, PendingIntentoperation) {
setRepeating(type, triggerAtTime, 0, operation);
}
然后继续调用
public void setRepeating(int type, long triggerAtTime, longinterval,
PendingIntent operation) {
.....
synchronized (mLock) {
Alarm alarm = new Alarm();
alarm.type = type;
alarm.when = triggerAtTime;
alarm.repeatInterval = interval;
alarm.operation = operation;
// Remove this alarm if already scheduled.
removeLocked(operation);
if (localLOGV) Slog.v(TAG, "set: " + alarm);
int index = addAlarmLocked(alarm);
if (index == 0) {
setLocked(alarm);
}
}
}
然后就调用到
private void setLocked(Alarm alarm)
{
......
set(mDescriptor, alarm.type, alarmSeconds,alarmNanoseconds);//mDescriptor 这里的文件是 /dev/alarm
.....
}
这里就调用到jni了
private native void set(int fd, int type, long seconds, longnanoseconds);
这就调用到了com_android_server_AlarmManagerService.cpp 里面
static JNINativeMethod sMethods[] = {
{"init","()I", (void*)android_server_AlarmManagerService_init},
{"close","(I)V", (void*)android_server_AlarmManagerService_close},
{"set","(IIJJ)V", (void*)android_server_AlarmManagerService_set},
{"waitForAlarm", "(I)I",(void*)android_server_AlarmManagerService_waitForAlarm},
{"setKernelTimezone", "(II)I",(void*)android_server_AlarmManagerService_setKernelTimezone},
};
set 对应的是android_server_AlarmManagerService_set, 具体是
static void android_server_AlarmManagerService_set(JNIEnv* env,jobject obj, jint fd, jint type, jlong seconds, jlongnanoseconds)
{
#if HAVE_ANDROID_OS
structtimespec ts;
ts.tv_sec =seconds;
ts.tv_nsec =nanoseconds;
int result =ioctl(fd, ANDROID_ALARM_SET(type), &ts);
if (result< 0)
{
LOGE("Unable to set alarm to %lld. lld: %sn", seconds,nanoseconds, strerror(errno));
}
#endif
}
然后ioctl 就调用到了alarm-dev.c
static long alarm_ioctl(struct file *file, unsigned int cmd,unsigned long arg)
{
....
caseANDROID_ALARM_SET(0):
if(copy_from_user(&new_alarm_time, (void __user*)arg,
sizeof(new_alarm_time))) {
rv = -EFAULT;
goto err1;
}
from_old_alarm_set:
spin_lock_irqsave(&alarm_slock,flags);
pr_alarm(IO, "alarm %d set %ld. ldn",alarm_type,
new_alarm_time.tv_sec,new_alarm_time.tv_nsec);
alarm_enabled |= alarm_type_mask;
alarm_start_range(&alarms[alarm_type],
timespec_to_ktime(new_alarm_time),
timespec_to_ktime(new_alarm_time));
spin_unlock_irqrestore(&alarm_slock,flags);
if (ANDROID_ALARM_BASE_CMD(cmd) !=ANDROID_ALARM_SET_AND_WAIT(0)
&& cmd !=ANDROID_ALARM_SET_AND_WAIT_OLD)
break;
....
case ANDROID_ALARM_SET_RTC:
if (copy_from_user(&new_rtc_time,(void __user *)arg,
sizeof(new_rtc_time))) {
rv = -EFAULT;
goto err1;
}
rv = alarm_set_rtc(new_rtc_time);
spin_lock_irqsave(&alarm_slock,flags);
alarm_pending |=ANDROID_ALARM_TIME_CHANGE_MASK;
wake_up(&alarm_wait_queue);
spin_unlock_irqrestore(&alarm_slock,flags);
if (rv < 0)
goto err1;
break;
....
}
然后这边就调用到了alarm_start_range设置闹钟,alarm_set_rtc 设置RTC
这两个函数在 android_alarm.h 声明,在 alarm.c 里实现
这是android_alarm.h 里面的声明
void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_tend);
int alarm_try_to_cancel(struct alarm *alarm);
int alarm_cancel(struct alarm *alarm);
ktime_t alarm_get_elapsed_realtime(void);
int alarm_set_rtc(const struct timespec ts);
下面看alarm.c 里面实现:
int alarm_set_rtc(struct timespec new_time)
{
....
ret = rtc_set_time(alarm_rtc_dev,&rtc_new_rtc_time);
....
}
alarm.c 里面实现了 alarm_suspendalarm_resume 函数
就是如果系统没有suspend的时候,设置闹钟并不会往rtc芯片的寄存器上写数据,因为不需要唤醒系统,所以闹钟数据时间什么的就通过上层写到设备文件/dev/alarm
里面就可以了,AlarmThread 会不停的去轮寻下一个时间有没有闹钟,直接从设备文件 /dev/alarm 里面读取
第二种,系统要是进入susupend的话,alarm 的alarm_suspend就会写到下层的rtc芯片的寄存器上去, 然后即使系统suspend之后,闹钟通过rtc 也能唤醒系统
这里就调用到了interface.c 里面 //这里面 intrtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 差不多也是跟下面一样
int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{
....
err =rtc->ops->set_time(rtc->dev.parent,tm);
....
}
然后set_time 就看到具体的是那个RTC芯片,这边我们是rtc-pcf8563.c
static const struct rtc_class_ops pcf8563_rtc_ops = {
.read_time= pcf8563_rtc_read_time,
.set_time= pcf8563_rtc_set_time,
.read_alarm= pcf8563_rtc_read_alarm,
.set_alarm= pcf8563_rtc_set_alarm,
};
然后就到了
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time*tm)
{
unsignedchar buf[TIME_NUM];
intret;
ret =data_calc(buf, tm, TIME_NUM);
if (ret< 0)
goto out;
ret =i2c_smbus_write_i2c_block_data(pcf8563_info->client,PCF8563_RTC_SEC, TIME_NUM, buf);//这边就调用i2c统一接口,往pcf8563rtc芯片寄存器里面写出数据
out:
returnret;
}
到此,闹钟时间就已经写到rtc芯片的寄存器里面,第二个参数就是寄存器的名字,后面的buf就是要写入的时间,rtc芯片是额外供电的,所以系统suspend之后,系统kernel都关了,但是rtc里面还有电,寄存器里面数据还是有的(掉电就会丢失数据),所以闹钟到了,通过硬件中断机制就可以唤醒系统。
上面那个rtc下面有几十个rtc芯片驱动代码,没有结构基本一样,都有基本操作函数,注册函数,都是对各自芯片上特有的寄存器操作,为什么调用的是pcf8563rtc呢?这个要看你系统用的是那个芯片,这个可以通过./kernel/kernel/kernel/.config查看,这边的pcf8563rtc 是当前系统正在使用的芯片型号
# CONFIG_RTC_DRV_ISL1208 is not set
# CONFIG_RTC_DRV_X1205 is not set
CONFIG_RTC_DRV_PCF8563=y
# CONFIG_RTC_DRV_PCF8583 is not set
# CONFIG_RTC_DRV_M41T80 is not set
下面是系统唤醒之后,闹钟怎么工作的流程,简单阐述
系统没有suspend的话直接走下面流程,如果suspend的话会被RTC唤醒,然后还是走下面的流程
private class AlarmThread extends Thread
{
public AlarmThread()
{
super("AlarmManager");
}
public void run()
{
while (true)
{
int result = waitForAlarm(mDescriptor);//这里调用jni调用static jintandroid_server_AlarmManagerService_waitForAlarm,主要还是对/dev/alarm 操作
....
Alarm alarm = it.next();
try {
if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
alarm.operation.send(mContext, 0,
mBackgroundIntent.putExtra(
Intent.EXTRA_ALARM_COUNT, alarm.count),
mResultReceiver, mHandler);
....
}
}
}
static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*env, jobject obj, jint fd)
{
#if HAVE_ANDROID_OS
int result =0;
do
{
result = ioctl(fd, ANDROID_ALARM_WAIT);
} while(result < 0 && errno== EINTR);
if (result< 0)
{
LOGE("Unable to wait on alarm: %sn", strerror(errno));
return 0;
}
returnresult;
#endif
}
AlarmManagerService里面有个AlarmThread 会一直轮询/dev/alarm文件,如果打开失败就直接返回,成功就会做一些动作,比如查找时间最近的
alarm,比如睡眠被闹钟唤醒的时候,这边就发一个intent出去,然后在AlarmReceiver.java里面弹出里面会收到就会调用下面的
context.startActivity(alarmAlert);
然后弹出alarm 这个界面
Class c = AlarmAlert.class;
其中public class AlarmAlert extendsAlarmAlertFullScreen所以系统睡眠之后被alarm唤醒弹出的alarm就是这边start的
public class AlarmReceiver extends BroadcastReceiver {
privatefinal static int STALE_WINDOW = 30 * 60 * 1000;
@Override
public voidonReceive(Context context, Intent intent) {
.........
Intent alarmAlert = new Intent(context, c);
alarmAlert.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm);
alarmAlert.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_NO_USER_ACTION);
context.startActivity(alarmAlert);
........
}
更多阅读
外贸新人的最详细业务流程(1) 外贸业务流程
外贸新人的最详细业务流程........刚在SOHU的一个BBS板块里边看到一个叫“飞翔的狗狗”写的,觉得很好,发过来给大家看看。外贸就是和老外做生意,挣老外的银子。一般的操作流程过程如下:1),和老外谈生意,接订单2),备货:下订单到工厂生产或采购3
个体工商户变更登记 流程 变更税务登记证流程
个体工商户变更(登记)流程 各位好,上次介绍了个体工商户开业登记流程,今天为大家讲解一下个体工商户变更登记流程。不足之处,欢迎批评指正。目前,个体工商户变更主要有以下三类:名称变更,经营地址变更,经营范围变更。经营着变更目前是不受
苹果公司新产品开发流程 新产品开发流程表
每一个新产品都源自于设计在Apple内,设计宛如皇室般地被礼遇着,所有的产品都遵照着设计师们的愿望。对于其他公司来说,这是完全相反的状况。设计并不是迎合着制造流程、财务预算或是生产部门,而是这一切都必须顺从着由Jony Ive领导的设
小组会会议流程建议 小组会议流程
各位梦想实践家:为了取得高效的小组会、大组会的会议成果,让每个成员在非常宝贵的时间最大收益,请大家能遵循以下会议制度。会议组织者能做好会议进程、秩序的引导。开会制度:1、 人员到齐后方可开始。2、 确定会议主题和流程后,严格
汽车4S店售后服务流程 汽车售后服务的流程
一、核心流程的价值体现出的“顾客为中心”的服务理念,展现品牌服务特色与战略,让客户充分体认有形化服务的特色,以提升客户的忠诚度;以标准化、统一化的作业标准,规范所有服务网点,面对客户的服务行动,透过核心流程的优化作业,提升客户满意