Android Alarm 工作原理(java)

本文详细剖析Android应用如何利用AlarmManager设置闹钟,涉及时钟类型选择、PendingIntent与BroadcastReceiver、系统服务调用过程,以及闹钟触发时机和处理机制。深入理解AlarmManager的工作原理和实际操作细节。

一、APP 使用

闹钟设置步骤:

  • 定义一个 PendingIntent,用户闹钟到期时触发相应动作(发送广播、启动服务等);
  • 调用 AlarmManager 的 set 函数设置闹钟;
  • 对于第一步使用广播方式,需要定义广播接收器,捕捉闹钟到期广播;

1、时钟类型

Android framework 中定义的时钟类型:

public static final int RTC_WAKEUP = 0;
public static final int RTC = 1;
public static final int ELAPSED_REALTIME_WAKEUP = 2;
public static final int ELAPSED_REALTIME = 3;

对应的 Native 中使用的时钟类型:

static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
   
   
    CLOCK_REALTIME_ALARM,
    CLOCK_REALTIME,
    CLOCK_BOOTTIME_ALARM,
    CLOCK_BOOTTIME,
    CLOCK_MONOTONIC,
    CLOCK_REALTIME,
};

上层时钟类型作为索引,在 android_alarm_to_clockid 表中取到的时钟类型,即为底层使用的时钟。比如上层时钟类型为 ELAPSED_REALTIME_WAKEUP,那么底层时钟类型为 CLOCK_BOOTTIME_ALARM。实际使用过程中 RTC_WAKEUP、RTC 两种类型,会在 framework 层中转换层 ELAPSED_REALTIME_WAKEUP、ELAPSED_REALTIME 时钟。
RTC 表示 Unix 时间,ELAPSED_REALTIME 表示系统启动到现在经过的时间。两种时间都 WAKEUP 的版本,表示可以唤醒系统。

2、使用实例

PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1,
        new Intent(context, AlarmReceiver.class).setAction("testtime"), PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 15000 * 60 * 1L, pendingIntent);

二、原理分析

1、闹钟设置

APP 设置闹钟最终都会调用 AlarmManager 的 setImpl 函数:

private void setImpl(@AlarmType int type, long triggerAtMillis, long windowMillis,
        long intervalMillis, int flags, PendingIntent operation, final OnAlarmListener listener,
        String listenerTag, Handler targetHandler, WorkSource workSource,
        AlarmClockInfo alarmClock)

参数说明:

变量名 含义
type 类型:RTC_WAKEUP、RTC、ELAPSED_REALTIME_WAKEUP、ELAPSED_REALTIME
triggerAtMillis 闹钟触发时间(与 type 对应设置)
windowMillis 窗口时间,精确定间设置 WINDOW_EXACT(0)
intervalMillis 重复闹钟间隔时间
flags 标记:FLAG_STANDALONE、FLAG_WAKE_FROM_IDLE、FLAG_ALLOW_WHILE_IDLE、FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED、FLAG_IDLE_UNTIL
operation PendingIntent
listener 与 operation 必须二选其一;重复闹钟,只能设置 operation 参数。
listenerTag 与 listener 配置使用
targetHandler OnAlarmListener 的 onAlarm() 方法将通过 targetHandler 调用,如果 targetHandler 为 null,则 onAlarm 将在应用程序的 main looper 上调用。

setImpl 函数通过 Binder 会调用到 AlarmManagerService 的 set 函数:

public void set(String callingPackage,
        int type, long triggerAtTime, long windowLength, long interval, int flags,
        PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
        WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock) {
   
   
    final int callingUid = Binder.getCallingUid();

    // make sure the caller is not lying about which package should be blamed for
    // wakelock time spent in alarm delivery
    mAppOps.checkPackage(callingUid, callingPackage);

    // Repeating alarms must use PendingIntent, not direct listener
    if (interval != 0) {
   
   
        if (directReceiver != null) {
   
   
            throw new IllegalArgumentException("Repeating alarms cannot use AlarmReceivers");
        }
    }

    if (workSource != null) {
   
   
        getContext().enforcePermission(
                android.Manifest.permission.UPDATE_DEVICE_STATS,
                Binder.getCallingPid(), callingUid, "AlarmManager.set");
    }

    // No incoming callers can request either WAKE_FROM_IDLE or
    // ALLOW_WHILE_IDLE_UNRESTRICTED -- we will apply those later as appropriate.
    flags &= ~(AlarmManager.FLAG_WAKE_FROM_IDLE
            | AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED);

    // Only the system can use FLAG_IDLE_UNTIL -- this is used to tell the alarm
    // manager when to come out of idle mode, which is only for DeviceIdleController.
    if (callingUid != Process.SYSTEM_UID) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翻滚吧香香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值