AlarmManagerService(一)

极力推荐Android 开发大总结文章:欢迎收藏
程序员Android 力荐 ,Android 开发者需要的必备技能

本篇文章主要介绍 Android 开发中的AlarmManagerService部分知识点,通过阅读本篇文章,您将收获以下内容:

1.AlarmManager的使用
2.AlarmManagerService初始化

本文转自网络地址如下:
http://www.robinheztto.com/2017/03/10/android-alarm-1/

Android系统通过AlarmManager向应用提供定时/闹钟服务,以使应用在其生命周期之外可执行基于特定时间的操作,本篇将具体分析AlarmManager的使用及AlarmManagerService服务的初始化。

相关源码位于以下文件中:

frameworks/base/core/java/android/app/AlarmManager.java
frameworks/base/services/core/java/com/android/server/AlarmManagerService.java
frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp

AlarmManager的使用

1.获取AlarmManager:
Alarm相关的服务接口定义在AlarmManager中,与其他系统服务一样,通过Context获取AlarmManager。

Context.getSystemService(Context.ALARM_SERVICE);
  1. Alarm的类型:
  • AlarmManager.RTC_WAKEUP
    使用系统绝对时间(当前系统时间,System.currentTimeMillis()),系统休眠状态也将唤醒系统。

  • AlarmManager.RTC
    使用系统绝对时间(当前系统时间,System.currentTimeMillis()),系统休眠状态下不可用。

  • AlarmManager.ELAPSED_REALTIME_WAKEUP
    使用系统相对时间(相对系统启动时间,SystemClock.elapsedRealtime()),系统休眠状态也将唤醒系统。

  • AlarmManager.ELAPSED_REALTIME
    使用系统相对时间(相对系统启动时间,SystemClock.elapsedRealtime()),系统休眠状态下不可用
    RTC/RTC_WAKEUP和ELAPSED_REALTIME/ELAPSED_REALTIME_WAKEUP最大的差别就是RTC受time zone/locale的影响,可以通过修改手机时间触发闹钟事件,ELAPSED_REALTIME/ELAPSED_REALTIME_WAKEUP要通过真实时间的流逝,即使在休眠状态时间也会被计算。

WAKEUP类型的Alarm会唤醒系统,休眠状态下会增加系统的功耗,所以在使用中应尽量避免使用该种类型的Alarm。

  1. Alarm的Flag:
  • FLAG_STANDALONE
    指定stand-alone精准alarm,该alarm不会被batch,设置WINDOW_EXACT的alarm会指定此flag。
  • FLAG_WAKE_FROM_IDLE
    指定alarm即使在idle模式也将唤醒系统,如alarm clock。
  • FLAG_ALLOW_WHILE_IDLE
    针对Doze模式,alarm即使在系统idle状态下也会执行,但是不会使系统退出idle mode,只有特殊alarm才需要标记该Flag。
  • FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED
    针对Doze模式,alarm即使在系统idle状态下也会执行而且没有时间限制,但是不会使系统退出idle mode,只有特殊alarm才需要标记该Flag。
  • FLAG_IDLE_UNTIL
    只有调用AlarmManager.setIdleUntil()接口才可能设置该flag,用来使系统进入idle mode直到marker alarm被执行,执行marker alarm时系统会退出idle mode(设置后进入DozeIdle状态让Alarm系统挂起,直到这个Alarm到期)。

4.Alarm的set:

非精准Alarm,其window被指定为WINDOW_HEURISTIC:


public void set(int type, long triggerAtMillis, PendingIntent operation) {}

public void set(int type, long triggerAtMillis, String tag, OnAlarmListener listener,Handler targetHandler) {}

public void setRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation) {}

public void setInexactRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation) {}// Doze模式下

public void setAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {} 

精准Alarm,其window被标记为WINDOW_EXACT

public void setWindow(int type, long windowStartMillis, long windowLengthMillis,PendingIntent operation) {}

public void setWindow(int type, long windowStartMillis, long windowLengthMillis, String tag, OnAlarmListener listener, Handler targetHandler) {}

public void setExact(int type, long triggerAtMillis, PendingIntent operation) {}  
 
public void setExact(int type, long triggerAtMillis, String tag, OnAlarmListener listener, Handler targetHandler) {}  

public void setAlarmClock(AlarmClockInfo info, PendingIntent operation) {}// Doze模式下

public void setIdleUntil(int type, long triggerAtMillis, String tag, OnAlarmListener listener,Handler targetHandler) {}

public void setExactAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {}

AlarmManager中的set方法最终都是调用setImpl,下面是setImpl的具体实现。
frameworks/base/core/java/android/app/AlarmManager.java

 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) {
        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;
        }
// OnAlarmListener封装到ListenerWrapper,并添加到sWrappers管理
        ListenerWrapper recipientWrapper = null;
        if (listener != null) {
            synchronized (AlarmManager.class) {
                if (sWrappers == null) {
                    sWrappers = new ArrayMap<OnAlarmListener, ListenerWrapper>();
                }

                recipientWrapper = sWrappers.get(listener);
                // no existing wrapper => build a new one
                if (recipientWrapper == null) {
                    recipientWrapper = new ListenerWrapper(listener);
                    sWrappers.put(listener, recipientWrapper);
                }
            }

            final Handler handler = (targetHandler != null) ? targetHandler : mMainThreadHandler;
            recipientWrapper.setHandler(handler);
        }
 // 调用AlarmManagerService
        try {
            mService.set(mPackageName, type, triggerAtMillis, windowMillis, intervalMillis, flags,
                    operation, recipientWrapper, listenerTag, workSource, alarmClock);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

AlarmManagerService初始化

    public AlarmManagerService(Context context) {
        super(context);
        mConstants = new Constants(mHandler);
    }

下面先看Constants类的具体实现,主要负责Alarm相关的常量的读取及更新。

 private final class Constants extends ContentObserver {
        // Key names stored in the settings value.
        private static final String KEY_MIN_FUTURITY = "min_futurity";
        private static final String KEY_MIN_INTERVAL = "min_interval";
        private static final String KEY_ALLOW_WHILE_IDLE_SHORT_TIME = "allow_while_idle_short_time";
        private static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time";
        private static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION
                = "allow_while_idle_whitelist_duration";
        private static final String KEY_LISTENER_TIMEOUT = "listener_timeout";

        private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
        private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
        private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;
        private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;
        private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;

        private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;

        // Minimum futurity of a new alarm
        public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;

        // Minimum alarm recurrence interval
        public long MIN_INTERVAL = DEFAULT_MIN_INTERVAL;

        // Minimum time between ALLOW_WHILE_IDLE alarms when system is not idle.
        public long ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME;

        // Minimum time between ALLOW_WHILE_IDLE alarms when system is idling.
        public long ALLOW_WHILE_IDLE_LONG_TIME = DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME;

        // BroadcastOptions.setTemporaryAppWhitelistDuration() to use for FLAG_ALLOW_WHILE_IDLE.
        public long ALLOW_WHILE_IDLE_WHITELIST_DURATION
                = DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION;

        // Direct alarm listener callback timeout
        public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT;

        private ContentResolver mResolver;
        private final KeyValueListParser mParser = new KeyValueListParser(',');
        private long mLastAllowWhileIdleWhitelistDuration = -1;

        public Constants(Handler handler) {
            super(handler);
            updateAllowWhileIdleMinTimeLocked();
            updateAllowWhileIdleWhitelistDurationLocked();
        }

        public void start(ContentResolver resolver) {
            mResolver = resolver;
            mResolver.registerContentObserver(Settings.Global.getUriFor(
                    Settings.Global.ALARM_MANAGER_CONSTANTS), false, this);
            updateConstants();
        }

        public void updateAllowWhileIdleMinTimeLocked() {
            mAllowWhileIdleMinTime = mPendingIdleUntil != null
                    ? ALLOW_WHILE_IDLE_LONG_TIME : ALLOW_WHILE_IDLE_SHORT_TIME;
        }

        public void updateAllowWhileIdleWhitelistDurationLocked() {
            if (mLastAllowWhileIdleWhitelistDuration != ALLOW_WHILE_IDLE_WHITELIST_DURATION) {
                mLastAllowWhileIdleWhitelistDuration = ALLOW_WHILE_IDLE_WHITELIST_DURATION;
                BroadcastOptions opts = BroadcastOptions.makeBasic();
                opts.setTemporaryAppWhitelistDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION);
                mIdleOptions = opts.toBundle();
            }
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            updateConstants();
        }

        private void updateConstants() {
            synchronized (mLock) {
                try {
                    mParser.setString(Settings.Global.getString(mResolver,
                            Settings.Global.ALARM_MANAGER_CONSTANTS));
                } catch (IllegalArgumentException e) {
                    // Failed to parse the settings string, log this and move on
                    // with defaults.
                    Slog.e(TAG, "Bad alarm manager settings", e);
                }

                MIN_FUTURITY = mParser.getLong(KEY_MIN_FUTURITY, DEFAULT_MIN_FUTURITY);
                MIN_INTERVAL = mParser.getLong(KEY_MIN_INTERVAL, DEFAULT_MIN_INTERVAL);
                ALLOW_WHILE_IDLE_SHORT_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME,
                        DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME);
                ALLOW_WHILE_IDLE_LONG_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME,
                        DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME);
                ALLOW_WHILE_IDLE_WHITELIST_DURATION = mParser.getLong(
                        KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION,
                        DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION);
                LISTENER_TIMEOUT = mParser.getLong(KEY_LISTENER_TIMEOUT,
                        DEFAULT_LISTENER_TIMEOUT);

                updateAllowWhileIdleMinTimeLocked();
                updateAllowWhileIdleWhitelistDurationLocked();
            }
        }

        void dump(PrintWriter pw) {
            pw.println("  Settings:");

            pw.print("    "); pw.print(KEY_MIN_FUTURITY); pw.print("=");
            TimeUtils.formatDuration(MIN_FUTURITY, pw);
            pw.println();

            pw.print("    "); pw.print(KEY_MIN_INTERVAL); pw.print("=");
            TimeUtils.formatDuration(MIN_INTERVAL, pw);
            pw.println();

            pw.print("    "); pw.print(KEY_LISTENER_TIMEOUT); pw.print("=");
            TimeUtils.formatDuration(LISTENER_TIMEOUT, pw);
            pw.println();

            pw.print("    "); pw.print(KEY_ALLOW_WHILE_IDLE_SHORT_TIME); pw.print("=");
            TimeUtils.formatDuration(ALLOW_WHILE_IDLE_SHORT_TIME, pw);
            pw.println();

            pw.print("    "); pw.print(KEY_ALLOW_WHILE_IDLE_LONG_TIME); pw.print("=");
            TimeUtils.formatDuration(ALLOW_WHILE_IDLE_LONG_TIME, pw);
            pw.println();

            pw.print("    "); pw.print(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION); pw.print("=");
            TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw);
            pw.println();
        }
    }

AlarmManagerService实例化后即调用onStart()方法。

  @Override
    public void onStart() {
       // native层初始化
        mNativeData = init();
        mNextWakeup = mNextNonWakeup = 0;

        // We have to set current TimeZone info to kernel
        // because kernel doesn't keep this after reboot
        setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
        /// M:add for PPL feature ,@{
        initPpl();
        ///@}
        /// M: For handling non-wakeup alarms while WFD is connected
        registerWFDStatusChangeReciever();
        ///@}
        /// M: added for BG powerSaving feature @{
        initAlarmGrouping();
        ///@}
        // Also sure that we're booting with a halfway sensible current time
        if (mNativeData != 0) {
            final long systemBuildTime = Environment.getRootDirectory().lastModified();
            if (System.currentTimeMillis() < systemBuildTime) {
                Slog.i(TAG, "Current time only " + System.currentTimeMillis()
                        + ", advancing to build time " + systemBuildTime);
                setKernelTime(mNativeData, systemBuildTime);
            }
        }

        // Determine SysUI's uid
        final PackageManager packMan = getContext().getPackageManager();
        try {
            PermissionInfo sysUiPerm = packMan.getPermissionInfo(SYSTEM_UI_SELF_PERMISSION, 0);
            ApplicationInfo sysUi = packMan.getApplicationInfo(sysUiPerm.packageName, 0);
            if ((sysUi.privateFlags&ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
                mSystemUiUid = sysUi.uid;
            } else {
                Slog.e(TAG, "SysUI permission " + SYSTEM_UI_SELF_PERMISSION
                        + " defined by non-privileged app " + sysUi.packageName
                        + " - ignoring");
            }
        } catch (NameNotFoundException e) {
        }

        if (mSystemUiUid <= 0) {
            Slog.wtf(TAG, "SysUI package not found!");
        }

        PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");

        mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
                new Intent(Intent.ACTION_TIME_TICK).addFlags(
                        Intent.FLAG_RECEIVER_REGISTERED_ONLY
                        | Intent.FLAG_RECEIVER_FOREGROUND
                        | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS), 0,
                        UserHandle.ALL);
        Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
                | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
        mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
        
        // now that we have initied the driver schedule the alarm
        mClockReceiver = new ClockReceiver();
        mClockReceiver.scheduleTimeTickEvent();
        mClockReceiver.scheduleDateChangedEvent();
        mInteractiveStateReceiver = new InteractiveStateReceiver();
        mUninstallReceiver = new UninstallReceiver();
        
        if (mNativeData != 0) {
            AlarmThread waitThread = new AlarmThread();
            waitThread.start();
        } else {
            Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
        }

        try {
            ActivityManager.getService().registerUidObserver(new UidObserver(),
                    ActivityManager.UID_OBSERVER_IDLE, ActivityManager.PROCESS_STATE_UNKNOWN, null);
        } catch (RemoteException e) {
            // ignored; both services live in system_server
        }

        publishBinderService(Context.ALARM_SERVICE, mService);
        publishLocalService(LocalService.class, new LocalService());
    }

在onStart()后,SYSTEM_SERVICES_READY时onBootPhase()将被回调。

    @Override
    public void onBootPhase(int phase) {
        if (phase == PHASE_SYSTEM_SERVICES_READY) {
            mConstants.start(getContext().getContentResolver());
            mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
            mLocalDeviceIdleController
                    = LocalServices.getService(DeviceIdleController.LocalService.class);
        }
    }

回到onStart(),分析native层init的调用,下面看native init()的实现。

frameworks/base/services/core/java/com/android/server/AlarmManagerService.java

private native long init();

frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp

static const JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
    {"init", "()J", (void*)android_server_AlarmManagerService_init},
    {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
    {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
    {"clear", "(JIJJ)V", (void*)android_server_AlarmManagerService_clear},
    {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
    {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
    {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
};

int register_android_server_AlarmManagerService(JNIEnv* env)
{
    return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
                                    sMethods, NELEM(sMethods));
}

register_android_server_AlarmManagerService中注册了native方法,init()即调用android_server_AlarmManagerService_init。

frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp

static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
{
    // 初始化/dev/alarm
    jlong ret = init_alarm_driver();
    if (ret) {
        return ret;
    }

    // 如果初始化/dev/alarm不成功,则进入timerfd初始化,现一般采用timerfd方式采用
    return init_timerfd();
}

Native Alarm初始化采用了二种方案,AlarmDriver与timerfd,当alarm_driver失败时则使用timerfd,现在基本使用的是timerfd。如下,AlarmImpl是Native层Alarm操作的统一接口,AlarmImplAlarmDriver与AlarmImplTimerFd是AlarmDriver与timerfd二种不同方式的具体实现。

class AlarmImpl
{
public:
    AlarmImpl(int *fds, size_t n_fds);
    virtual ~AlarmImpl();

    virtual int set(int type, struct timespec *ts) = 0;
    virtual int clear(int type, struct timespec *ts) = 0;
    virtual int setTime(struct timeval *tv) = 0;
    virtual int waitForAlarm() = 0;

protected:
    int *fds;
    size_t n_fds;
};

class AlarmImplAlarmDriver : public AlarmImpl
{
public:
    AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { }

    int set(int type, struct timespec *ts);
    int clear(int type, struct timespec *ts);
    int setTime(struct timeval *tv);
    int waitForAlarm();
};

class AlarmImplTimerFd : public AlarmImpl
{
public:
    AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd, int rtc_id) :
        AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd), rtc_id(rtc_id) { }
    ~AlarmImplTimerFd();

    int set(int type, struct timespec *ts);
    int clear(int type, struct timespec *ts);
    int setTime(struct timeval *tv);
    int waitForAlarm();

private:
    int epollfd;
    int rtc_id;
};

下面先看AlarmDriver的方式。

frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp

static jlong init_alarm_driver()
{
    // 打开/dev/alarm,失败则退出
    int fd = open("/dev/alarm", O_RDWR);
    if (fd < 0) {
        ALOGV("opening alarm driver failed: %s", strerror(errno));
        return 0;
    }

    // 根据fd创建AlarmImplAlarmDriver对象
    AlarmImpl *ret = new AlarmImplAlarmDriver(fd);
    return reinterpret_cast<jlong>(ret);
}

int AlarmImplAlarmDriver::set(int type, struct timespec *ts)
{
    return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);
}

int AlarmImplAlarmDriver::clear(int type, struct timespec *ts)
{
    return ioctl(fds[0], ANDROID_ALARM_CLEAR(type), ts);
}

int AlarmImplAlarmDriver::setTime(struct timeval *tv)
{
    struct timespec ts;
    int res;

    ts.tv_sec = tv->tv_sec;
    ts.tv_nsec = tv->tv_usec * 1000;
    res = ioctl(fds[0], ANDROID_ALARM_SET_RTC, &ts);
    if (res < 0)
        ALOGV("ANDROID_ALARM_SET_RTC ioctl failed: %s\n", strerror(errno));
    return res;
}

int AlarmImplAlarmDriver::waitForAlarm()
{
    return ioctl(fds[0], ANDROID_ALARM_WAIT);
}

AlarmImplAlarmDriver中主要通过ioctl来实现Alarm的操作。当init_alarm_driver打开/dev/alarm失败时,选择timerfd实现Alarm的操作。

frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp

static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1;
static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
    CLOCK_REALTIME_ALARM,
    CLOCK_REALTIME,
    CLOCK_BOOTTIME_ALARM,
    CLOCK_BOOTTIME,
    CLOCK_MONOTONIC,
    CLOCK_POWEROFF_ALARM,
    CLOCK_REALTIME,
};

static jlong init_timerfd()
{
    int epollfd;
    int fds[N_ANDROID_TIMERFDS];

    // 创建epoll句柄,监听N_ANDROID_TIMERFDS个文件描述符
    epollfd = epoll_create(N_ANDROID_TIMERFDS);
    if (epollfd < 0) {
        ALOGV("epoll_create(%zu) failed: %s", N_ANDROID_TIMERFDS,
                strerror(errno));
        return 0;
    }

    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
        // 创建定时器文件
        fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
        if (fds[i] < 0) {
            ALOGV("timerfd_create(%u) failed: %s",  android_alarm_to_clockid[i],
                    strerror(errno));
            close(epollfd);
            for (size_t j = 0; j < i; j++) {
                close(fds[j]);
            }
            return 0;
        }
    }

    // 根据fds创建AlarmImplTimerFd对象,AlarmImplTimerFd也继承于AlarmImpl
    AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd, wall_clock_rtc());

    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
        epoll_event event;
        event.events = EPOLLIN | EPOLLWAKEUP;
        event.data.u32 = i;

        // 将创建的定时器文件列表加入到epoll监听中
        int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event);
        if (err < 0) {
            ALOGV("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
            delete ret;
            return 0;
        }
    }

    struct itimerspec spec;
    memset(&spec, 0, sizeof(spec));

    int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
            TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
    if (err < 0) {
        ALOGV("timerfd_settime() failed: %s", strerror(errno));
        delete ret;
        return 0;
    }

    return reinterpret_cast<jlong>(ret);
}

init_timerfd()中利用epoll+timerfd的方式,创建timerfd文件并加入到epoll监听中,创建的定时器文件中,我们主要使用的是CLOCK_REALTIME_ALARM,CLOCK_BOOTTIME_ALARM,CLOCK_POWEROFF_ALARM,分别对应RTC_WAKEUP(RTC),ELAPSED_REALTIME_WAKEUP(ELAPSED_REALTIME),RTC_POWEROFF_WAKEUP。下面具体看一下AlarmImplTimerFd::set设置定时器的实现。
frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp

int AlarmImplTimerFd::set(int type, struct timespec *ts)
{
    if (type > ANDROID_ALARM_TYPE_COUNT) {
        errno = EINVAL;
        return -1;
    }

    if (!ts->tv_nsec && !ts->tv_sec) {
        ts->tv_nsec = 1;
    }
    /* timerfd interprets 0 = disarm, so replace with a practically
       equivalent deadline of 1 ns */

    struct itimerspec spec;
    memset(&spec, 0, sizeof(spec));
    memcpy(&spec.it_value, ts, sizeof(spec.it_value));

    // 直接调用timerfd_settime设置Alarm定时时间
    return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
}

在waitForAlarm中将等待Alarm的到来,下面看AlarmImplTimerFd::waitForAlarm的实现。

frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp

int AlarmImplTimerFd::waitForAlarm()
{
    epoll_event events[N_ANDROID_TIMERFDS];

    // 利用epolle_wait监听定时器的事件
    int nevents = epoll_wait(epollfd, events, N_ANDROID_TIMERFDS, -1);
    if (nevents < 0) {
        return nevents;
    }

    int result = 0;
    // 事件到来,循环读取定时器文件
    for (int i = 0; i < nevents; i++) {
        uint32_t alarm_idx = events[i].data.u32;
        uint64_t unused;
        ssize_t err = read(fds[alarm_idx], &unused, sizeof(unused));
        if (err < 0) {
            if (alarm_idx == ANDROID_ALARM_TYPE_COUNT && errno == ECANCELED) {
                // 时间改变
                result |= ANDROID_ALARM_TIME_CHANGE_MASK;
            } else {
                return err;
            }
        } else {
            // 设置result为触发的alarm_idx
            result |= (1 << alarm_idx);
        }
    }
    // 返回结果给AlarmManagerService
    return result;
}

waitForAlarm中一直在epoll_wait监听等待Alarm fd事件,当事件到来,循环读取定时器文件并向上层返回触发的Alarm index或时间改变事件。

至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

如有侵权,请联系小编,小编对此深感抱歉,届时小编会删除文章,立即停止侵权行为,请您多多包涵。

posted @ 2019-08-09 15:26  程序员Android  阅读(1315)  评论(0编辑  收藏  举报