alarm实现原理

19 篇文章 0 订阅

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];将相关锁写入到文件界面,
剩下的便是驱动的实现了,这里不讨论。
————————————————
版权声明:本文为CSDN博主「AK_Coffee」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chi_wy/article/details/83503019

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值