@Overridepublicvoidset(inttype,longtriggerAtTime,longwindowLength,longinterval,PendingIntentoperation,WorkSourceworkSource){if(workSource!=null){mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,"AlarmManager.set");}set(type,triggerAtTime,windowLength,interval,operation,false,workSource);}->publicvoidset(inttype,longtriggerAtTime,longwindowLength,longinterval,PendingIntentoperation,booleanisStandalone,WorkSourceworkSource){...setImplLocked(type,triggerAtTime,triggerElapsed,windowLength,maxElapsed,interval,operation,isStandalone,true,workSource);}->privatevoidsetImplLocked(inttype,longwhen,longwhenElapsed,longwindowLength,longmaxWhen,longinterval,PendingIntentoperation,booleanisStandalone,booleandoValidate,WorkSourceworkSource){...rescheduleKernelAlarmsLocked();}->privatevoidrescheduleKernelAlarmsLocked(){// Schedule the next upcoming wakeup alarm. If there is a deliverable batch// prior to that which contains no wakeups, we schedule that as well.if(mAlarmBatches.size()>0){finalBatchfirstWakeup=findFirstWakeupBatchLocked();finalBatchfirstBatch=mAlarmBatches.get(0);if(firstWakeup!=null&&mNextWakeup!=firstWakeup.start){mNextWakeup=firstWakeup.start;setLocked(ELAPSED_REALTIME_WAKEUP,firstWakeup.start);}if(firstBatch!=firstWakeup&&mNextNonWakeup!=firstBatch.start){mNextNonWakeup=firstBatch.start;setLocked(ELAPSED_REALTIME,firstBatch.start);}}}->privatevoidsetLocked(inttype,longwhen){if(mDescriptor!=-1){// The kernel never triggers alarms with negative wakeup times// so we ensure they are positive.longalarmSeconds,alarmNanoseconds;if(when<0){alarmSeconds=0;alarmNanoseconds=0;}else{alarmSeconds=when/1000;alarmNanoseconds=(when%1000)*1000*1000;}set(mDescriptor,type,alarmSeconds,alarmNanoseconds);}->privatenativevoidset(intfd,inttype,longseconds,longnanoseconds);
staticvoidandroid_server_AlarmManagerService_set(JNIEnv*env,jobjectobj,jintfd,jinttype,jlongseconds,jlongnanoseconds){structtimespects;ts.tv_sec=seconds;ts.tv_nsec=nanoseconds;intresult=ioctl(fd,ANDROID_ALARM_SET(type),&ts);if(result<0){ALOGE("Unable to set alarm to %lld.%09lld: %s\n",seconds,nanoseconds,strerror(errno));}}
privatefinalAlarmThreadmWaitThread=newAlarmThread();publicAlarmManagerService(Contextcontext){...if(mDescriptor!=-1){mWaitThread.start();}else{Slog.w(TAG,"Failed to open alarm driver. Falling back to a handler.");}}
/** * Broadcast Action: The current time has changed. Sent every * minute. You can <em>not</em> receive this through components declared * in manifests, only by explicitly registering for it with * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) * Context.registerReceiver()}. * * <p class="note">This is a protected intent that can only be sent * by the system. */@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)publicstaticfinalStringACTION_TIME_TICK="android.intent.action.TIME_TICK";
publicAlarmManagerService(Contextcontext){...mTimeTickSender=PendingIntent.getBroadcastAsUser(context,0,newIntent(Intent.ACTION_TIME_TICK).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY|Intent.FLAG_RECEIVER_FOREGROUND),0,UserHandle.ALL);// now that we have initied the driver schedule the alarmmClockReceiver=newClockReceiver();mClockReceiver.scheduleTimeTickEvent();...}classClockReceiverextendsBroadcastReceiver{publicClockReceiver(){IntentFilterfilter=newIntentFilter();filter.addAction(Intent.ACTION_TIME_TICK);filter.addAction(Intent.ACTION_DATE_CHANGED);mContext.registerReceiver(this,filter);}publicvoidonReceive(Contextcontext,Intentintent){if(intent.getAction().equals(Intent.ACTION_TIME_TICK)){scheduleTimeTickEvent();}publicvoidscheduleTimeTickEvent(){finallongcurrentTime=System.currentTimeMillis();finallongnextTime=60000*((currentTime/60000)+1);// Schedule this event for the amount of time that it would take to get to// the top of the next minute.finallongtickEventDelay=nextTime-currentTime;finalWorkSourceworkSource=null;// Let system take blame for time tick events.set(ELAPSED_REALTIME,SystemClock.elapsedRealtime()+tickEventDelay,0,0,mTimeTickSender,true,workSource);}}
protectedvoidonAttachedToWindow(){...// tick the secondspost(mClockTick);...}privatefinalRunnablemClockTick=newRunnable(){@Overridepublicvoidrun(){onTimeChanged();invalidate();AnalogClock.this.postDelayed(mClockTick,1000);}};
在创建的时候 post 一个 Runnable, 在 Runnable 中的 run 方法中 又设定了在一秒钟之后,再 post 这个 Runnable。这样每秒钟都会执行 Runnable 一次,进行重新绘制。
/** * Returns the current time in milliseconds since January 1, 1970 00:00:00.0 UTC. * * <p>This method always returns UTC times, regardless of the system's time zone. * This is often called "Unix time" or "epoch time". * Use a {@link java.text.DateFormat} instance to format this time for display to a human. * * <p>This method shouldn't be used for measuring timeouts or * other elapsed time measurements, as changing the system time can affect * the results. Use {@link #nanoTime} for that. */publicstaticnativelongcurrentTimeMillis();
GETTIMEOFDAY(2)LinuxProgrammer'sManualGETTIMEOFDAY(2)NAMEgettimeofday,settimeofday-get/settimeSYNOPSIS#include<sys/time.h>intgettimeofday(structtimeval*tv,structtimezone*tz);intsettimeofday(conststructtimeval*tv,conststructtimezone*tz);FeatureTestMacroRequirementsforglibc(seefeature_test_macros(7)):settimeofday():_BSD_SOURCEDESCRIPTIONThefunctionsgettimeofday()andsettimeofday()cangetandsetthetimeaswellasatimezone.Thetvargumentisastructtimeval(asspecifiedin<sys/time.h>):structtimeval{time_ttv_sec;/* seconds */suseconds_ttv_usec;/* microseconds */};andgivesthenumberofsecondsandmicrosecondssincetheEpoch(seetime(2)).Thetzargumentisastructtimezone:structtimezone{inttz_minuteswest;/* minutes west of Greenwich */inttz_dsttime;/* type of DST correction */};IfeithertvortzisNULL,thecorrespondingstructureisnotsetorreturned.
/* * native public static long elapsedRealtime(); */staticjlongandroid_os_SystemClock_elapsedRealtime(JNIEnv*env,jobjectclazz){return(jlong)elapsedRealtime();}
/* * native public static long elapsedRealtime(); */int64_telapsedRealtime(){returnnanoseconds_to_milliseconds(elapsedRealtimeNano());}->/* * native public static long elapsedRealtimeNano(); */int64_telapsedRealtimeNano(){...staticints_fd=-1;if(s_fd==-1){intfd=open("/dev/alarm",O_RDONLY);if(android_atomic_cmpxchg(-1,fd,&s_fd)){close(fd);}}result=ioctl(s_fd,ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME),&ts);if(result==0){timestamp=seconds_to_nanoseconds(ts.tv_sec)+ts.tv_nsec;checkTimeStamps(timestamp,&prevTimestamp,&prevMethod,METHOD_IOCTL);returntimestamp;}...}
AlarmManagerService 调用了 SystemClock 的 api setCurrentTimeMillis.
SystemClock.java
1234567
/** * Sets the current wall time, in milliseconds. Requires the calling * process to have appropriate permissions. * * @return if the clock was successfully set to the specified time. */nativepublicstaticbooleansetCurrentTimeMillis(longmillis);
SystemClock.java 调用了 native 方法
android_os_SystemClock.cpp
123456789101112
/* * Set the current time. This only works when running as root. */staticintsetCurrentTimeMillis(int64_tmillis){...fd=open("/dev/alarm",O_RDWR);...res=ioctl(fd,ANDROID_ALARM_SET_RTC,&ts);...}