Android Framework 框架系列之 AlarmManagerService(一)

640?wx_fmt=gif

640?wx_fmt=gif

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

640?wx_fmt=jpeg

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

1.AlarmManager的使用

本文转自网络地址如下:
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:

Context.getSystemService(Context.ALARM_SERVICE);
  1. Alarm的类型:

  • AlarmManager.RTC_WAKEUP

  • AlarmManager.RTC

  • AlarmManager.ELAPSED_REALTIME_WAKEUP

  • AlarmManager.ELAPSED_REALTIME

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

  1. Alarm的Flag:

  • FLAG_STANDALONE

  • FLAG_WAKE_FROM_IDLE

  • FLAG_ALLOW_WHILE_IDLE

  • FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED

  • FLAG_IDLE_UNTIL

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.javaprivate 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或时间改变事件。

640?wx_fmt=jpeg

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

640?wx_fmt=jpeg

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

640?wx_fmt=jpeg

posted @ 2018-12-16 08:57  程序员Android的博客  阅读(154)  评论(0编辑  收藏  举报