AlarmManager流程

1 类型

在M版本里,Alarm有以下几种方式
/**
* Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
* (wall clock time in UTC), which will wake up the device when
* it goes off.
*/
public static final int RTC_WAKEUP = 0;
/**
* Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
* (wall clock time in UTC). This alarm does not wake the
* device up; if it goes off while the device is asleep, it will not be
* delivered until the next time the device wakes up.
*/
public static final int RTC = 1;
/**
* Alarm time in {@link android.os.SystemClock#elapsedRealtime
* SystemClock.elapsedRealtime()} (time since boot, including sleep),
* which will wake up the device when it goes off.
*/
public static final int ELAPSED_REALTIME_WAKEUP = 2;
/**
* Alarm time in {@link android.os.SystemClock#elapsedRealtime
* SystemClock.elapsedRealtime()} (time since boot, including sleep).
* This alarm does not wake the device up; if it goes off while the device
* is asleep, it will not be delivered until the next time the device
* wakes up.
*/
public static final int ELAPSED_REALTIME = 3;

2 用法

public static void enableAlert(Context context, final Alarm alarm, final long atTimeInMillis) {
    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Log.iRelease(TAG, "enableAlert : setAlert id = " + alarm.id + " atTime = " + formatDate(atTimeInMillis)
            + " alarmType = " + alarm.daysOfWeekType);
    Intent intent = new Intent(ALARM_ALERT_ACTION);
    Parcel out = Parcel.obtain();
    alarm.writeToParcel(out, 0);
    out.setDataPosition(0);
    intent.putExtra(ALARM_RAW_DATA, out.marshall());
    int userid= UserHandle.getUserId(Binder.getCallingUid());
    intent.putExtra(USER_DATA, userid == UserHandle.USER_OWNER);
    PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    if (Utils.isKitKatOrLater()) {
        am.setExact(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);
    } else {
        am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);
    }
    Calendar c = Calendar.getInstance();
    c.setTimeInMillis(atTimeInMillis);
    String timeString = formatDayAndTime(context, c);
    saveNextAlarm(context, timeString);
    saveNextHwAlarm(context, timeString, atTimeInMillis);
    setStatusBarIcon(context, true);
    setNowAlertAlarmId(context, alarm.id);
    out.recycle();
}

public static void disableAlert(Context context) {
    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(ALARM_ALERT_ACTION);
    /**
     * remove_poweroff_alarm_anyway : has not alarm in database, or not alarm enable.
     * will remove poweroff alarm.
     */
    int userid= UserHandle.getUserId(Binder.getCallingUid());
    if (userid == UserHandle.USER_OWNER) {
        intent.putExtra(Config.REMOVE_POWEROFF_ALARM_ANYWAY, true);
    }
    PendingIntent sender = PendingIntent.getBroadcast(context, 0,
            intent, PendingIntent.FLAG_UPDATE_CURRENT);
    am.cancel(sender);
    saveNextAlarm(context, "");
    saveNextHwAlarm(context, "", 0);
    setStatusBarIcon(context, false);
    }

3 AlarmManager

public void set(int type, long triggerAtMillis, PendingIntent operation) {
    setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation, null, null);
}
    private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
        PendingIntent operation, WorkSource workSource, AlarmClockInfo alarmClock) {
    if (triggerAtMillis < 0) {
        /* NOTYET
        if (mAlwaysExact) {
            // Fatal error for KLP+ apps to use negative trigger times
            throw new IllegalArgumentException("Invalid alarm trigger time "
                    + triggerAtMillis);
        }
        */
        triggerAtMillis = 0;
    }

    try {
        mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation,
                workSource, alarmClock);
    } catch (RemoteException ex) {
  }
  }

4 AlarmManagerService

@Override
public void onStart() {
    mNativeData = init();
........
if (mNativeData != 0) {
        AlarmThread waitThread = new AlarmThread();
        waitThread.start();
    } else {
        Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
    }

    publishBinderService(Context.ALARM_SERVICE, mService);
}
private class AlarmThread extends Thread
{
    public AlarmThread()
    {
        super("AlarmManager");
    }

    public void run()
    {
        ArrayList triggerList = new ArrayList();

        while (true)
        {
            int result = waitForAlarm(mNativeData);
......
            Message msg = Message.obtain();
            msg.what =AlarmHandler.HANDLE_DELIVERALARMS;
                        msg.obj = triggerList;                                                  mHandler.removeMessages(AlarmHandler.HANDLE_DELIVERALARMS);                                 mHandler.sendMessageDelayed(msg, 50);
         }
@Override
protected void finalize() throws Throwable {
    try {
        close(mNativeData);
    } finally {
        super.finalize();
    }
}

5 JNI

com_android_server_AlarmManagerService.cpp
static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
{
jlong ret = init_alarm_driver();
if (ret) {
return ret;
}
return init_timerfd();
}
static jlong init_alarm_driver()
{
int fd = open("/dev/alarm", O_RDWR);
if (fd < 0) {
ALOGV("opening alarm driver failed: %s", strerror(errno));
return 0;
}
AlarmImpl *ret = new AlarmImplAlarmDriver(fd);
return reinterpret_cast(ret);
}
int AlarmImplAlarmDriver::set(int type, struct timespec *ts)
{
return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);
}
int AlarmImplAlarmDriver::waitForAlarm()
{
return ioctl(fds[0], ANDROID_ALARM_WAIT);
}

6 驱动

static long alarm_do_ioctl(struct file *file, unsigned int cmd,
                        struct timespec *ts)
{
int rv = 0;
unsigned long flags;
enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);

if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
    return -EINVAL;

if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
    if ((file->f_flags & O_ACCMODE) == O_RDONLY)
        return -EPERM;
    if (file->private_data == NULL &&
        cmd != ANDROID_ALARM_SET_RTC) {
        spin_lock_irqsave(&alarm_slock, flags);
        if (alarm_opened) {
            spin_unlock_irqrestore(&alarm_slock, flags);
            return -EBUSY;
        }
        alarm_opened = 1;
        file->private_data = (void *)1;
        spin_unlock_irqrestore(&alarm_slock, flags);
    }
}

switch (ANDROID_ALARM_BASE_CMD(cmd)) {
case ANDROID_RTC_ALARM_SET:  /* add for poweroff alarm */
    rv = alarm_set_rtc_alarm(ts->tv_sec, true);
    break;
case ANDROID_ALARM_CLEAR(0):
    alarm_clear(alarm_type);
    break;
case ANDROID_ALARM_SET(0):
    alarm_set(alarm_type, ts);
    break;
case ANDROID_ALARM_SET_AND_WAIT(0):
    alarm_set(alarm_type, ts);
    /* fall though */
case ANDROID_ALARM_WAIT:
    rv = alarm_wait();
    break;
case ANDROID_ALARM_SET_RTC:
    rv = alarm_set_rtc(ts);
    break;
case ANDROID_ALARM_GET_TIME(0):
    rv = alarm_get_time(alarm_type, ts);
    break;

default:
    rv = -EINVAL;
}
    return rv;
}

7 RTC

就是如果系统没有suspend的时候,设置闹钟并不会往rtc 芯片的寄存器上写数据,因为不需要唤醒系统,所以闹钟数据时间什么的就通过上层写到设备文件/dev/alarm
里面就可以了,AlarmThread 会不停的去轮寻下一个时间有没有闹钟,直接从设备文件 /dev/alarm 里面读取
第二种,系统要是进入susupend的话,alarm 的alarm_suspend 就会写到下层的rtc芯片的寄存器上去, 然后即使系统suspend之后,闹钟通过rtc 也能唤醒系统。
这里就调用到了interface.c 里面 //这里面 int rtc_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-hym8563.c
然后就到了
static int hym8563_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], __u16 len)
{
int ret;
ret = i2c_master_reg8_send(client, reg, buf, (int)len, RTC_SPEED);
return ret;
}

到此,闹钟时间就已经写到rtc 芯片的寄存器里面,第二个参数就是寄存器的名字,后面的buf就是要写入的时间,rtc芯片是额外供电的,所以系统suspend之后,系统kernel都关了,但是rtc里面还有电,寄存器里面数据还是有的(掉电就会丢失数据),所以闹钟到了,通过硬件中断机制就可以唤醒系统。

你可能感兴趣的:(Alarm)