日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android Alarm自上而下 调试浅析

發布時間:2023/12/20 Android 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android Alarm自上而下 调试浅析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.為了創建一個新的Alarm,使用set方法并指定一個Alarm類型、觸發時間和在Alarm觸發時要調用的Intent。如果你設定的Alarm發生在過去,那么,它將立即觸發。

這里有4種Alarm類型。你的選擇將決定你在set方法中傳遞的時間值代表什么,是特定的時間或者是時間流逝:

? RTC_WAKEUP

在指定的時刻(設置Alarm的時候),喚醒設備來觸發Intent。

? RTC

在一個顯式的時間觸發Intent,但不喚醒設備。

? ELAPSED_REALTIME

從設備啟動后,如果流逝的時間達到總時間,那么觸發Intent,但不喚醒設備。流逝的時間包括設備睡眠的任何時間。注意一點的是,時間流逝的計算點是自從它最后一次啟動算起。

? ELAPSED_REALTIME_WAKEUP

從設備啟動后,達到流逝的總時間后,如果需要將喚醒設備并觸發Intent。


2.Alarm 調用流程,alarm的流程實現了從上層應用一直到下面driver的調用流程,下面簡單闡述:

點擊Clock 應用程序,然后設置新鬧鐘,會調到? Alarms.java? 里面的

[cpp]?view plaincopy
  • public?static?long?setAlarm(Context?context,?Alarm?alarm)?{??
  • ????ContentValues?values?=?createContentValues(alarm);??
  • ????ContentResolver?resolver?=?context.getContentResolver();??
  • ????resolver.update(??
  • ????????????ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI,?alarm.id),??
  • ????????????values,?null,?null);??
  • ??
  • ????long?timeInMillis?=?calculateAlarm(alarm);??
  • ??
  • ????if?(alarm.enabled)?{??
  • ????????//?Disable?the?snooze?if?we?just?changed?the?snoozed?alarm.?This??
  • ????????//?only?does?work?if?the?snoozed?alarm?is?the?same?as?the?given??
  • ????????//?alarm.??
  • ????????//?TODO:?disableSnoozeAlert?should?have?a?better?name.??
  • ????????disableSnoozeAlert(context,?alarm.id);??
  • ??
  • ????????//?Disable?the?snooze?if?this?alarm?fires?before?the?snoozed?alarm.??
  • ????????//?This?works?on?every?alarm?since?the?user?most?likely?intends?to??
  • ????????//?have?the?modified?alarm?fire?next.??
  • ????????clearSnoozeIfNeeded(context,?timeInMillis);??
  • ????}??
  • ??
  • ????setNextAlert(context);??
  • ??
  • ????return?timeInMillis;??
  • }??

  • 然后這里面也會調用到

    [cpp]?view plaincopy
  • public?static?void?setNextAlert(final?Context?context)?{??
  • ????final?Alarm?alarm?=?calculateNextAlert(context);??
  • ????if?(alarm?!=?null)?{??
  • ????????enableAlert(context,?alarm,?alarm.time);??
  • ????}?else?{??
  • ????????disableAlert(context);??
  • ????}??
  • }??
  • calculateNextAlert(context);?? //new 一個新的alarm?
    然后繼續調用到

    ?? ? private static void enableAlert(Context context, final Alarm alarm,final long atTimeInMillis)

    其中am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);//這里是RTC_WAKEUP, 這就保證了即使系統睡眠了,都能喚醒,鬧鐘工作(android平臺關機鬧鐘好像不行)

    然后就調用到了AlarmManager.java 里面方法

    [cpp]?view plaincopy
  • public?void?set(int?type,?long?triggerAtTime,?PendingIntent?operation)?{??
  • ????try?{??
  • ????????mService.set(type,?triggerAtTime,?operation);??
  • ????}?catch?(RemoteException?ex)?{??
  • ????}??
  • }??

  • 然后就調用到了AlarmManagerService.java? 里面方法
    [cpp]?view plaincopy
  • public?void?set(int?type,?long?triggerAtTime,?PendingIntent?operation)?{??
  • ????????setRepeating(type,?triggerAtTime,?0,?operation);??
  • ????}??

  • 然后繼續調用
    [cpp]?view plaincopy
  • public?void?setRepeating(int?type,?long?triggerAtTime,?long?interval,???
  • ????????????PendingIntent?operation)?{??
  • .....??
  • synchronized?(mLock)?{??
  • ????????????Alarm?alarm?=?new?Alarm();??
  • ????????????alarm.type?=?type;??
  • ????????????alarm.when?=?triggerAtTime;??
  • ????????????alarm.repeatInterval?=?interval;??
  • ????????????alarm.operation?=?operation;??
  • ??
  • ????????????//?Remove?this?alarm?if?already?scheduled.??
  • ????????????removeLocked(operation);??
  • ??
  • ????????????if?(localLOGV)?Slog.v(TAG,?"set:?"?+?alarm);??
  • ??
  • ????????????int?index?=?addAlarmLocked(alarm);??
  • ????????????if?(index?==?0)?{??
  • ????????????????setLocked(alarm);??
  • ????????????}??
  • ????????}??
  • ????}??

  • 然后就調用到
    [cpp]?view plaincopy
  • private?void?setLocked(Alarm?alarm)??
  • ????{??
  • ????......??
  • ????set(mDescriptor,?alarm.type,?alarmSeconds,?alarmNanoseconds);???//mDescriptor??這里的文件是?/dev/alarm??
  • ????.....??
  • }??
  • 這里就調用到jni了
    private native void set(int fd, int type, long seconds, long nanoseconds);

    這就調用到了com_android_server_AlarmManagerService.cpp 里面
    [cpp]?view plaincopy
  • static?JNINativeMethod?sMethods[]?=?{??
  • ?????/*?name,?signature,?funcPtr?*/??
  • ????{"init",?"()I",?(void*)android_server_AlarmManagerService_init},??
  • ????{"close",?"(I)V",?(void*)android_server_AlarmManagerService_close},??
  • ????{"set",?"(IIJJ)V",?(void*)android_server_AlarmManagerService_set},??
  • ????{"waitForAlarm",?"(I)I",?(void*)android_server_AlarmManagerService_waitForAlarm},??
  • ????{"setKernelTimezone",?"(II)I",?(void*)android_server_AlarmManagerService_setKernelTimezone},??
  • };??
  • set 對應的是android_server_AlarmManagerService_set, 具體是
    [cpp]?view plaincopy
  • static?void?android_server_AlarmManagerService_set(JNIEnv*?env,?jobject?obj,?jint?fd,?jint?type,?jlong?seconds,?jlong?nanoseconds)??
  • {??
  • #if?HAVE_ANDROID_OS??
  • ????struct?timespec?ts;??
  • ????ts.tv_sec?=?seconds;??
  • ????ts.tv_nsec?=?nanoseconds;??
  • ??????
  • ????int?result?=?ioctl(fd,?ANDROID_ALARM_SET(type),?&ts);??
  • ????if?(result?<?0)??
  • ????{??
  • ????????LOGE("Unable?to?set?alarm?to?%lld.%09lld:?%s\n",?seconds,?nanoseconds,?strerror(errno));??
  • ????}??
  • #endif??
  • }??
  • 然后ioctl 就調用到了alarm-dev.c

    [cpp]?view plaincopy
  • static?long?alarm_ioctl(struct?file?*file,?unsigned?int?cmd,?unsigned?long?arg)??
  • {??
  • ????int?rv?=?0;??
  • ????unsigned?long?flags;??
  • ????struct?timespec?new_alarm_time;??
  • ????struct?timespec?new_rtc_time;??
  • ????struct?timespec?tmp_time;??
  • ????enum?android_alarm_type?alarm_type?=?ANDROID_ALARM_IOCTL_TO_TYPE(cmd);??
  • ????uint32_t?alarm_type_mask?=?1U?<<?alarm_type;??
  • ????printk(">>%s?cmd?==?%d\n",__FUNCTION__,cmd);??
  • ????if?(alarm_type?>=?ANDROID_ALARM_TYPE_COUNT)??
  • ????????return?-EINVAL;??
  • ??
  • ????if?(ANDROID_ALARM_BASE_CMD(cmd)?!=?ANDROID_ALARM_GET_TIME(0))?{??
  • ????????if?((file->f_flags?&?O_ACCMODE)?==?O_RDONLY)??
  • ????????????return?-EPERM;??
  • ????????if?(file->private_data?==?NULL?&&??
  • ????????????cmd?!=?ANDROID_ALARM_SET_RTC)?{??
  • ????????????spin_lock_irqsave(&alarm_slock,?flags);??
  • ????????????if?(alarm_opened)?{??
  • ????????????????spin_unlock_irqrestore(&alarm_slock,?flags);??
  • ????????????????return?-EBUSY;??
  • ????????????}??
  • ????????????alarm_opened?=?1;??
  • ????????????file->private_data?=?(void?*)1;??
  • ????????????spin_unlock_irqrestore(&alarm_slock,?flags);??
  • ????????}??
  • ????}??
  • ??
  • ????switch?(ANDROID_ALARM_BASE_CMD(cmd))?{??
  • ????case?ANDROID_ALARM_CLEAR(0):??
  • ????????spin_lock_irqsave(&alarm_slock,?flags);??
  • ????????pr_alarm(IO,?"alarm?%d?clear\n",?alarm_type);??
  • ????????alarm_try_to_cancel(&alarms[alarm_type]);??
  • ????????if?(alarm_pending)?{??
  • ????????????alarm_pending?&=?~alarm_type_mask;??
  • ????????????if?(!alarm_pending?&&?!wait_pending)??
  • ????????????????wake_unlock(&alarm_wake_lock);??
  • ????????}??
  • ????????alarm_enabled?&=?~alarm_type_mask;??
  • ????????spin_unlock_irqrestore(&alarm_slock,?flags);??
  • ????????break;??
  • ??
  • ????case?ANDROID_ALARM_SET_OLD:??
  • ????case?ANDROID_ALARM_SET_AND_WAIT_OLD:??
  • ????????if?(get_user(new_alarm_time.tv_sec,?(int?__user?*)arg))?{??
  • ????????????rv?=?-EFAULT;??
  • ????????????goto?err1;??
  • ????????}??
  • ????????new_alarm_time.tv_nsec?=?0;??
  • ????????goto?from_old_alarm_set;??
  • ??
  • ????case?ANDROID_ALARM_SET_AND_WAIT(0):??
  • ????case?ANDROID_ALARM_SET(0):??
  • ????????if?(copy_from_user(&new_alarm_time,?(void?__user?*)arg,??
  • ????????????sizeof(new_alarm_time)))?{??
  • ????????????rv?=?-EFAULT;??
  • ????????????goto?err1;??
  • ????????}??
  • from_old_alarm_set:??
  • ????????spin_lock_irqsave(&alarm_slock,?flags);??
  • ????????pr_alarm(IO,?"alarm?%d?set?%ld.%09ld\n",?alarm_type,??
  • ????????????new_alarm_time.tv_sec,?new_alarm_time.tv_nsec);??
  • ????????alarm_enabled?|=?alarm_type_mask;??
  • ????????alarm_start_range(&alarms[alarm_type],??
  • ????????????timespec_to_ktime(new_alarm_time),??
  • ????????????timespec_to_ktime(new_alarm_time));??
  • ????????spin_unlock_irqrestore(&alarm_slock,?flags);??
  • ????????if?(ANDROID_ALARM_BASE_CMD(cmd)?!=?ANDROID_ALARM_SET_AND_WAIT(0)??
  • ????????????&&?cmd?!=?ANDROID_ALARM_SET_AND_WAIT_OLD)??
  • ????????????break;??
  • ????????/*?fall?though?*/??
  • ????case?ANDROID_ALARM_WAIT:??
  • ????????spin_lock_irqsave(&alarm_slock,?flags);??
  • ????????pr_alarm(IO,?"alarm?wait\n");??
  • ????????if?(!alarm_pending?&&?wait_pending)?{??
  • ????????????wake_unlock(&alarm_wake_lock);??
  • ????????????wait_pending?=?0;??
  • ????????}??
  • ????????spin_unlock_irqrestore(&alarm_slock,?flags);??
  • ????????rv?=?wait_event_interruptible(alarm_wait_queue,?alarm_pending);??
  • ????????if?(rv)??
  • ????????????goto?err1;??
  • ????????spin_lock_irqsave(&alarm_slock,?flags);??
  • ????????rv?=?alarm_pending;??
  • ????????wait_pending?=?1;??
  • ????????alarm_pending?=?0;??
  • ????????spin_unlock_irqrestore(&alarm_slock,?flags);??
  • ????????break;??
  • ????case?ANDROID_ALARM_SET_RTC:??
  • ????????if?(copy_from_user(&new_rtc_time,?(void?__user?*)arg,??
  • ????????????sizeof(new_rtc_time)))?{??
  • ????????????rv?=?-EFAULT;??
  • ????????????goto?err1;??
  • ????????}??
  • ????????rv?=?alarm_set_rtc(new_rtc_time);??
  • ????????spin_lock_irqsave(&alarm_slock,?flags);??
  • ????????alarm_pending?|=?ANDROID_ALARM_TIME_CHANGE_MASK;??
  • ????????wake_up(&alarm_wait_queue);??
  • ????????spin_unlock_irqrestore(&alarm_slock,?flags);??
  • ????????if?(rv?<?0)??
  • ????????????goto?err1;??
  • ????????break;??
  • ????case?ANDROID_ALARM_GET_TIME(0):??
  • ????????switch?(alarm_type)?{??
  • ????????case?ANDROID_ALARM_RTC_WAKEUP:??
  • ????????case?ANDROID_ALARM_RTC:??
  • ????????????getnstimeofday(&tmp_time);??
  • ????????????break;??
  • ????????case?ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:??
  • ????????case?ANDROID_ALARM_ELAPSED_REALTIME:??
  • ????????????tmp_time?=??
  • ????????????????ktime_to_timespec(alarm_get_elapsed_realtime());??
  • ????????????break;??
  • ????????case?ANDROID_ALARM_TYPE_COUNT:??
  • ????????case?ANDROID_ALARM_SYSTEMTIME:??
  • ????????????ktime_get_ts(&tmp_time);??
  • ????????????break;??
  • ????????}??
  • ????????if?(copy_to_user((void?__user?*)arg,?&tmp_time,??
  • ????????????sizeof(tmp_time)))?{??
  • ????????????rv?=?-EFAULT;??
  • ????????????goto?err1;??
  • ????????}??
  • ????????break;??
  • ??
  • ????default:??
  • ????????rv?=?-EINVAL;??
  • ????????goto?err1;??
  • ????}??
  • err1:??
  • ????return?rv;??
  • }??

  • alarm.c? 里面實現了 alarm_suspend? alarm_resume 函數
    就是如果系統沒有suspend的時候,設置鬧鐘并不會往rtc 芯片的寄存器上寫數據,因為不需要喚醒系統,所以鬧鐘數據時間什么的就通過上層寫到設備文件/dev/alarm
    里面就可以了,AlarmThread 會不停的去輪尋下一個時間有沒有鬧鐘,直接從設備文件 /dev/alarm 里面讀取
    第二種,系統要是進入susupend的話,alarm 的alarm_suspend? 就會寫到下層的rtc芯片的寄存器上去, 然后即使系統suspend之后,鬧鐘通過rtc 也能喚醒系統。

    這里就調用到了interface.c 里面?? //這里面 int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 差不多 也是跟下面一樣

    [cpp]?view plaincopy
  • int?rtc_set_time(struct?rtc_device?*rtc,?struct?rtc_time?*tm)??
  • {??
  • ....??
  • ????err?=?rtc->ops->set_time(rtc->dev.parent,?tm);??
  • ....??
  • }??

  • 然后set_time 就看到具體的是那個RTC芯片,這邊我們是rtc-hym8563.c
    然后就到了
    [cpp]?view plaincopy
  • static?int?hym8563_i2c_set_regs(struct?i2c_client?*client,?u8?reg,?u8?const?buf[],?__u16?len)??
  • {??
  • ????int?ret;???
  • ????ret?=?i2c_master_reg8_send(client,?reg,?buf,?(int)len,?RTC_SPEED);??
  • ????return?ret;??
  • }??

  • 到此,鬧鐘時間就已經寫到rtc 芯片的寄存器里面,第二個參數就是寄存器的名字,后面的buf就是要寫入的時間,rtc芯片是額外供電的,所以系統suspend之后,系統kernel都關了,但是rtc里面還有電,寄存器里面數據還是有的(掉電就會丟失數據),所以鬧鐘到了,通過硬件中斷機制就可以喚醒系統。

    3.下面是系統喚醒之后,鬧鐘怎么工作的流程,簡單闡述

    [cpp]?view plaincopy
  • ?private?class?AlarmThread?extends?Thread??
  • ????{??
  • ????????public?AlarmThread()??
  • ????????{??
  • ????????????super("AlarmManager");??
  • ????????}??
  • ??????????
  • ????????public?void?run()??
  • ????????{???
  • ????????while?(true)??
  • ????????????{??
  • ????????int?result?=?waitForAlarm(mDescriptor);?//這里調用jni調用static?jint?android_server_AlarmManagerService_waitForAlarm,主要還是對?/dev/alarm??操作??
  • ????????....??
  • ????????Alarm?alarm?=?it.next();??
  • ????????????????????????try?{??
  • ????????????????????????????if?(localLOGV)?Slog.v(TAG,?"sending?alarm?"?+?alarm);??
  • ????????????????????????????alarm.operation.send(mContext,?0,??
  • ????????????????????????????????????mBackgroundIntent.putExtra(??
  • ????????????????????????????????????????????Intent.EXTRA_ALARM_COUNT,?alarm.count),??
  • ????????????????????????????????????mResultReceiver,?mHandler);??
  • ????????....??
  • ????????}??
  • ??
  • ????}??
  • ??????}??
  • ??
  • ??
  • static?jint?android_server_AlarmManagerService_waitForAlarm(JNIEnv*?env,?jobject?obj,?jint?fd)??
  • {??
  • #if?HAVE_ANDROID_OS??
  • ????int?result?=?0;??
  • ??????
  • ????do??
  • ????{??
  • ????????result?=?ioctl(fd,?ANDROID_ALARM_WAIT);??
  • ????}?while?(result?<?0?&&?errno?==?EINTR);??
  • ??????
  • ????if?(result?<?0)??
  • ????{??
  • ????????LOGE("Unable?to?wait?on?alarm:?%s\n",?strerror(errno));??
  • ????????return?0;??
  • ????}??
  • ??????
  • ????return?result;??
  • #endif??
  • }??
  • 系統沒有suspend的話直接走下面流程,如果suspend的話會被RTC喚醒,然后還是走下面的流程
    AlarmManagerService? 里面有個AlarmThread? 會一直輪詢 /dev/alarm文件,如果打開失敗就直接返回,成功就會做一些動作,比如查找時間最近的
    alarm,比如睡眠被鬧鐘喚醒的時候,這邊就發一個intent出去,然后在AlarmReceiver.java里面彈出里面會收到就會調用下面的
    ?? ??? ?context.startActivity(alarmAlert);
    然后彈出alarm? 這個界面
    ??????? Class c = AlarmAlert.class;
    其中public class AlarmAlert extends AlarmAlertFullScreen? 所以系統睡眠之后被alarm喚醒彈出的alarm就是這邊start的

    [cpp]?view plaincopy
  • public?class?AlarmReceiver?extends?BroadcastReceiver?{??
  • ??
  • ????/**?If?the?alarm?is?older?than?STALE_WINDOW,?ignore.??It?
  • ????????is?probably?the?result?of?a?time?or?timezone?change?*/??
  • ????private?final?static?int?STALE_WINDOW?=?30?*?60?*?1000;??
  • ??
  • ????@Override??
  • ????public?void?onReceive(Context?context,?Intent?intent)?{??
  • ????.........??
  • ????????Intent?alarmAlert?=?new?Intent(context,?c);??
  • ????????alarmAlert.putExtra(Alarms.ALARM_INTENT_EXTRA,?alarm);??
  • ????????alarmAlert.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK??
  • ????????????????|?Intent.FLAG_ACTIVITY_NO_USER_ACTION);??
  • ????????context.startActivity(alarmAlert);??
  • ????........??
  • }??

  • 到這里alarm 就顯示出來了

    總結

    以上是生活随笔為你收集整理的Android Alarm自上而下 调试浅析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。