alarm实现原理

AlarmManager
直接上试用案例,AlarmManager.INTERVAL_DAY时间后触发相关Service:

Intent i = new Intent(EntitlementService.this, EntitlementService.class);
            i.setAction(ACTION_ENTITLEMENT_CHECK);
            i.putExtra("service", service);
            PendingIntent pi = PendingIntent.getService(EntitlementService.this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
            AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
            am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + AlarmManager.INTERVAL_DAY, AlarmManager.INTERVAL_DAY, pi);


    * @param type type of alarm.
     * @param triggerAtMillis time in milliseconds that the alarm should first
     * go off, using the appropriate clock (depending on the alarm type).
     * @param intervalMillis interval in milliseconds between subsequent repeats
     * of the alarm.
     * @param operation Action to perform when the alarm goes off;
     * typically comes from {@link PendingIntent#getBroadcast
     * IntentSender.getBroadcast()}.
   
   public void setRepeating(@AlarmType int type, long triggerAtMillis,
            long intervalMillis, PendingIntent operation) {
        setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, 0, operation,
                null, null, null, null, null);
    }
    

我们看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) {
                ...
                try {
            mService.set(mPackageName, type, triggerAtMillis, windowMillis, intervalMillis, flags,
                    operation, recipientWrapper, listenerTag, workSource, alarmClock);
       		 } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
       		 }
        }

其实是调用了mService的set方法,mService是IAlarmManager的对象,看名字就可以知道,这里是一个代理类,具体的实现实在AlarmManagerService里面

private final IBinder mService = new IAlarmManager.Stub() {
        @Override
        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) {
                    ...
                    setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver,
                    listenerTag, flags, workSource, alarmClock, callingUid, callingPackage);
                }

 

继续展开setImpl:

void setImpl(int type, long triggerAtTime, long windowLength, long interval,
            PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
            int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
            int callingUid, String callingPackage) {
                ...
                setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
                    interval, operation, directReceiver, listenerTag, flags, true, workSource,
                    alarmClock, callingUid, callingPackage,needAlarmGrouping());
            }

setImplLocked这个方法会更新AlarmManagerService中的list,该list保存的是整个系统中所有的alarm。
然后调用rescheduleKernelAlarmsLocked-->setLocked

    private void setLocked(int type, long when) {
        if (mNativeData != 0 && mNativeData != -1) {
            // The kernel never triggers alarms with negative wakeup times
            // so we ensure they are positive.
            long alarmSeconds, alarmNanoseconds;
            if (when < 0) {
                alarmSeconds = 0;
                alarmNanoseconds = 0;
            } else {
                alarmSeconds = when / 1000;
                alarmNanoseconds = (when % 1000) * 1000 * 1000;
            }
            
            set(mNativeData, type, alarmSeconds, alarmNanoseconds);
        } else {
            Message msg = Message.obtain();
            msg.what = ALARM_EVENT;
            
            mHandler.removeMessages(ALARM_EVENT);
            mHandler.sendMessageAtTime(msg, when);
        }
    }

我们看驱动支持的情况,也就是走:
set(mNativeData, type, alarmSeconds, alarmNanoseconds);
protected native void set(long nativeData, int type, long seconds, long nanoseconds);
方法实现在
frameworks\base\services\core\jni\com_android_server_AlarmManagerService.cpp

static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
{
    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
    struct timespec ts;
    ts.tv_sec = seconds;
    ts.tv_nsec = nanoseconds;

    int result = impl->set(type, &ts);
    if (result < 0)
    {
        ALOGE("Unable to set alarm to %lld.%09lld: %s\n",
              static_cast<long long>(seconds),
              static_cast<long long>(nanoseconds), strerror(errno));
    }
}

AlarmImpl的set方法的实现在AlarmImplAlarmDriver中,先看init方法:

static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
{
    jlong ret = init_alarm_driver();
    if (ret) {
        return ret;
    }

    return init_timerfd();
}

这里驱动支持,走的是init_alarm_driver:

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<jlong>(ret);
}

可以知道如果驱动支持,会在dev目录下面生产一个alarm的节点,在初始化alarm系统的时候fd就不会<0,所以来看看AlarmImplAlarmDriver的set方法:

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

通过ioctl的方式将时间设置给驱动,等到硬件中断返回后,再回调到native层,native再回调到framework。

AlarmManagerService

@Override
    public void onStart() {
        //这里的init就是读的驱动节点open("/dev/alarm", O_RDWR);
        mNativeData = init();
        ...
        if (mNativeData != 0) {
            AlarmThread waitThread = new AlarmThread();
            waitThread.start();
        }
        ...
    }

这里驱动支持的话,起了一个线程:

private class AlarmThread extends Thread
    {
        public AlarmThread()
        {
            super("AlarmManager");
        }

        public void run()
        {
            ArrayList<Alarm> triggerList = new ArrayList<Alarm>();

            while (true)
            {
                int result = waitForAlarm(mNativeData);
                ...
            }
        }
    }

可以看到这里一直的死循环,等待驱动的返回。

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

framework回调

void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) {
    ...
    mDeliveryTracker.deliverLocked(alarm, nowELAPSED, allowWhileIdle);
    ...
}

public void deliverLocked(Alarm alarm, long nowELAPSED, boolean allowWhileIdle) {
    ...
    alarm.operation.send(getContext(), 0,
                            mBackgroundIntent.putExtra(
                                    Intent.EXTRA_ALARM_COUNT, alarm.count),
                                    mDeliveryTracker, mHandler, null,
                                    allowWhileIdle ? mIdleOptions : null);
    ...
}

这里的operation是PendingIntent对象,最后回调其实是PendingIntent的send方法

public void send(Context context, int code, @Nullable Intent intent,
            @Nullable OnFinished onFinished, @Nullable Handler handler,
            @Nullable String requiredPermission, @Nullable Bundle options)
            throws CanceledException {
        try {
            String resolvedType = intent != null ?
                    intent.resolveTypeIfNeeded(context.getContentResolver())
                    : null;
            int res = ActivityManager.getService().sendIntentSender(
                    mTarget, mWhitelistToken, code, intent, resolvedType,
                    onFinished != null
                            ? new FinishedDispatcher(this, onFinished, handler)
                            : null,
                    requiredPermission, options);
            if (res < 0) {
                throw new CanceledException();
            }
        } catch (RemoteException e) {
            throw new CanceledException(e);
        }
    }

这里的mTarget就是驱动回调的起点IIntentSender mTarget,而sendIntentSender的实现便在AMS中:

    public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code,
            Intent intent, String resolvedType,
            IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
        if (target instanceof PendingIntentRecord) {
            return ((PendingIntentRecord)target).sendWithResult(code, intent, resolvedType,
                    whitelistToken, finishedReceiver, requiredPermission, options);
        } else {
            if (intent == null) {
                // Weird case: someone has given us their own custom IIntentSender, and now
                // they have someone else trying to send to it but of course this isn't
                // really a PendingIntent, so there is no base Intent, and the caller isn't
                // supplying an Intent... but we never want to dispatch a null Intent to
                // a receiver, so um...  let's make something up.
                Slog.wtf(TAG, "Can't use null intent with direct IIntentSender call");
                intent = new Intent(Intent.ACTION_MAIN);
            }
            try {
                target.send(code, intent, resolvedType, whitelistToken, null,
                        requiredPermission, options);
            } catch (RemoteException e) {
            }
            // Platform code can rely on getting a result back when the send is done, but if
            // this intent sender is from outside of the system we can't rely on it doing that.
            // So instead we don't give it the result receiver, and instead just directly
            // report the finish immediately.
            if (finishedReceiver != null) {
                try {
                    finishedReceiver.performReceive(intent, 0,
                            null, null, false, false, UserHandle.getCallingUserId());
                } catch (RemoteException e) {
                }
            }
            return 0;
        }
    }

最终回调到frameworks\base\services\core\java\com\android\server\am\PendingIntentRecord.java
中的

int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken,
            IIntentReceiver finishedReceiver,
            String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
            int flagsMask, int flagsValues, Bundle options) {
                    ...
                    switch (key.type) {
                    case ActivityManager.INTENT_SENDER_ACTIVITY:
                        ...
                        break;
                    case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
                        ...
                        break;
                    case ActivityManager.INTENT_SENDER_BROADCAST:
                        ...
                        break;
                    case ActivityManager.INTENT_SENDER_SERVICE:
                    case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
                        ...
                        break;
                    ...
            }

最后根据不同的类型调用ams的方法启动Broadcast / Activity / Service

Android WakeLock
WakeLock levelAndFlags和使用场景

Level保持CPU保持屏幕常亮保持键盘灯常亮使用场景
PARTIAL_WAKE_LOCK长时间运行的后台服务,例如Service等
SCREEN_DIM_WAKE_LOCK低亮度除非必须保持CPU运行直至运算完成,否则请使用FLAG_KEEP_SCREEN_ON方式
SCREEN_BRIGHT_WAKE_LOCK高亮度除非必须保持CPU运行直至运算完成,否则请使用FLAG_KEEP_SCREEN_ON方式
FULL_WAKE_LOCK高亮度除非必须保持CPU运行直至运算完成,否则请使用FLAG_KEEP_SCREEN_ON方式

除了这四个Level之外,PowerMager还提供了两个Flag,可以配合Level使用

FLAG描述
ACQUIRE_CAUSES_WAKEUP典型的应用就是在收到一个重要的notifications时,需要马上点亮屏幕。
ON_AFTER_RELEASE当wake lock被释放的时候,当前调用wake lock的activity的计数器会被重置,所以屏幕会继续亮一段时间

使用方法:

    public void acquireWakeLock() {
        if (mWakeLock == null) {
            PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "XXX");
            if (mWakeLock != null) {
                mWakeLock.acquire();
            }
        }
    }

    public void releaseWakeLock() {
        if (mWakeLock != null) {
            mWakeLock.release();
        }
    }

WakeLock源码
frameworks\base\core\java\android\os\PowerManager.java

    public WakeLock newWakeLock(int levelAndFlags, String tag) {
        validateWakeLockParameters(levelAndFlags, tag);
        return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
    }

    /** @hide */
    public static void validateWakeLockParameters(int levelAndFlags, String tag) {
        switch (levelAndFlags & WAKE_LOCK_LEVEL_MASK) {
            case PARTIAL_WAKE_LOCK:
            case SCREEN_DIM_WAKE_LOCK:
            case SCREEN_BRIGHT_WAKE_LOCK:
            case FULL_WAKE_LOCK:
            case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
            case DOZE_WAKE_LOCK:
            case DRAW_WAKE_LOCK:
                break;
            default:
                throw new IllegalArgumentException("Must specify a valid wake lock level.");
        }
        if (tag == null) {
            throw new IllegalArgumentException("The tag must not be null.");
        }
    }

继续看构造函数:

WakeLock(int flags, String tag, String packageName) {
            mFlags = flags;
            mTag = tag;
            mPackageName = packageName;
            mToken = new Binder();
            mTraceName = "WakeLock (" + mTag + ")";
        }
        
        public void acquire() {
            synchronized (mToken) {
                acquireLocked();
            }
        }
        
        private void acquireLocked() {
            mInternalCount++;
            mExternalCount++;
            if (!mRefCounted || mInternalCount == 1) {
                // Do this even if the wake lock is already thought to be held (mHeld == true)
                // because non-reference counted wake locks are not always properly released.
                // For example, the keyguard's wake lock might be forcibly released by the
                // power manager without the keyguard knowing.  A subsequent call to acquire
                // should immediately acquire the wake lock once again despite never having
                // been explicitly released by the keyguard.
                mHandler.removeCallbacks(mReleaser);
                Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
                try {
                    mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
                            mHistoryTag);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
                mHeld = true;
            }
        }

mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
mHistoryTag);
实现在
frameworks/base/services/java/com/android/server/power/PowerManagerService.java
acquireWakeLock -> acquireWakeLockInternal -> updatePowerStateLocked -> updateSuspendBlockerLocked -> acquire -> nativeAcquireSuspendBlocker
到此调用利用JNI调用native代码
private static native void nativeAcquireSuspendBlocker(String name);
实现在:
frameworks\base\services\core\jni\com_android_server_power_PowerManagerService.cpp
static void nativeAcquireSuspendBlocker(JNIEnv env, jclass / clazz */, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}
这个acquire_wake_lock是在/hardware/libhardware_legacy/power/power.c里定义的

int
acquire_wake_lock(int lock, const char* id)
{
    initialize_fds();

//    ALOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id);

    if (g_error) return g_error;

    int fd;
    size_t len;
    ssize_t ret;

    if (lock != PARTIAL_WAKE_LOCK) {
        return -EINVAL;
    }

    fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];

    ret = write(fd, id, strlen(id));
    if (ret < 0) {
        return -errno;
    }

    return ret;
}

const char * const NEW_PATHS[] = {
"/sys/power/wake_lock",
"/sys/power/wake_unlock",
};
fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];将相关锁写入到文件界面,
剩下的便是驱动的实现了,这里不讨论。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
`timerfd` 是 Linux 内核提供的一种定时器机制,可以用于在用户空间中创建定时器。当定时器超时时,内核会向相应的文件描述符写入数据,从而通知用户空间程序。下面简要介绍一下 `timerfd` 的实现原理: `timerfd` 实际上是通过创建一个文件描述符,然后使用 `timer_create` 系统调用创建一个内核定时器来实现的。该系统调用的参数包括定时器的类型、超时时间、定时器的回调函数等等。当定时器超时时,内核会向文件描述符写入数据,用户空间程序可以通过 `read` 系统调用来读取这些数据,从而得知定时器已经超时。 `rtc_alarm` 是 Linux 内核中的另一种定时器机制,它可以用于在硬件级别上触发定时器事件。具体来说,它是通过设置硬件时钟中的闹钟时间来实现定时器功能的。当闹钟时间到达时,硬件时钟会触发一个中断信号,内核会在中断处理函数中执行相应的操作。 `rtc_alarm` 与 `timerfd` 的主要区别在于实现方式不同。`rtc_alarm` 是由硬件时钟实现的,因此可以在系统处于低功耗模式时正常工作;而 `timerfd` 则是由内核软件实现的,需要系统处于运行状态才能正常工作。另外,`rtc_alarm` 通常用于实现系统级别的定时器功能,例如唤醒系统、执行定时任务等等;而 `timerfd` 主要用于应用程序级别的定时器功能,例如定时发送数据、定时执行任务等等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值