PendingIntent源码分析

一、 重要api和参数

首先看下官方解释:

A description of an Intent and target action to perform with it. Instances of this class are created with getActivity(Context, int, Intent, int), getActivities(Context, int, Intent[], int), getBroadcast(Context, int, Intent, int), and getService(Context, int, Intent, int); the returned object can be handed to other applications so that they can perform the action you described on your behalf at a later time.
简单来说PendingIntent就是一个Intent的封装,我们可以把这个封装好的intent交给别的程序,别的程序根据这个intent延后处理intent中所描述的事情。

重要的方法有三个:
  • getActivity(Context context, int requestCode, Intent intent, int flags, Bundle options)
  • getBroadcast(Context context, int requestCode, Intent intent, int flags)
  • getService(Context context, int requestCode, Intent intent, int flags)


重要的参数:
  • FLAG_CANCEL_CURRENT:清除之前的,重新创建一个新的
  • FLAG_NO_CREATE:如果pendingintent不存在则不创建直接返回null
  • FLAG_ONE_SHOT:一次性的.
  • FLAG_UPDATE_CURRENT:如果已经存在,则复用这个pendingIntent实例,只更新intent相关的extra data
之前DeviceManager和LCTS中存在alarm个数过多的问题,就是这里参数不正确造成的。


二、比较两个PendingIntent实例是否相等的流程

两个PendingIntent对等是指它们的intentSender一样, 且其它们的Intent的action, data, categories, components和flags都一样。但是它们的Intent的Extra可以不一样。



具体分析如下:
@PendingIntent.java
@Override
public boolean equals(Object otherObj) {
     if (otherObj instanceof PendingIntent) {
         return mTarget.asBinder().equals(((PendingIntent)otherObj).mTarget.asBinder());
    }
    return false;
}
这里复写了equals方法,比较的是mTarget,而这个对象是一个IIntentSender的对象。

public static PendingIntent getActivity(Context context, int requestCode,
                                            Intent intent, int flags, Bundle options) {

    String packageName = context.getPackageName();
    String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
    context.getContentResolver()) : null;
    try {
        intent.migrateExtraStreamToClipData();
        ntent.prepareToLeaveProcess();

       IIntentSender target =ActivityManagerNative.getDefault().getIntentSender(
           ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
           null, null, requestCode, new Intent[] { intent },
           resolvedType != null ? new String[] { resolvedType } : null,
           flags, options, UserHandle.myUserId());
       return target != null ? new PendingIntent(target) : null;

构造方法:
PendingIntent
(IIntentSender target) {

    mTarget = target;
}
上面提到的mTarget是在这里创建的,通过AMS查询到一个intentsender的实例,然后通过PendingIntent的构造方法 传入。


@ActivityManagerService.java
ActivityManagerNative.getDefault().getIntentSender()最终是调用了getIntentSenderLocked这个方法:

IIntentSender  getIntentSenderLocked (int type, String packageName,int callingUid, int userId, IBinder token, String resultWho,int requestCode, Intent[] intents, String[] resolvedTypes, int flags,Bundle options) {
...
final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
|PendingIntent.FLAG_UPDATE_CURRENT);

//根据参数生成key
PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, activity, resultWho,
          requestCode, intents, resolvedTypes, flags, options, userId);
WeakReference ref;
//从已有的IntentSendRecoder中查找是否有key一样的
ref = mIntentSenderRecords.get(key);
PendingIntentRecord rec = ref != null ? ref.get() : null;

//如果找到key一样的
if (rec != null) {
    if (!cancelCurrent) { //参数不是FLAG_CANCEL_CURRENT
        if (updateCurrent) { //参数是FLAG_UPDATE_CURRENT
            if (rec.key.requestIntent != null) {  //替换intents中最后一个intent的extra
                 rec.key.requestIntent.replaceExtras(intents != null ?
                 intents[intents.length - 1] : null);
            }
            if (intents != null) {
                intents[intents.length-1] = rec.key.requestIntent;
                rec.key.allIntents = intents;
                rec.key.allResolvedTypes = resolvedTypes;
            } else {
                rec.key.allIntents = null; 
                rec.key.allResolvedTypes = null;
            }
        }
        return rec;
    }
    rec.canceled = true;
    mIntentSenderRecords.remove(key);
}
if (noCreate) {
    return rec;
}

三、pendingIntent的发送和接收流程
使用到PendingIntent的主要场景都是和android中特定的的远程服务打交道(如:短信、通知、闹铃等)。
下面以Alarm为例,介绍一下整个发送和接收流程。

从上面的介绍知道,通过getActivity,getService,getBroadcast方法能够获得一个PendingIntent的实例。

【例子】
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent,
                                               PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.cancel(sender);
alarmMgr.set(AlarmManager.RTC, System.currentTimeMillis() + period,sender);


@AlarmManagerService.java中set()方法最后调到了setImplLocked()

private void  setImplLocked (int type, long when, long whenElapsed, long windowLength,
                long maxWhen, long interval, PendingIntent operation, boolean isStandalone,
                boolean doValidate, WorkSource workSource) {

Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,operation, workSource);
removeLocked(operation); 

int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);
if (whichBatch < 0) {//mAlarmBatches没找到匹配的batch
    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);  
}

rescheduleKernelAlarmsLocked();
}
这里最重要的就是新建/获取一个Batch 对象,加入到mAlarmBatches这个list中,然后调用
rescheduleKernelAlarmsLocked方法


private 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.
    if (mAlarmBatches.size() > 0) {
        final Batch firstWakeup = findFirstWakeupBatchLocked();
        final Batch firstBatch = 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);
        }
    }
}
找出第一个唤醒型的alarm和第一个非唤醒型的alarm,一并处理

private void  setLocked (int type, long when){
...
Message msg = Message.obtain();
msg.what = ALARM_EVENT;

mHandler.removeMessages(ALARM_EVENT);
mHandler.sendMessageAtTime(msg, when);
}
这里就简单的发送一个message。


private class AlarmHandler extends Handler {
public static final int ALARM_EVENT = 1;
public static final int MINUTE_CHANGE_EVENT = 2;
public static final int DATE_CHANGE_EVENT = 3;

public AlarmHandler() {
}

public void  handleMessage (Message msg) {
    if (msg.what ==  ALARM_EVENT ) { 
        ArrayList triggerList = new ArrayList();
        synchronized (mLock) {
            final long nowRTC = System.currentTimeMillis();
            final long nowELAPSED = SystemClock.elapsedRealtime();
             triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
        }

        // now trigger the alarms without the lock held
        for (int i=0; i
            Alarm alarm = triggerList.get(i);
            try {
                 alarm.operation.send();
            } catch (PendingIntent.CanceledException e) {
                if (alarm.repeatInterval > 0) {
                    // This IntentSender is no longer valid, but this
                    // is a repeating alarm, so toss the hoser.
                    remove(alarm.operation);
                }
            }
        }
    }
}
}

private void  triggerAlarmsLocked (ArrayList triggerList, long nowELAPSED, long nowRTC) {

while (mAlarmBatches.size() > 0) {
    
    Batch batch = mAlarmBatches.get(0);
    if (batch.start > nowELAPSED) {
        //遍历mAlarmBatches,直到所有的到期的batch都被处理完毕
        break;
    }
    mAlarmBatches.remove(0);

    final int N = batch.size();
    for (int i = 0; i < N; i++) {
        Alarm alarm = batch.get(i);
        alarm.count = 1;
         triggerList.add(alarm);
        if (alarm.repeatInterval > 0) {
            setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
                maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
                alarm.repeatInterval, alarm.operation, batch.standalone, true,
                alarm.workSource);
        }
    }

这里最重要的事情就是将触发的alarm加入到triggerList,如果有repeat的,继续调一次setImplLocked,重新走一遍流程。

回到handlemessage方法中,triggerAlarmsLocked调用结束后,所有被触发的alarm都存在triggerList里,然后遍历这个list去调用alarm.operation.send();
这里的operation就是一个PendingIntent。

@PendingIntent.java
public void  send () throws CanceledException {
    send(null, 0, null, null, null, null);
}


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

从上面分析可知,这里的mTarget就是AMS中返回的PendingIntentRecord对象

@PendingIntentRecord.java
public int  send (int code, Intent intent, String resolvedType,IIntentReceiver finishedReceiver, String                                  requiredPermission) {
    return sendInner(code, intent, resolvedType, finishedReceiver,
                               requiredPermission, null, null, 0, 0, 0, null);
}

int  sendInner (int code, Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission,
IBinder resultTo, String resultWho, int requestCode,
int flagsMask, int flagsValues, Bundle options) {
...
    switch (key.type) {
    case ActivityManager. INTENT_SENDER_ACTIVITY :
        owner.startActivityInPackage(uid, key.packageName, finalIntent, resolvedType, resultTo, resultWho,                  requestCode, 0,options, userId);
    case ActivityManager. INTENT_SENDER_BROADCAST :
        owner.broadcastIntentInPackage(key.packageName, uid,finalIntent, resolvedType,finishedReceiver,                    code, null, null,requiredPermission, (finishedReceiver != null), false, userId);
    case ActivityManager. INTENT_SENDER_SERVICE :
         owner.startServiceInPackage(uid,finalIntent, resolvedType, userId);
    }

...
}
这里的owner是AMS,到这里终于调用AMS去启动对应的actvity,service或者broadcast。整个流程也就结束了。

另外需要注意的是,通过pendingIntent启动Activity或者service时,最好给定显式的intent,防止被其他进程接收。

你可能感兴趣的:(Android)