版權說明:本文為 開開向前沖 原創(chuàng)文章萍虽,轉載請注明出處轴脐;
注:限于作者水平有限,文中有不對的地方還請指教
項目需求:AP需要在開機24小時后自檢重啟砾嫉;
針對上述需求幼苛,我們首先想想有哪些實現(xiàn)方法呢?
- 1:開機接收廣播焕刮,啟動一個常駐服務舶沿,在服務中輪訓。輪訓的方式可以通過Handler或者啟動一個常駐服務配并,在服務中開啟線程中做死循環(huán)括荡;
- 2:使用Timer 來定時操作;
- 3:使用AlarmManager 來實現(xiàn)定時操作功能溉旋;
上述三個方法看似都可行畸冲;實際上只有最后一種可行,前兩種都是不可行的,為什么不可行呢召夹?
一:服務輪訓:Handler發(fā)送消息岩喷,消息的發(fā)送依賴于Handler 線程,如果線程結束监憎,GG!那開啟一個常駐服務呢婶溯,在服務中開啟一個線程做死循環(huán)鲸阔,我們先不說省電問題,如果系統(tǒng)進入深度睡眠迄委,即使這個while(1)的循環(huán)也不能得到執(zhí)行褐筛;
二:Timer:Timer的問題也是在于如果系統(tǒng)進入深度睡眠杰刽,將無法喚醒焙格;
所以只有AlarmManager∝参剩可以通過AlarmManager定時喚醒系統(tǒng)執(zhí)行任務信轿,即使系統(tǒng)處于深度睡眠也能喚醒——這就和我們的鬧鐘差不多晃痴;也能省電;那使用AlarmManager如果做呢财忽?
代碼敬上:
AlarmManager aManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent in = new Intent();
in.setClass(context, RebootService.class);
PendingIntent pi = PendingIntent.getService(context, 0, in, 0);
aManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,24 * 60 * 60 * 1000, pi);
沒錯倘核,AlarmManager的使用就是這個簡單,在開機后24小時系統(tǒng)將會啟動RebootService即彪,RebootService是我自己實現(xiàn)的一個服務紧唱,在這個服務中任意Lifecycle中實現(xiàn)關機操作就OK;
PowerManager pm = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
pm.reboot("self-inspection");
AlarmManager不僅可以喚醒服務隶校,也可以發(fā)送廣播漏益,也可以調起Activity;需要將上述PendingIntent.getService()修改成對應的PendingIntent.getActivity()或者PendingIntent.getBroadcast()方法深胳;
因為之前有維護過原生Clock APP绰疤,對AlarmManager有了解,正好借此機會完整機會闡述一下AlarmManager稠屠;
AlarmManager 對象獲嚷退:
AlarmManager aManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
AlarmManager 常用接口:
- set(int type, long triggerAtMillis, PendingIntent operation)
一次性任務; - setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
重復任務权埠;時間固定榨了; - setInexactRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
重復任務,時間不固定攘蔽; - cancel(PendingIntent operation)
取消上述設置的定時任務龙屉;此時PendingIntent務必和需要取消的任務的PendingIntent一模一樣;
這里主要介紹了幾個常用于定時任務的接口;關于AlarmManager 的接口和用法转捕,
可以參考Google官方API文檔AlarmManager 文檔作岖;
接口參數(shù)詳解:
- int type
AlarmManager.RTC:硬件時間,不喚醒休眠設備五芝;當休眠時不發(fā)起鬧鐘痘儡。
AlarmManager.RTC_WAKEUP:硬件時間,當鬧鐘發(fā)射時喚醒休眠設備枢步;
AlarmManager.ELAPSED_REALTIME:真實時間流逝沉删,不喚醒休眠設備;當設備休眠時不發(fā)起鬧鐘醉途。
AlarmManager.ELAPSED_REALTIME_WAKEUP:真實時間流逝矾瑰,當鬧鐘發(fā)起時喚醒手機休眠;
RTC鬧鐘和ELAPSED_REALTIME 最大的差別就是前者可以通過修改手機時間觸發(fā)鬧鐘事件隘擎,
后者要通過真實時間的流逝殴穴,即使在休眠狀態(tài),時間也會被計算货葬。
- long triggerAtMillis : 鬧鐘第一次執(zhí)行時間采幌,毫秒為單位,需與第一個type參數(shù)匹配宝惰,
- 如果是RTC類型植榕,triggerAtMillis 則一般使用System.currentTimeMillis();
- 如果是ELAPSED類型尼夺,triggerAtMillis 則一般使用SystemClock.elapsedRealtime();
- long intervalMillis : 兩次鬧鐘執(zhí)行間隔
- PendingIntent operation : 任務的執(zhí)行動作尊残,發(fā)送廣播,啟動activity淤堵,啟動service
上述大概講了AlarmManager接口如何使用寝衫,作為一名System Engineer,我們還需要研究研究真實的服務提供者AlarmManagerService:
從上述名字中我們知道AlarmManager 只是AlarmManagerService的代理拐邪,實際實現(xiàn)都是在AlarmManagerService中實現(xiàn)的慰毅;
AlarmManagerService啟動
frameworks\base\services\java\com\android\server\SystemServer.java
private void startOtherServices() {
...
mAlarmManagerService = mSystemServiceManager.startService(AlarmManagerService.class);
//mSystemServiceManager 即是SystemServiceManger
alarm = IAlarmManager.Stub.asInterface(
ServiceManager.getService(Context.ALARM_SERVICE));
...
}
frameworks\base\services\core\java\com\android\server\SystemServiceManager.java
public <T extends SystemService> T startService(Class<T> serviceClass) {
...
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
...
mServices.add(service);
service.onStart(); //service 即是AlarmManagerService
}
frameworks\base\services\core\java\com\android\server\AlarmManagerService.java
@Override
public void onStart() {
mNativeData = init();//init方法是native 方法,調用JNI
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));
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), 0,
UserHandle.ALL);
Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
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();
/*
上述代碼注冊了各種監(jiān)聽器扎阶,監(jiān)聽各種和時間變化相關的事務
*/
if (mNativeData != 0) {
AlarmThread waitThread = new AlarmThread(); //創(chuàng)建AlarmThread
waitThread.start();
} else {
Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
}
publishBinderService(Context.ALARM_SERVICE, mService); //注冊服務汹胃,調用ServiceManager.addService添加服務;
}
最后的publishBinderService即調用ServiceManager.addService注冊服務东臀,服務
AlarmManagerService的onStart方法工作
1. 由于重啟內核沒有時區(qū)信息着饥,需要將時區(qū)信息保存到內核;
2. 創(chuàng)建ClockReceiver用于監(jiān)聽TIME_TICK和DATE_CHANGED廣播惰赋;
3. 創(chuàng)建InteractiveStateReceiver宰掉,用于監(jiān)聽亮屏/滅屏廣播;
4. 創(chuàng)建UninstallReceiver,用于監(jiān)聽package移除/重啟轨奄,sdcard不可用的廣播孟害;
5. 創(chuàng)建線程”AlarmManager”;
6. 注冊服務挪拟。
AlarmManagerService中的native JNI方法:
private native long init();
private native void close(long nativeData);
private native void set(long nativeData, int type, long seconds, long nanoseconds);
private native void clear(long nativeData, int type, long seconds, long nanoseconds);
private native int waitForAlarm(long nativeData);
private native int setKernelTime(long nativeData, long millis);
private native int setKernelTimezone(long nativeData, int minuteswest);
我們根據(jù)Android JNI 文件命名規(guī)范(報名中"."替換為"_")知道對應的JNI文件名為com_android_server_AlarmManagerService.cpp
static 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},
};
上述說道在AlarmManagerService.java中onStart方法中有調用native JNI init()方法挨务;
static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
{
jlong ret = init_alarm_driver(); //初始化alarm driver
if (ret) {
return ret;
}
return init_timerfd(); //初始化文件描述符
}
static jlong init_alarm_driver()
{
int fd = open("/dev/alarm", O_RDWR); //打開節(jié)點/dev/alarm,并創(chuàng)建Alarm驅動對象舞丛。
if (fd < 0) {
ALOGV("opening alarm driver failed: %s", strerror(errno));
return 0;
}
AlarmImpl *ret = new AlarmImplAlarmDriver(fd);//創(chuàng)建AlarmImplAlarmDriver對象
return reinterpret_cast<jlong>(ret);
}
static jlong init_timerfd()
{
int epollfd;
int fds[N_ANDROID_TIMERFDS];
......
epollfd = epoll_create(N_ANDROID_TIMERFDS);
for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
......
}
AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd);//創(chuàng)建AlarmImplTimerFd對象
for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
epoll_event event;
event.events = EPOLLIN | EPOLLWAKEUP;
event.data.u32 = i;
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));
/* 0 = disarmed; the timerfd doesn't need to be armed to get
RTC change notifications, just set up as cancelable */
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);
}
//android_alarm_to_clockid 數(shù)組的定義
android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
CLOCK_REALTIME_ALARM,
CLOCK_REALTIME,
CLOCK_BOOTTIME_ALARM,
CLOCK_BOOTTIME,
CLOCK_MONOTONIC,
CLOCK_REALTIME,
};
AlarmThread
private class AlarmThread extends Thread
{
public AlarmThread()
{
super("AlarmManager");
}
public void run()
{
ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
while (true) //無線循環(huán)
{
int result = waitForAlarm(mNativeData); //JNI 方法耘子,使用EPOLL監(jiān)聽FD,等待驅動返回執(zhí)行下面的分發(fā)執(zhí)行球切;
triggerList.clear();
if ((result & TIME_CHANGED_MASK) != 0) {
if (DEBUG_BATCH) {
Slog.v(TAG, "Time changed notification from kernel; rebatching");
}
removeImpl(mTimeTickSender);
rebatchAllAlarms();
mClockReceiver.scheduleTimeTickEvent();
synchronized (mLock) {
mNumTimeChanged++;
}
Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_FOREGROUND);
getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
}
synchronized (mLock) {
final long nowRTC = System.currentTimeMillis();
final long nowELAPSED = SystemClock.elapsedRealtime();
if (localLOGV) Slog.v(
TAG, "Checking for alarms... rtc=" + nowRTC
+ ", elapsed=" + nowELAPSED);
if (WAKEUP_STATS) {
if ((result & IS_WAKEUP_MASK) != 0) {
long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
int n = 0;
for (WakeupEvent event : mRecentWakeups) {
if (event.when > newEarliest) break;
n++; // number of now-stale entries at the list head
}
for (int i = 0; i < n; i++) {
mRecentWakeups.remove();
}
recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);
}
}
boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
if (SystemProperties.getInt("sys.quickboot.enable", 0) == 1) {
filtQuickBootAlarms(triggerList);
}
if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
// if there are no wakeup alarms and the screen is off, we can
// delay what we have so far until the future.
if (mPendingNonWakeupAlarms.size() == 0) {
mStartCurrentDelayTime = nowELAPSED;
mNextNonWakeupDeliveryTime = nowELAPSED
+ ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2);
}
mPendingNonWakeupAlarms.addAll(triggerList);
mNumDelayedAlarms += triggerList.size();
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
} else {
// now deliver the alarm intents; if there are pending non-wakeup
// alarms, we need to merge them in to the list. note we don't
// just deliver them first because we generally want non-wakeup
// alarms delivered after wakeup alarms.
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
if (mPendingNonWakeupAlarms.size() > 0) {
calculateDeliveryPriorities(mPendingNonWakeupAlarms);
triggerList.addAll(mPendingNonWakeupAlarms);
Collections.sort(triggerList, mAlarmDispatchComparator);
final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
mTotalDelayTime += thisDelayTime;
if (mMaxDelayTime < thisDelayTime) {
mMaxDelayTime = thisDelayTime;
}
mPendingNonWakeupAlarms.clear();
}
deliverAlarmsLocked(triggerList, nowELAPSED); //alarm 事件分發(fā)
}
}
}
}
}
waitForAlarm是一個native方法具體的實現(xiàn)在驅動中。如果整個系統(tǒng)中沒有alarm的時間回調绒障,
waitForAlarm則阻塞在這吨凑,直到有回調的時候才往后執(zhí)行,這樣會減少CPU的開銷户辱。
com_android_server_AlarmManagerService.cpp waitForAlarm()
int AlarmImplTimerFd::waitForAlarm()
{
epoll_event events[N_ANDROID_TIMERFDS];
int nevents = epoll_wait(epollfd, events, N_ANDROID_TIMERFDS, -1);//監(jiān)聽事件
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 |= (1 << alarm_idx);
}
}
return result;
}
deliverAlarmsLocked() —— AlarmThread事件中分發(fā)Alarm事件
void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) {
mLastAlarmDeliveryTime = nowELAPSED;
for (int i=0; i<triggerList.size(); i++) {
Alarm alarm = triggerList.get(i);
try {
if (localLOGV) {
Slog.v(TAG, "sending alarm " + alarm);
}
alarm.operation.send(getContext(), 0, //調用PendingIntent的send方法
mBackgroundIntent.putExtra(
Intent.EXTRA_ALARM_COUNT, alarm.count),
mResultReceiver, mHandler);
// we have an active broadcast so stay awake.
if (mBroadcastRefCount == 0 || !mWakeLock.isHeld()) {
setWakelockWorkSource(alarm.operation, alarm.workSource,
alarm.type, alarm.tag, true);
mWakeLock.acquire();
}
final InFlight inflight = new InFlight(AlarmManagerService.this,
alarm.operation, alarm.workSource, alarm.type, alarm.tag, alarm.uid);
mInFlight.add(inflight);
mBroadcastRefCount++;
mTriggeredUids.add(new Integer(alarm.uid));
final BroadcastStats bs = inflight.mBroadcastStats;
bs.count++;
if (bs.nesting == 0) {
bs.nesting = 1;
bs.startTime = nowELAPSED;
} else {
bs.nesting++;
}
final FilterStats fs = inflight.mFilterStats;
fs.count++;
if (fs.nesting == 0) {
fs.nesting = 1;
fs.startTime = nowELAPSED;
} else {
fs.nesting++;
}
if (alarm.type == ELAPSED_REALTIME_WAKEUP
|| alarm.type == RTC_WAKEUP
|| alarm.type == RTC_POWEROFF_WAKEUP) {
bs.numWakeup++;
fs.numWakeup++;
if (alarm.workSource != null && alarm.workSource.size() > 0) {
for (int wi=0; wi<alarm.workSource.size(); wi++) {
ActivityManagerNative.noteWakeupAlarm(
alarm.operation, alarm.workSource.get(wi),
alarm.workSource.getName(wi));
}
} else {
ActivityManagerNative.noteWakeupAlarm(
alarm.operation, -1, null);
}
}
} catch (PendingIntent.CanceledException e) {
if (alarm.repeatInterval > 0) {
// This IntentSender is no longer valid, but this
// is a repeating alarm, so toss the hoser.
removeImpl(alarm.operation);
}
} catch (RuntimeException e) {
Slog.w(TAG, "Failure sending alarm.", e);
}
}
}
PendingIntent.java
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 = mTarget.send(code, intent, resolvedType, //////////mTarget 是PendingIntentRecord
onFinished != null
? new FinishedDispatcher(this, onFinished, handler)
: null,
requiredPermission, options);
...
} catch (RemoteException e) {
throw new CanceledException(e);
}
}
mTarget 是什么呢鸵钝??庐镐?
我們前面講述AlarmManger使用時講述會通過PendingIntent.getActivity或者getService吧恩商;
PendingIntent 常用的幾個靜態(tài)方法:
PendingIntent.getActivity
PendingIntent.getService
PendingIntent.getBroadcast
PendingIntent.getBroadcastAsUser
mTarget就是在上述方法中創(chuàng)建PendingIntent時創(chuàng)建的。上述幾個方法最終都會調用ActivityManagerService的getIntentSender方法
public static PendingIntent getService(Context context, int requestCode,
Intent intent, int flags) {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
intent.prepareToLeaveProcess();
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender( // ActivityManagerNative.getDefault()獲取的是
//AMS的代理ActivityMangerProxy必逆,binder call 調用AMS的相關方法
ActivityManager.INTENT_SENDER_SERVICE, packageName,
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, null, UserHandle.myUserId());
return target != null ? new PendingIntent(target) : null;
} catch (RemoteException e) {
}
return null;
}
ActivityMangerService.java的 getIntentSender()獲取的是PendingIntentRecord對象, 而該對象繼承于IIntentSender.Stub怠堪, 經(jīng)過binder call回來, 所以此處target是指PendingIntentRecord對象的代理端, 即為PendingIntent.mTarget,所以上述最終會調用PendingIntentRecord的send方法名眉;具體的喚起Activity,Service等具體業(yè)務就是在這個send 方法中完成粟矿;
下面完整看一下AlarmManager 的set接口操作過程;
AlarmManager.java
public void set(int type, long triggerAtMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation, null, null);
}
private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
PendingIntent operation, 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;
}
try {
mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation,
workSource, alarmClock); //這里的mService就是前面的AlarmManagerService中的mService對象损拢。
} catch (RemoteException ex) {
}
}
//AlarmManager 類的構造函數(shù)
AlarmManager(IAlarmManager service, Context ctx) {
mService = service;
final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT);
}
ContextImpl.java
AlarmManager對象的獲饶按狻:(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
private static void registerService(String serviceName, ServiceFetcher fetcher) {
if (!(fetcher instanceof StaticServiceFetcher)) {
fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
}
SYSTEM_SERVICE_MAP.put(serviceName, fetcher); //添加service到SYSTEM_SERVICE_MAP
}
registerService(ALARM_SERVICE, new ServiceFetcher() { //注冊
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(ALARM_SERVICE);
IAlarmManager service = IAlarmManager.Stub.asInterface(b);
return new AlarmManager(service, ctx);
}});
/*package*/ static class ServiceFetcher {
int mContextCacheIndex = -1;
/**
* Main entrypoint; only override if you don't need caching.
*/
public Object getService(ContextImpl ctx) {
ArrayList<Object> cache = ctx.mServiceCache;
Object service;
synchronized (cache) {
if (cache.size() == 0) {
// Initialize the cache vector on first access.
// At this point sNextPerContextServiceCacheIndex
// is the number of potential services that are
// cached per-Context.
for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
cache.add(null);
}
} else {
service = cache.get(mContextCacheIndex);
if (service != null) {
return service;
}
}
service = createService(ctx);
cache.set(mContextCacheIndex, service);
return service;
}
}
/**
* Override this to create a new per-Context instance of the
* service. getService() will handle locking and caching.
*/
public Object createService(ContextImpl ctx) {
throw new RuntimeException("Not implemented");
}
}
所以getSystemService中返回的就是AlarmManagerService 中mService 的代理;即AlarmManager中mService變量即是AlarmManagerService中mService的代理福压;AlarmManager中方法最終都是有AlarmManagerService的mService處理
關于上述AlarmManager中set方法的處理掏秩,調用
mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation,
workSource, alarmClock); //這里的mService就是前面的AlarmManagerService中的mService對象。
Binder Call 到AlarmMangerService中
本段代碼是截取Android 5.1源碼荆姆;
@Override
public void set(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock) {
if (workSource != null) {
getContext().enforceCallingPermission(
android.Manifest.permission.UPDATE_DEVICE_STATS,
"AlarmManager.set");
}
setImpl(type, triggerAtTime, windowLength, interval, operation,
windowLength == AlarmManager.WINDOW_EXACT, workSource, alarmClock);
}
void setImpl(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, boolean isStandalone, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock) {
if (operation == null) {
Slog.w(TAG, "set/setRepeating ignored because there is no intent");
return;
}
// Sanity check the window length. This will catch people mistakenly
// trying to pass an end-of-window timestamp rather than a duration.
if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
Slog.w(TAG, "Window length " + windowLength
+ "ms suspiciously long; limiting to 1 hour");
windowLength = AlarmManager.INTERVAL_HOUR;
}
// Sanity check the recurrence interval. This will catch people who supply
// seconds when the API expects milliseconds.
if (interval > 0 && interval < MIN_INTERVAL) {
Slog.w(TAG, "Suspiciously short interval " + interval
+ " millis; expanding to " + (int)(MIN_INTERVAL/1000)
+ " seconds");
interval = MIN_INTERVAL;
}
if (type < RTC_WAKEUP || type > RTC_POWEROFF_WAKEUP) {
throw new IllegalArgumentException("Invalid alarm type " + type);
}
if (triggerAtTime < 0) {
final long who = Binder.getCallingUid();
final long what = Binder.getCallingPid();
Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who
+ " pid=" + what);
triggerAtTime = 0;
}
final long nowElapsed = SystemClock.elapsedRealtime();
final long nominalTrigger = convertToElapsed(triggerAtTime, type);
// Try to prevent spamming by making sure we aren't firing alarms in the immediate future
final long minTrigger = nowElapsed + MIN_FUTURITY;
final long triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger;
final long maxElapsed;
if (windowLength == AlarmManager.WINDOW_EXACT) {
maxElapsed = triggerElapsed;
} else if (windowLength < 0) {
maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
} else {
maxElapsed = triggerElapsed + windowLength;
}
final int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
if (DEBUG_BATCH) {
Slog.v(TAG, "set(" + operation + ") : type=" + type
+ " triggerAtTime=" + triggerAtTime + " win=" + windowLength
+ " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
+ " interval=" + interval + " standalone=" + isStandalone);
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
interval, operation, isStandalone, true, workSource, alarmClock, userId);
}
}
private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
long maxWhen, long interval, PendingIntent operation, boolean isStandalone,
boolean doValidate, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
int userId) {
Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
operation, workSource, alarmClock, userId);
removeLocked(operation);
int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);
if (whichBatch < 0) {
Batch batch = new Batch(a);
batch.standalone = isStandalone;
addBatchLocked(mAlarmBatches, batch);
} else {
Batch batch = mAlarmBatches.get(whichBatch);
if (batch.add(a)) {
// The start time of this batch advanced, so batch ordering may
// have just been broken. Move it to where it now belongs.
mAlarmBatches.remove(whichBatch);
addBatchLocked(mAlarmBatches, batch);
}
}
if (alarmClock != null) {
mNextAlarmClockMayChange = true;
updateNextAlarmClockLocked();
}
if (DEBUG_VALIDATE) {
if (doValidate && !validateConsistencyLocked()) {
Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when
+ " when(hex)=" + Long.toHexString(when)
+ " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen
+ " interval=" + interval + " op=" + operation
+ " standalone=" + isStandalone);
rebatchAllAlarmsLocked(false);
}
}
rescheduleKernelAlarmsLocked();
}
void rescheduleKernelAlarmsLocked() {
// Schedule the next upcoming wakeup alarm. If there is a deliverable batch
// prior to that which contains no wakeups, we schedule that as well.
long nextNonWakeup = 0;
if (mAlarmBatches.size() > 0) {
final Batch firstWakeup = findFirstWakeupBatchLocked();
final Batch firstBatch = mAlarmBatches.get(0);
final Batch firstRtcWakeup = findFirstRtcWakeupBatchLocked();
// always update the kernel alarms, as a backstop against missed wakeups
if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
mNextWakeup = firstWakeup.start;
setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);//調用方法
}
if (firstRtcWakeup != null && mNextRtcWakeup != firstRtcWakeup.start) {
mNextRtcWakeup = firstRtcWakeup.start;
long when = firstRtcWakeup.getWhenByElapsedTime(mNextRtcWakeup);
if (when != 0) {
setLocked(RTC_POWEROFF_WAKEUP, when);
}
}
if (firstBatch != firstWakeup) {
nextNonWakeup = firstBatch.start;
}
}
if (mPendingNonWakeupAlarms.size() > 0) {
if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) {
nextNonWakeup = mNextNonWakeupDeliveryTime;
}
}
// always update the kernel alarm, as a backstop against missed wakeups
if (nextNonWakeup != 0) {
mNextNonWakeup = nextNonWakeup;
setLocked(ELAPSED_REALTIME, nextNonWakeup); //
}
}
private void setLocked(int type, long when) {
if (mNativeData != 0) {
// 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); //native JNI call蒙幻,調用JN native 方法
} else {
Message msg = Message.obtain();
msg.what = ALARM_EVENT;
mHandler.removeMessages(ALARM_EVENT);
mHandler.sendMessageAtTime(msg, when);
}
}
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); //從java傳遞的nativeData,
//AlarmMangerService中的nativeData 實際是該JNI init() 的返回值胞枕;此時返回的是AlarmImplAlarmDriver
struct timespec ts;
ts.tv_sec = seconds;
ts.tv_nsec = nanoseconds;
int result = impl->set(type, &ts);//AlarmImplAlarmDriver->set
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));
}
}
static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
{
jlong ret = init_alarm_driver();//即操作Alarm device——"/dev/alarm"
if (ret) {
return ret;
}
return init_timerfd();//如果沒有Alarm device杆煞,繼續(xù)執(zhí)行
}
int AlarmImplAlarmDriver::set(int type, struct timespec *ts)
{
return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);// 最終ioctl操作硬件
}
最終通過ioctl的方式將時間設置給驅動,后續(xù)驅動不做詳解,我也不清楚决乎,
目的就是把時間設置給驅動队询,等到硬件中斷返回后,再回調到native層构诚,native再回調到framework蚌斩,
如何回調到framework的呢?范嘱?
我們上述說的AlarmThread送膳,在run()方法中開啟一個無限循環(huán),循環(huán)中會調用
int result = waitForAlarm(mNativeData); //JNI 方法丑蛤,使用EPOLL監(jiān)聽FD叠聋,阻塞等待驅動返回執(zhí)行下面的分發(fā)執(zhí)行;
waitForAlarm是一個native方法受裹,具體的實現(xiàn)在驅動中碌补。如果整個系統(tǒng)中沒有alarm的時間回調,waitForAlarm則阻塞在這棉饶,直到有回調的時候才往后執(zhí)行厦章,才會繼續(xù)執(zhí)行上述的deliverAlarmsLocked()方法,才會去執(zhí)行相應的send方法喚醒activity等照藻。
一個完整的過程就是操作"/dev/alarm"設備的過程袜啃。自此一個完整的操作過程就結束了;