关于Notification的一点愚见(PendingIntent工作流程)

PendingIntent,顾名思义,延迟的Intent。那么肯定会产生一个疑问,那就是PendingIntent究竟和Intent的区别在哪里呢?
其实PendingIntent其实就是对Intent的一个封装,不过Intent是立即触发效果,就像我们常用的这样:

        Intent intent = new Intent(MainActivity.this,DemoActivity1.class);
        startActivity(intent);

而PendingIntent触发的时间点不太一样,一般是触发效果的地点不在函数中,而是在其他方法处被调用,所以看起来就像被延迟了一样。

PendingIntent的声明

我们可以知道PendingIntent可以支持三种意图:启动Activity,启动Service,启动Broadcast。我们取出其中一个场景来讨论,其他两个场景是类似的。
上一章中,有如下这段:

PendingIntent pendingIntent = PendingIntent.getActivity(this,
                    0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

这一段就是PendingIntent的声明,调用PendingIntent中的getActivity()的方法返回实例。
下面是getActivity的源码:

    public static PendingIntent getActivity(Context context, int requestCode,
            Intent intent, @Flags int flags) {
        return getActivity(context, requestCode, intent, flags, null);
    }

这里又调用了:

public static PendingIntent getActivity(Context context, int requestCode,
            @NonNull Intent intent, @Flags int flags, @Nullable Bundle options) {
        String packageName = context.getPackageName();
        String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                context.getContentResolver()) : null;
        try {
            intent.migrateExtraStreamToClipData();
            intent.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;
        } catch (RemoteException e) {
        }
        return null;
    }

其中核心代码:

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;

而这里ActivityManagerNative.getDefault()是指的是AMS(ActivityManagerService)这个类,这个类可以说是贯穿了Android整个应用层的结构。它在Android系统中,四大组件的行为和它密切相关。
而AMS是属于原进程之外,那么我们就必须完成进程间通讯的动作。而同时Activity是继承了Binder实现了IActivityManager的接口。之前的讲述Binder的时候也说过了,在Android的进程间通讯,Binder起到了至关重要的作用。

于此同时,也要说明一下IIntentSender这个类其实是继承了IInterface抽象类的接口。

 public interface IIntentSender extends android.os.IInterface

AMS中PendingIntent的工作

我们下去AMS的getIntentSender()看看这个函数的究竟。

  @Override
    public IIntentSender getIntentSender(int type,
            String packageName, IBinder token, String resultWho,
            int requestCode, Intent[] intents, String[] resolvedTypes,
            int flags, Bundle options, int userId) {

....//获取Intent对象,存入数组并且对非法的intent做出处理

        synchronized(this) {
            int callingUid = Binder.getCallingUid();
            int origUserId = userId;
            userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
                    type == ActivityManager.INTENT_SENDER_BROADCAST,
                    ALLOW_NON_FULL, "getIntentSender", null);
            if (origUserId == UserHandle.USER_CURRENT) {
                // We don't want to evaluate this until the pending intent is
                // actually executed.  However, we do want to always do the
                // security checking for it above.
                userId = UserHandle.USER_CURRENT;
            }
            try {
                if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
                    int uid = AppGlobals.getPackageManager()
                            .getPackageUid(packageName, UserHandle.getUserId(callingUid));
                    if (!UserHandle.isSameApp(callingUid, uid)) {
                        String msg = "Permission Denial: getIntentSender() from pid="
                            + Binder.getCallingPid()
                            + ", uid=" + Binder.getCallingUid()
                            + ", (need uid=" + uid + ")"
                            + " is not allowed to send as package " + packageName;
                        Slog.w(TAG, msg);
                        throw new SecurityException(msg);
                    }
                }

                return getIntentSenderLocked(type, packageName, callingUid, userId,
                        token, resultWho, requestCode, intents, resolvedTypes, flags, options);

            } catch (RemoteException e) {
                throw new SecurityException(e);
            }
        }
    }

我们主要看这一段线程同步的代码,最后你会发现获取完uid之类的信息之后就会回调函数getIntentSenderLocked(type, packageName, callingUid, userId,
token, resultWho, requestCode, intents, resolvedTypes, flags, options);这个才是真正处理问题的函数。

IIntentSender getIntentSenderLocked(int type, String packageName,
            int callingUid, int userId, IBinder token, String resultWho,
            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
            Bundle options) {
        if (DEBUG_MU)
            Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);
        ActivityRecord activity = null;
        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
            activity = ActivityRecord.isInStackLocked(token);
            if (activity == null) {
                return null;
            }
            if (activity.finishing) {
                return null;
            }
        }

        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);

        PendingIntentRecord.Key key = new PendingIntentRecord.Key(
                type, packageName, activity, resultWho,
                requestCode, intents, resolvedTypes, flags, options, userId);
        WeakReference<PendingIntentRecord> ref;
        ref = mIntentSenderRecords.get(key);
        PendingIntentRecord rec = ref != null ? ref.get() : null;
        if (rec != null) {
            if (!cancelCurrent) {
                if (updateCurrent) {
                    if (rec.key.requestIntent != null) {
                        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;
        }
        rec = new PendingIntentRecord(this, key, callingUid);
        mIntentSenderRecords.put(key, rec.ref);
        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
            if (activity.pendingResults == null) {
                activity.pendingResults
                        = new HashSet<WeakReference<PendingIntentRecord>>();
            }
            activity.pendingResults.add(rec.ref);
        }
        return rec;
    }

这一段做的工作有一下几点:
1.假若flags是type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT。则说明是从Activity应答的PendingIntent,我们不做讨论。

2.假如PendingIntentRecord不为空,根据PendingIntent的标志位,Intent数组的做出调整来达到PendingIntent的效果。
这里先说一下PendingIntent,有四个标志位:

1)FLAG_ONE_SHOT :当前描述的PendingIntent只能被使用一次,然后它就会调用cancel删除。如果还有后续相同的PendingIntent,那么他们的send方法将会调用失败。
对于通知栏而言,采用此标志位,同类通知只能使用一次,后续点击通知会无效。

2)FLAG_NO_CREATE:当前描述的PendingIntent不会主动创建,如果当前PendingIntent之前不存在,则所有的getActivity,getService,getBroadcast返回null,获取PendingIntent失败。这个很少用,暂时不讨论。

3)FLAG_CANCEL_CURRENT:当前描述的PendingIntent已经存在了,那么他们会被cancel,然后系统创建一个新的PendingIntent。对于通知栏而言,被cancel后的消息单击无效。

4)FLAG_UPDATE_CURRENT:如果当前的PendingIntent已经存在,则它们都会被更新,即里面的PendingIntent都换为最新。

3.假如PendingIntentRecord为空则创建一个新的PendingIntentRecord。并且存入Activity中PendingIntentRecord的HashSet中。最后返回PendingIntentRecord。

这个时候,我们发现返回了PendingIntentRecord,说明这个类正是实现了IIntentSender。让我们看看这个类是怎么回事吧。

final class PendingIntentRecord extends IIntentSender.Stub

看到了吧,这个类正是实现了IIntentSender.Stub的类。

final class PendingIntentRecord extends IIntentSender.Stub

是不是觉得和眼熟呢?没错就是我们之前分析的AIDL,在这个过程AMS相当于中转器,就像设计模式中的中介者一样。将函数转移到远程端的实现。这种思想在探索四大组件的时候经常会用到。

PendingIntentRecord中工作

在这个类中完成的事情只有一件,那就是将数据存储进来。

PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) {
        owner = _owner;
        key = _k;
        uid = _u;
        ref = new WeakReference<PendingIntentRecord>(this);
    }

//内部类key的定义
     Key(int _t, String _p, ActivityRecord _a, String _w,
                int _r, Intent[] _i, String[] _it, int _f, Bundle _o, int _userId) {
            type = _t;
            packageName = _p;
            activity = _a;
            who = _w;
            requestCode = _r;
            requestIntent = _i != null ? _i[_i.length-1] : null;
            requestResolvedType = _it != null ? _it[_it.length-1] : null;
            allIntents = _i;
            allResolvedTypes = _it;
            flags = _f;
            options = _o;
            userId = _userId;

            int hash = 23;
            hash = (ODD_PRIME_NUMBER*hash) + _f;
            hash = (ODD_PRIME_NUMBER*hash) + _r;
            hash = (ODD_PRIME_NUMBER*hash) + _userId;
            if (_w != null) {
                hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode();
            }
            if (_a != null) {
                hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode();
            }
            if (requestIntent != null) {
                hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode();
            }
            if (requestResolvedType != null) {
                hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode();
            }
            hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode();
            hash = (ODD_PRIME_NUMBER*hash) + _t;
            hashCode = hash;
            //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"
            //        + Integer.toHexString(hashCode));
        }

在这一段代码中,很好的解释了为什么我们在声明PendingIntent的时候,请求码一般为0,在上面hashcode的数值和请求码requestCode进行相加的运算获得新的请求码。假如请求码变动了,hashcode也变动了,那么在AMS中建立的HashSet的检索策略不同了就会造成寻找到的Intent不同,对错误的Intent处理了错误标志位。

到这里,PendingIntent已经存储,完毕正在等待用户的调度。

NotificationManager的调用

我们这里分析Notification中PendingIntent的情况,其实在AppWidget中调用PendingIntent的情景也是十分类似。

我们在制作通知的时候,最后会声明一个NotificationManager的notify去唤醒PendingIntent并且执行。

让我们去NotificationManager中看看,notify方法吧。
我们可以知道, public void notify(int id, Notification notification)又会调用 public void notify(String tag, int id, Notification notification)

 public void notify(String tag, int id, Notification notification)
    {
        int[] idOut = new int[1];
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();
        if (notification.sound != null) {
            notification.sound = notification.sound.getCanonicalUri();
            if (StrictMode.vmFileUriExposureEnabled()) {
                notification.sound.checkFileUriExposed("Notification.sound");
            }
        }
        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
        Notification stripped = notification.clone();
        Builder.stripForDelivery(stripped);
        try {
            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                    stripped, idOut, UserHandle.myUserId());
            if (id != idOut[0]) {
                Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
            }
        } catch (RemoteException e) {
        }
    }

在这一段中,我们只用注意这个函数service.enqueueNotificationWithTag(pkg, mContext.getOpPack-ageName(), tag, id,stripped, idOut, UserHandle.myUserId());
这个函数也是进程间的通讯,透过INotificationManager这个AIDL实现的类,远程调用NotificationManagerService中方法。这个过程也是AIDL实现的Binder弯完成的。

NotificationManagerService中的工作流程

在这里,声明了一个IBinder来实现Stub:

private final IBinder mService = new INotificationManager.Stub() 

而函数enqueueNotificationWithTag又会调用:

void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
            final int callingPid, final String tag, final int id, final Notification notification,
            int[] idOut, int incomingUserId) {
            ...
            //从NotificationList中获取通知存入NotificationRecord,以及对Notification中
            //的一些非法额度参数进行异常处理
            mHandler.post(new Runnable() {
            @Override
            public void run() {

                synchronized (mNotificationList) {

                    // === Scoring ===

                    // 0. Sanitize inputs
                    notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
                            Notification.PRIORITY_MAX);
                    // Migrate notification flags to scores
                    if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
                        if (notification.priority < Notification.PRIORITY_MAX) {
                            notification.priority = Notification.PRIORITY_MAX;
                        }
                    } else if (SCORE_ONGOING_HIGHER &&
                            0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
                        if (notification.priority < Notification.PRIORITY_HIGH) {
                            notification.priority = Notification.PRIORITY_HIGH;
                        }
                    }

                    // 1. initial score: buckets of 10, around the app [-20..20]
                    final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER;

                    // 2. extract ranking signals from the notification data
                    final StatusBarNotification n = new StatusBarNotification(
                            pkg, opPkg, id, tag, callingUid, callingPid, score, notification,
                            user);
                    NotificationRecord r = new NotificationRecord(n, score);
                    NotificationRecord old = mNotificationsByKey.get(n.getKey());
                    if (old != null) {
                        // Retain ranking information from previous record
                        r.copyRankingInformation(old);
                    }
                    mRankingHelper.extractSignals(r);

                    // 3. Apply local rules

                    // blocked apps
                    if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
                        if (!isSystemNotification) {
                            r.score = JUNK_SCORE;
                            Slog.e(TAG, "Suppressing notification from package " + pkg
                                    + " by user request.");
                        }
                    }

                    if (r.score < SCORE_DISPLAY_THRESHOLD) {
                        // Notification will be blocked because the score is too low.
                        return;
                    }

                    // Clear out group children of the old notification if the update causes the
                    // group summary to go away. This happens when the old notification was a
                    // summary and the new one isn't, or when the old notification was a summary
                    // and its group key changed.
                    if (old != null && old.getNotification().isGroupSummary() &&
                            (!notification.isGroupSummary() ||
                                    !old.getGroupKey().equals(r.getGroupKey()))) {
                        cancelGroupChildrenLocked(old, callingUid, callingPid, null);
                    }

                    int index = indexOfNotificationLocked(n.getKey());
                    if (index < 0) {
                        mNotificationList.add(r);
                        mUsageStats.registerPostedByApp(r);
                    } else {
                        old = mNotificationList.get(index);
                        mNotificationList.set(index, r);
                        mUsageStats.registerUpdatedByApp(r, old);
                        // Make sure we don't lose the foreground service state.
                        notification.flags |=
                                old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
                        r.isUpdate = true;
                    }

                    mNotificationsByKey.put(n.getKey(), r);

                    // Ensure if this is a foreground service that the proper additional
                    // flags are set.
                    if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
                        notification.flags |= Notification.FLAG_ONGOING_EVENT
                                | Notification.FLAG_NO_CLEAR;
                    }

                    applyZenModeLocked(r);
                    mRankingHelper.sort(mNotificationList);

                    if (notification.icon != 0) {
                        StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
                        mListeners.notifyPostedLocked(n, oldSbn);
                    } else {
                        Slog.e(TAG, "Not posting notification with icon==0: " + notification);
                        if (old != null && !old.isCanceled) {
                            mListeners.notifyRemovedLocked(n);
                        }
                        // ATTENTION: in a future release we will bail out here
                        // so that we do not play sounds, show lights, etc. for invalid
                        // notifications
                        Slog.e(TAG, "WARNING: In a future release this will crash the app: "
                                + n.getPackageName());
                    }

                    buzzBeepBlinkLocked(r);
                }
            }
        });

        idOut[0] = id;

我们主要看Handler.post方法中的Runnable方法。
这么最主要的工作就是这个函数:

if (old != null && old.getNotification().isGroupSummary() &&
                            (!notification.isGroupSummary() ||
                                    !old.getGroupKey().equals(r.getGroupKey()))) {
                        cancelGroupChildrenLocked(old, callingUid, callingPid, null);
                    }

这一段的意思就是清掉前一个通知,如果更新而导致数组的大小出现了变化的话。这个发生在过去的通知是个所有的通知的集合,或者当过去的通知是一个集合但是他的key发生了改变。

而函数cancelGroupChildrenLocked中做了一个动作那就是去除尾部的通知同时执行尾部的通知,接下来又调用了cancelNotificationLocked(childR, false, REASON_GROUP_SUMMARY_CANCELED);

 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
  if (sendDelete) {
            if (r.getNotification().deleteIntent != null) {
                try {
                    r.getNotification().deleteIntent.send();
                } catch (PendingIntent.CanceledException ex) {
                    // do nothing - there's no relevant way to recover, and
                    //     no reason to let this propagate
                    Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
                }
            }
        }
        ....
   }

我们只需要注重上面那一段通过Notification的deleteIntent(上面在显示Notification的时候已经显示了deleteIntent是PendingIntent)的send方法,执行了PendingIntent。

PendingIntent的send

我们接着看PendingIntent的send的方法,在这里send被重载了好几种方法,最终会到这个send执行:

 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.send调用,而mTarget则是IInterSender,这时又会回到PendingIntentRecord。这个时候就可以调用之前存进来的PendingIntent了。
最后由函数sendInner完成:

int sendInner(int code, Intent intent, String resolvedType,
            IIntentReceiver finishedReceiver, String requiredPermission,
            IBinder resultTo, String resultWho, int requestCode,
            int flagsMask, int flagsValues, Bundle options, IActivityContainer container) {
        synchronized(owner) {
            if (!canceled) {
                sent = true;
                if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
                    owner.cancelIntentSenderLocked(this, true);
                    canceled = true;
                }
                Intent finalIntent = key.requestIntent != null
                        ? new Intent(key.requestIntent) : new Intent();
                if (intent != null) {
                    int changes = finalIntent.fillIn(intent, key.flags);
                    if ((changes&Intent.FILL_IN_DATA) == 0) {
                        resolvedType = key.requestResolvedType;
                    }
                } else {
                    resolvedType = key.requestResolvedType;
                }
                flagsMask &= ~Intent.IMMUTABLE_FLAGS;
                flagsValues &= flagsMask;
                finalIntent.setFlags((finalIntent.getFlags()&~flagsMask) | flagsValues);

                final long origId = Binder.clearCallingIdentity();

                boolean sendFinish = finishedReceiver != null;
                int userId = key.userId;
                if (userId == UserHandle.USER_CURRENT) {
                    userId = owner.getCurrentUserIdLocked();
                }
                switch (key.type) {
                    case ActivityManager.INTENT_SENDER_ACTIVITY:
                        if (options == null) {
                            options = key.options;
                        } else if (key.options != null) {
                            Bundle opts = new Bundle(key.options);
                            opts.putAll(options);
                            options = opts;
                        }
                        try {
                            if (key.allIntents != null && key.allIntents.length > 1) {
                                Intent[] allIntents = new Intent[key.allIntents.length];
                                String[] allResolvedTypes = new String[key.allIntents.length];
                                System.arraycopy(key.allIntents, 0, allIntents, 0,
                                        key.allIntents.length);
                                if (key.allResolvedTypes != null) {
                                    System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,
                                            key.allResolvedTypes.length);
                                }
                                allIntents[allIntents.length-1] = finalIntent;
                                allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
                                owner.startActivitiesInPackage(uid, key.packageName, allIntents,
                                        allResolvedTypes, resultTo, options, userId);
                            } else {
                                owner.startActivityInPackage(uid, key.packageName, finalIntent,
                                        resolvedType, resultTo, resultWho, requestCode, 0,
                                        options, userId, container, null);
                            }
                        } catch (RuntimeException e) {
                            Slog.w(ActivityManagerService.TAG,
                                    "Unable to send startActivity intent", e);
                        }
                        break;
                    case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
                        key.activity.task.stack.sendActivityResultLocked(-1, key.activity,
                                key.who, key.requestCode, code, finalIntent);
                        break;
                    case ActivityManager.INTENT_SENDER_BROADCAST:
                        try {
                            // If a completion callback has been requested, require
                            // that the broadcast be delivered synchronously
                            owner.broadcastIntentInPackage(key.packageName, uid,
                                    finalIntent, resolvedType,
                                    finishedReceiver, code, null, null,
                                requiredPermission, (finishedReceiver != null), false, userId);
                            sendFinish = false;
                        } catch (RuntimeException e) {
                            Slog.w(ActivityManagerService.TAG,
                                    "Unable to send startActivity intent", e);
                        }
                        break;
                    case ActivityManager.INTENT_SENDER_SERVICE:
                        try {
                            owner.startServiceInPackage(uid,
                                    finalIntent, resolvedType, userId);
                        } catch (RuntimeException e) {
                            Slog.w(ActivityManagerService.TAG,
                                    "Unable to send startService intent", e);
                        }
                        break;
                }

                if (sendFinish) {
                    try {
                        finishedReceiver.performReceive(new Intent(finalIntent), 0,
                                null, null, false, false, key.userId);
                    } catch (RemoteException e) {
                    }
                }

                Binder.restoreCallingIdentity(origId);

                return 0;
            }
        }
        return ActivityManager.START_CANCELED;
    }

其实写的这么长,我们最终只有这么一句有用:

owner.startActivityInPackage(uid, key.packageName, finalIntent,
                                        resolvedType, resultTo, resultWho, requestCode, 0,
                                        options, userId, container, null);

这里的owner又是指AMS,我们回到AMS去看看,又是调用了什么:

final int startActivityInPackage(int uid, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo,
            String resultWho, int requestCode, int startFlags, Bundle options, int userId,
            IActivityContainer container, TaskRecord inTask) {

        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, ALLOW_FULL_ONLY, "startActivityInPackage", null);

        // TODO: Switch to user app stacks here.
        int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                null, null, null, options, userId, container, inTask);
        return ret;
    }

看到 mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent,resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,null, null, null, options, userId, container, inTask);
这个函数,我,恍然大悟,这不就是Activity启动流程中的一部分吗,通过Activity监听器来执行在Activity在任务栈中启动过程。

至此PendingIntent是如何启动四大组件的Activity就分析完毕了。

流程图

PendIntent工作流程

感谢任玉刚大神的android开发探索艺术,以及下面这位大神
PendingIntent的工作原理

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值