码迷,mamicode.com
首页 > 移动开发 > 详细

Android ActivityManagerService(AMS)的Activity管理

时间:2016-07-11 12:35:31      阅读:521      评论:0      收藏:0      [点我收藏+]

标签:

对于AMS来讲,Activity管理是它的核心工作,前面两篇文章都是讲AMS的启动流程和进程的管理,这两篇文章其实是为本文做铺垫的,只有理解了前面两篇文章才能更好地理解AMS的activity管理。在谈到Activity的管理的时候,就不得不说一下Activity的启动流程,说道activity的启动流程就要说一下进程启动的问题了,前面一片文章中我们已经分析了AMS的进程管理,这里需要补充的一点就是在android中并没有针对app开放进程的启动接口,只是在启动activity或者service等组件的时候,我们的AMS会根据需要来启动相应的进程。
好了,下面我们开始分析AMS的activity的启动流程吧。

AMS的activity的启动流程

Activity的启动是从app端开始的,在AMS实际启动完成后结束的,这里就涉及到了Binder的C/S通讯,因此这里我们分为两个部分分析:客户端和服务端的实现。

activity启动之客户端

这里我们以在app中通过调用activity的startActivity方法启动目标activity来分析一个典型的activity启动流程。首先我们需要看一下Activity的startActivity方法的实现,Activity的startActivity实现了多态,一共两个实现:一个参数(intent)的,两个参数的(一个intent和一个bundle)的,不过通常我们都是调用一个参数的,下面是一个参数的实现:
startActivity@Activity.java

@Override
public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}

可以看到这里还是调用了两个参数的:

@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        // Note we want to go through this call for compatibility with
        // applications that may have overridden the method.
        startActivityForResult(intent, -1);
    }
}

我们发现这里调用了startActivityForResult方法,这个方法根据option的不同调用startActivityForResult方法时参数不一样,我们前面给的option参数是null因此这里走第一个分支:
startActivityForResult@Activity.java

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
    if (mParent == null) {
        // 通过mInstrumentation的execStartActivity实际启动activity
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        // ar表示activity启动结果,如果结果就调用ActivityThread的sendActivityResult通知启动结果,这里会回调到请求activity的onActivityResult方法
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        if (requestCode >= 0) {
            // If this start is requesting a result, we can avoid making
            // the activity visible until the result is received.  Setting
            // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
            // activity hidden during this time, to avoid flickering.
            // This can only be done when a result is requested because
            // that guarantees we will get information back when the
            // activity is finished, no matter what happens to it.
            mStartedActivity = true;
        }

        cancelInputsAndStartExitTransition(options);
        // TODO Consider clearing/flushing other event sources and events for child windows.
    } else {
        if (options != null) {
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            // Note we want to go through this method for compatibility with
            // existing applications that may have overridden it.
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}

这里的关键就是通过mInstrumentation的execStartActivity实际启动activity部分了,我们看下Instrumentation的execStartActivity实现:
execStartActivity@Instrumentation.java

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    Uri referrer = target != null ? target.onProvideReferrer() : null;
    if (referrer != null) {
        intent.putExtra(Intent.EXTRA_REFERRER, referrer);
    }
    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i=0; i<N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                if (am.match(who, null, intent)) {
                    am.mHits++;
                    if (am.isBlocking()) {
                        return requestCode >= 0 ? am.getResult() : null;
                    }
                    break;
                }
            }
        }
    }
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess();
        // 通过调用ActivityManagerNative的startActivity来实际启动activity
        int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

这里我们看到execStartActivity方法最终也是通过调用ActivityManagerNative的startActivity来实际启动activity,ActivityManagerNative这个是一个Binder类,这个类提供了Binder通讯的实现用于和AMS通讯的,我们先看一下这个类的定义:

public abstract class ActivityManagerNative extends Binder implements IActivityManager

果不其然,这里继承自Binder类,并且实现了IActivityManager接口,下面我们来看下上面调用的getDefault方法的实现,看名字应该是一个单例实现:

static public IActivityManager getDefault() {
   return gDefault.get();
}

我们在看下gDefault:

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

看到这里,想必大家都明白了,这的确是一个单例实现,其中g的意思应该是global的意思。Singleton泛型类的get方法会调用create方法来创建一个实例,我们一下这里的create的实现,首先通过SM获得AMS的IBinder对象(这个对象是用来和Binder发起通讯的对象),下面我们调用了asInterface方法将IBinder对象转换成IActivityManager,以方便客户端调用IActivityManager的接口。下面是asInterface的实现:

static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }

    return new ActivityManagerProxy(obj);
}

如果你熟悉Binder的话,那么asInterface方法你应该很熟悉了,这个方法就是用来将IBinder对象转换成实际的Interface对象的,我们看到这里的原理很简单,首先查询本地有没有实现接口的服务,如果有就返回这个对象,这个时候表示操作和AMS是在同一个进程中的,显然很多情况下不是这样的,我们应该就是直接new一个ActivityManagerProxy对象,然后返回。ActivityManagerProxy类是ActivityManagerNative的一个内部类,是一个用来和AMS交互的proxy类。
现在我们明白了,我们上面的startActivity实际最后会调用到ActivityManagerProxy的startActivity中去:
startActivity@ActivityManagerProxy

public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeString(callingPackage);
    intent.writeToParcel(data, 0);
    data.writeString(resolvedType);
    data.writeStrongBinder(resultTo);
    data.writeString(resultWho);
    data.writeInt(requestCode);
    data.writeInt(startFlags);
    if (profilerInfo != null) {
        data.writeInt(1);
        profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    } else {
        data.writeInt(0);
    }
    if (options != null) {
        data.writeInt(1);
        options.writeToParcel(data, 0);
    } else {
        data.writeInt(0);
    }
    // 通过Binder的transact方法开始和AMS通讯。
    mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
    reply.readException();
    int result = reply.readInt();
    reply.recycle();
    data.recycle();
    return result;
}

我们的ActivityManagerNative是一个强大的Binder实现类,这个类是一个既面向客户有面向服务端的类,它封装了Binder的通讯实现,减少客户端和服务端通讯的困难度。刚才我们说的ActivityManagerProxy内部类是运行在客户端的一个代理,他只是提供接口,真正的实现还是在服务端的,那么ActivityManagerNative就是运行在服务端的,他就是负责从Binder监听来自proxy代理的通讯请求,使用transaction code区别不同的信息,上面我们的transaction code就是START_ACTIVITY_TRANSACTION。在继续分析server端的实现之前,我们先来梳理一下client这边的操作,整体上如下面这个时序图:
技术分享
同时我们还要弄清楚ActivityManagerNative,ActivityManagerProxy,AMS,IActivityManager以及我们后面要说道面向app的管理类:ActivityManager之间是什么关系,下面我们给出它的类图关系:
技术分享
这张图描述了上面说到的一堆类和Binder之间的关系,看代码的话感觉关系比较乱,但是看这个图的话就基本明白了。下面我们就可以分析服务端的实现了。

activity启动之服务端

上面我们分析完了activity客户端的启动流程,下面我们继续看看服务端收到客户端的启动请求后是怎么处理的。上面我们说道ActivityManagerNative是运行在服务端的,专门用来处理客户端的通讯请求的,我们知道Binder驱动在收到数据后会返回给上层,上层的Binder会回调具体接受者的onTransact方法(如果你对Binder不熟悉的话,可以先学习一下Binder的知识,这在android世界里是很核心的一个东西,如果这个东西你不懂的话,那么android的大门永远你都进不了),下面我们看下ActivityManagerNative的onTransact实现:
onTransact@ActivityManagerNative.java

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
    switch (code) {
    case START_ACTIVITY_TRANSACTION:
    {
        // 读取客户端的数据
        data.enforceInterface(IActivityManager.descriptor);
        IBinder b = data.readStrongBinder();
        IApplicationThread app = ApplicationThreadNative.asInterface(b);
        String callingPackage = data.readString();
        Intent intent = Intent.CREATOR.createFromParcel(data);
        String resolvedType = data.readString();
        IBinder resultTo = data.readStrongBinder();
        String resultWho = data.readString();
        int requestCode = data.readInt();
        int startFlags = data.readInt();
        ProfilerInfo profilerInfo = data.readInt() != 0
                ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
        Bundle options = data.readInt() != 0
                ? Bundle.CREATOR.createFromParcel(data) : null;
        // 现在,数据读取完毕了,需要启动activity,调用startActivity实现
        int result = startActivity(app, callingPackage, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
        // 回写执行结果,通知客户端
        reply.writeNoException();
        reply.writeInt(result);
        return true;
    }
    ......(省略其他code的处理,我们现在只关心activity启动的code)

这里我们调用了startActivity方法来启动activity,这个方法在AMS中实现的,因为ActivityManagerNative是一个抽象类没有实现,而AMS继承自ActivityManagerNative。我们看一下AMS中的startActivity:
startActivity@ActivityManagerService.java

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
        resultWho, requestCode, startFlags, profilerInfo, options,
        UserHandle.getCallingUserId());
}

这里的startActivity是一个包装方法,它实际调用了startActivityAsUser方法,添加了一个参数UserHandle.getCallingUserId(),这个参数是通过Binder获取调用者的UID获得到的。
startActivityAsUser@ActivityManagerService.java

@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
    // 判断是不是一个独立的进程,独立进程是不允许调用startActivity方法的
    enforceNotIsolatedCaller("startActivity");
    // 判断当前UID是否允许启动activity
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
            false, ALLOW_FULL_ONLY, "startActivity", null);
    // TODO: Switch to user app stacks here.
    // 调用ActivityStackSupervisor的startActivityMayWait方法启动activity
    return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, options, false, userId, null, null);
}

上面的代码首先进行安全检查,如果是独立进程就不允许启动activity,所谓的独立进程就是使用android:isolatedProcess标记的进程,该进程与系统其他部分隔离,且没有自己的权限。 与其通讯的唯一手段就是通过 Service API (绑定和启动)。接下来就是判断当前的UID是否有权限,如果安全检查通过的话,那么会调用ActivityStackSupervisor的startActivityMayWait方法启动activity,这个方法比较长,我们分段来分析:
startActivityMayWait@ActivityStackSupervisor.java

final int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
        Bundle options, boolean ignoreTargetSecurity, int userId,
        IActivityContainer iContainer, TaskRecord inTask) {
    // Refuse possible leaked file descriptors
    if (intent != null && intent.hasFileDescriptors()) {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }

    // 获得处理该intent的组件,
    boolean componentSpecified = intent.getComponent() != null;

    // Don‘t modify the client‘s object!
    intent = new Intent(intent);

    // Collect information about the target of the Intent.
    // 解析intent中的目标信息
    ActivityInfo aInfo =
            resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);

这里主要是通过resolveActivity来解析intent中包含的目标信息,存储在ActivityInfo对象当中,resolveActivity方法会会通过packageManagerService来解析当前intent包含的目标信息。
接下来的操作全部都是原子操作,我们继续看这个原子操作内部的代码:

if (container != null && container.mParentActivity != null &&
                    container.mParentActivity.state != RESUMED) {
    // Cannot start a child activity if the parent is not resumed.
    return ActivityManager.START_CANCELED;
}

这里是一个判断,意思是如果启动目标activity的请求activity还没有resume的话,那么它是不能启动一个新的activity的,也就是说如果一个activity还没有启动完成,那么它是不能启动一个新的activity的。

final int realCallingPid = Binder.getCallingPid();
final int realCallingUid = Binder.getCallingUid();
int callingPid;
if (callingUid >= 0) {
    callingPid = -1;
} else if (caller == null) {
    callingPid = realCallingPid;
    callingUid = realCallingUid;
} else {
    callingPid = callingUid = -1;
}

这里的操作比较简单,通过Binder获得caller的pid和uid,然后给callingPid和callingUid赋值,我们前面你传递进来的callingUid是-1,并且caller不为空,因此我们走最后一个分支,也就是callingPid和callingUid都是-1。

if (aInfo != null &&
                    (aInfo.applicationInfo.privateFlags
                            &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
   // This may be a heavy-weight process!  Check to see if we already
   // have another, different heavy-weight process running.
   if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
       if (mService.mHeavyWeightProcess != null &&
               (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
               !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
           int appCallingUid = callingUid;
           if (caller != null) {
               ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
               if (callerApp != null) {
                   appCallingUid = callerApp.info.uid;
               } else {
                   Slog.w(TAG, "Unable to find app for caller " + caller
                         + " (pid=" + callingPid + ") when starting: "
                         + intent.toString());
                   ActivityOptions.abort(options);
                   return ActivityManager.START_PERMISSION_DENIED;
               }
           }

上面的代码就是判断目标activity进程是不是重量级进程,如果当前系统中已经存在的重量级进程不是将要启动的这个,那么就要给intent重新赋值。
接下来的工作就是通过调用startActivityLocked方法来进一步完成启动工作,后面的outResult因为我们给的是null,因此不会执行。
现在我们来详细分析一下startActivityLocked的实现,由于这个函数比较长,我们就只关注重点部分的操作,同样的我们分步分析:
startActivityLocked@ActivityStackSupervisor.java

ProcessRecord callerApp = null;
if (caller != null) {
    callerApp = mService.getRecordForAppLocked(caller);
    if (callerApp != null) {
        callingPid = callerApp.pid;
        callingUid = callerApp.info.uid;
    } else {
        Slog.w(TAG, "Unable to find app for caller " + caller
              + " (pid=" + callingPid + ") when starting: "
              + intent.toString());
        err = ActivityManager.START_PERMISSION_DENIED;
    }
}

首先通过判断caller是不是为空确定调用者本身进程是不是存在的,否则就直接返回START_PERMISSION_DENIED,表示操作失败。这种情况是有可能会发生的,比如调用者被意外杀死,或者发生操作退出等等。

if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
    // Transfer the result target from the source activity to the new
    // one being started, including any failures.
    if (requestCode >= 0) {
        ActivityOptions.abort(options);
        return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
    }
    resultRecord = sourceRecord.resultTo;
    if (resultRecord != null && !resultRecord.isInStackLocked()) {
        resultRecord = null;
    }
    resultWho = sourceRecord.resultWho;
    requestCode = sourceRecord.requestCode;
    sourceRecord.resultTo = null;
    if (resultRecord != null) {
        resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
    }
    if (sourceRecord.launchedFromUid == callingUid) {
        // The new activity is being launched from the same uid as the previous
        // activity in the flow, and asking to forward its result back to the
        // previous.  In this case the activity is serving as a trampoline between
        // the two, so we also want to update its launchedFromPackage to be the
        // same as the previous activity.  Note that this is safe, since we know
        // these two packages come from the same uid; the caller could just as
        // well have supplied that same package name itself.  This specifially
        // deals with the case of an intent picker/chooser being launched in the app
        // flow to redirect to an activity picked by the user, where we want the final
        // activity to consider it to have been launched by the previous app activity.
        callingPackage = sourceRecord.launchedFromPackage;
    }
}

这段代码是处理FLAG_ACTIVITY_FORWARD_RESULT标识的部分,FLAG_ACTIVITY_FORWARD_RESULT标识是一个跨越式传递的标记。比如Activity1启动了Activity2,但是Activity2启动Activity3的时候使用了这个标记,那么Activity3调用setResult的时候,result并不会想一般情况中的那样传递给Activity2,而是回传给Activity1.为了达到这个目的,只要caller修改为Activity1就可以了,上面的代码就是做这个工作的:替换caller。同时,因为在这个标记下,Activity2已经把result的目标对象设置为Activity1,因此它自身就不能再通过startActivityForResult来启动Activity3,否则就会报错:START_FORWARD_AND_REQUEST_CONFLICT。
接下来就会检查目标intent中的component是否为空,如果为空的话,就说明这个intent当目前为止还没有相应的class来handle它,这个时候需要退出;同样的,如果通过PMS解析还不能找到对应的类来处理的话,也是要终止操作的:

if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
    // We couldn‘t find a class that can handle the given Intent.
    // That‘s the end of that!
    err = ActivityManager.START_INTENT_NOT_RESOLVED;
}

if (err == ActivityManager.START_SUCCESS && aInfo == null) {
    // We couldn‘t find the specific class specified in the Intent.
    // Also the end of the line.
    err = ActivityManager.START_CLASS_NOT_FOUND;
}

接下来就执行权限判断,看下调用者是不是有权限启动任何activity:

boolean abort = false;
final int startAnyPerm = mService.checkPermission(
        START_ANY_ACTIVITY, callingPid, callingUid);

if (startAnyPerm != PERMISSION_GRANTED) {
    final int componentRestriction = getComponentRestrictionForCallingPackage(
            aInfo, callingPackage, callingPid, callingUid, ignoreTargetSecurity);
    final int actionRestriction = getActionRestrictionForCallingPackage(
            intent.getAction(), callingPackage, callingPid, callingUid);

    if (componentRestriction == ACTIVITY_RESTRICTION_PERMISSION
            || actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
        if (resultRecord != null) {
            resultStack.sendActivityResultLocked(-1,
                    resultRecord, resultWho, requestCode,
                    Activity.RESULT_CANCELED, null);
        }
        String msg;
        if (actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
            msg = "Permission Denial: starting " + intent.toString()
                    + " from " + callerApp + " (pid=" + callingPid
                    + ", uid=" + callingUid + ")" + " with revoked permission "
                    + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction());
        } else if (!aInfo.exported) {
            msg = "Permission Denial: starting " + intent.toString()
                    + " from " + callerApp + " (pid=" + callingPid
                    + ", uid=" + callingUid + ")"
                    + " not exported from uid " + aInfo.applicationInfo.uid;
        } else {
            msg = "Permission Denial: starting " + intent.toString()
                    + " from " + callerApp + " (pid=" + callingPid
                    + ", uid=" + callingUid + ")"
                    + " requires " + aInfo.permission;
        }
        Slog.w(TAG, msg);
        throw new SecurityException(msg);
    }

    if (actionRestriction == ACTIVITY_RESTRICTION_APPOP) {
        String message = "Appop Denial: starting " + intent.toString()
                + " from " + callerApp + " (pid=" + callingPid
                + ", uid=" + callingUid + ")"
                + " requires " + AppOpsManager.permissionToOp(
                        ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction()));
        Slog.w(TAG, message);
        abort = true;
    } else if (componentRestriction == ACTIVITY_RESTRICTION_APPOP) {
        String message = "Appop Denial: starting " + intent.toString()
                + " from " + callerApp + " (pid=" + callingPid
                + ", uid=" + callingUid + ")"
                + " requires appop " + AppOpsManager.permissionToOp(aInfo.permission);
        Slog.w(TAG, message);
        abort = true;
    }
}

如果权限不允许的话,就继续看是不是有权限启动intent中对应的组件(此时是activity)和目标app中对这个组件的权限是不是满足,如果两个都不满足就直接抛出SecurityException异常,终止操作。如果是目标进程不允许当前的操作的话,那么就把abort置为true。
我们继续看下面的代码:

abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
        callingPid, resolvedType, aInfo.applicationInfo);

这段代码通过intent防火墙来检查该intent是否可通过,intent防火墙是android 4.4.2中加入的一个安全机制,这个机制设计的目的就是要检查android中的intent的权限问题,可以通过配置位于/data/system/ifw/下的策略文件来阻止一些intent的发送。策略文件是一个xml文件,这个文件的格式基本如下:

<rules>
  <activity block="[true/false]" log="[true/false]" >
    <intent-filter >
      <path literal="[literal]" prefix="[prefix]" sglob="[sglob]" />
      <auth host="[host]" port="[port]" />
      <ssp literal="[literal]" prefix="[prefix]" sglob="[sglob]" />
      <scheme name="[name]" />
      <type name="[name]" />
      <cat name="[category]" />
      <action name="[action]" />
    </intent-filter>
    <component-filter name="[component]" />
  </activity>
</rules>

更多关于intent防火墙的信息,可以查看:
http://www.cis.syr.edu/~wedu/android/IntentFirewall/
我们看到上面intent防火墙检查代码会把最后的结果和abort变量或运算,abort变量就表示着activity启动是不是需要继续:

if (abort) {
    if (resultRecord != null) {
        resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
                Activity.RESULT_CANCELED, null);
    }
    // We pretend to the caller that it was really started, but
    // they will just get a cancel result.
    ActivityOptions.abort(options);
    return ActivityManager.START_SUCCESS;
}

这里如果需要结果就直接就发送一个RESULT_CANCELED结果,然后直接返回。否则就看下面的代码:

ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
        intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
        requestCode, componentSpecified, voiceSession != null, this, container, options);
if (outActivity != null) {
    outActivity[0] = r;
}

if (r.appTimeTracker == null && sourceRecord != null) {
    // If the caller didn‘t specify an explicit time tracker, we want to continue
    // tracking under any it has.
    r.appTimeTracker = sourceRecord.appTimeTracker;
}

这段代码主要就是生成一个ActivityRecord对象r,记录当前的各项判断结果。

final ActivityStack stack = mFocusedStack;
if (voiceSession == null && (stack.mResumedActivity == null
        || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
    if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
            realCallingPid, realCallingUid, "Activity start")) {
        PendingActivityLaunch pal =
                new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
        mPendingActivityLaunches.add(pal);
        ActivityOptions.abort(options);
        return ActivityManager.START_SWITCHES_CANCELED;
    }
}

这里检查启动activity是否会引起进程切换,如果需要的话,还要检查Android系统目前是否允许切换。什么情况不允许切换呢?最常见的例子就是打电话的时候,如果是位于通话界面的话,可以通过AMS的stopAppSwitches来禁止切换掉当前进程,电话结束后再调用resumeAppSwitches来恢复切换。需要注意的是,这个接口一般的普通的app是不能调用的,因此这个操作一定是系统app会操作的。

doPendingActivityLaunchesLocked(false);

err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
        startFlags, true, options, inTask);

如果允许进程切换的话,这时需要调用doPendingActivityLaunchesLocked方法先处理所有pending状态的activity,然后再调用startActivityUncheckedLocked方法继续处理当前方法继续处理当前的activity。处于pending状态的activity也是通过startActivityUncheckedLocked实现的,现在我们来分析一下这个方法,这个方法比较长,我们分段分析:

final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;

int launchFlags = intent.getFlags();

这是前期准备阶段,主要是获取activity的启动模式和启动标记信息,关于activity的启动模式可以参考我的博客Android升华之路——activity的启动模式关于activity启动标记,可以参考google的android api文档中的描述:
https://developer.android.com/reference/android/content/Intent.html
这个文档中主要讲解了所有的android中会用的启动flag,我们这里只关心activity启动相关的标记位,这些标记是以“FLAG_ACTIVITY”开头的,大家可以可以看看。如果大家对E文没有感觉的话,可以看热心网友翻译的(翻译中有个人理解):
http://blog.csdn.net/javensun/article/details/8700265
其中我们需要重点说明的几个标记位如下:
FLAG_ACTIVITY_NEW_DOCUMENT:我们的代码下面就要用到的,这个标记官网描述如下:
技术分享
从描述中可以看出,这个标记位最好和documentLaunchMode启动一起使用,那么什么是 documentLaunchMode呢?大家可以查看这个官网链接:
https://developer.android.com/reference/android/R.attr.html#documentLaunchMode
这里就不详细解释了。大家只要知道这个标记是在android 5.0中引入的,专门用于控制处于overview screen的任务总览使用的,overview screen是在android 5.0界面的导航栏最右边的方形按钮按下会弹出的界面。这个界面将最近的任务以快照的形式呈现出来。
FLAG_ACTIVITY_NEW_TASK:这个是single task对应的标记位,表示activity启动后需要放在一个新的task栈中
剩下的标记位大家最好在分析代码的时候,一边查看api手册。
继续我们上面的代码分析,上面的代码获取了当前activity的启动模式和标记位,以方便后面的处理。Android中的众多启动标记位和启动模式都是在这个方法中处理的。

if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
                (launchSingleInstance || launchSingleTask)) {
    // We have a conflict between the Intent and the Activity manifest, manifest wins.
    Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
            "\"singleInstance\" or \"singleTask\"");
    launchFlags &=
            ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
} else {
    switch (r.info.documentLaunchMode) {
        case ActivityInfo.DOCUMENT_LAUNCH_NONE:
            break;
        case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
            break;
        case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
            break;
        case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
            launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
            break;
    }
}

这段代码就是处理和FLAG_ACTIVITY_NEW_DOCUMENT相关的,我们知道android中的activity启动标记位既可以通过intent附加,也可以在AndroidManifest中指定,但是如果intent和AndroidManifest中的冲突怎么办呢?这段代码的开始就给出的处理策略:如果冲突就依据AndroidManifest的。如果不冲突的话,那么就获得相应的具体的documentLaunchMode,documentLaunchMode一共有以下4种:
技术分享
这里就对这4种模式进行处理。

final boolean launchTaskBehind = r.mLaunchTaskBehind
                && !launchSingleTask && !launchSingleInstance
                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;

下面主要就是处理FLAG_ACTIVITY_NEW_TASK时的result值回传问题:

if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0
        && r.resultTo.task.stack != null) {
    // For whatever reason this activity is being launched into a new
    // task...  yet the caller has requested a result back.  Well, that
    // is pretty messed up, so instead immediately send back a cancel
    // and let the new task continue launched as normal without a
    // dependency on its originator.
    Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
    r.resultTo.task.stack.sendActivityResultLocked(-1,
            r.resultTo, r.resultWho, r.requestCode,
            Activity.RESULT_CANCELED, null);
    r.resultTo = null;
}

这里的注释写的很清楚了,就是说在使用了FLAG_ACTIVITY_NEW_TASK的情况下如果使用startActivityForResult方法启动activity的话,那么得到的result将永远是RESULT_CANCELED。这个在intent的api文档中也有说明。

// If we are actually going to launch in to a new task, there are some cases where
// we further want to do multiple task.
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
    if (launchTaskBehind
            || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
        launchFlags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
    }
}

这段代码是处理FLAG_ACTIVITY_MULTIPLE_TASK的,这个标记通常都会与FLAG_ACTIVITY_NEW_TASK或者FLAG_ACTIVITY_NEW_DOCUMENT一起使用。FLAG_ACTIVITY_MULTIPLE_TASK意思是一个activity可以运行在多个task中,启动的时候直接创建新的task,然后把activity放进去,而不是查找是不是有一个已经存在的task。google不建议app开发者主动使用这个标记。

// We‘ll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
        "startActivity() => mUserLeaving=" + mUserLeaving);

// If the caller has asked not to resume at this point, we make note
// of this in the record so that we can skip it when trying to find
// the top running activity.
if (!doResume) {
    r.delayedResume = true;
}

这段代码首先处理了FLAG_ACTIVITY_NO_USER_ACTION标记,这个标记表示当前activity的启动不是用户主观要求的,可能是系统某些组件内部逻辑请求的,比如闹钟响起界面,手机电话来电界面等。然后就是如果用户指明了暂时不要resume这个activity的话,我们就把ActivityRecord中的delayedResume置为true,方便后期查找顶端运行的activity。

ActivityRecord notTop =
                (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;

这里是处理FLAG_ACTIVITY_PREVIOUS_IS_TOP的,如果设置了这个标记的话,那么notTop就是r本身,如果没有的话那就是null。FLAG_ACTIVITY_PREVIOUS_IS_TOP的含义是:当前启动的activity不被考虑是task的顶端,而启动它的前一个activity是顶端,这适合于当前activity只是执行一个很短的操作,并且很快就会销毁的情况下。

// If the onlyIfNeeded flag is set, then we can do this if the activity
// being launched is the same as the one making the call...  or, as
// a special case, if we do not know the caller then we count the
// current top activity as the caller.
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
    ActivityRecord checkedCaller = sourceRecord;
    if (checkedCaller == null) {
        checkedCaller = mFocusedStack.topRunningNonDelayedActivityLocked(notTop);
    }
    if (!checkedCaller.realActivity.equals(r.realActivity)) {
        // Caller is not the same as launcher, so always needed.
        startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
    }
}

这段代码中的注释说的很清楚,这里如果我们的startFlags中有START_FLAG_ONLY_IF_NEEDED的话,表示只在需要的情况下才会启动目标,即如果被启动的对象和调用者是同一个的时候,那么就没有必要重复操作。

// If the caller is not coming from another activity, but has given us an
// explicit task into which they would like us to launch the new activity,
// then let‘s see about doing that.
if (sourceRecord == null && inTask != null && inTask.stack != null) {
    final Intent baseIntent = inTask.getBaseIntent();
    final ActivityRecord root = inTask.getRootActivity();
    if (baseIntent == null) {
        ActivityOptions.abort(options);
        throw new IllegalArgumentException("Launching into task without base intent: "
                + inTask);
    }

    // If this task is empty, then we are adding the first activity -- it
    // determines the root, and must be launching as a NEW_TASK.
    if (launchSingleInstance || launchSingleTask) {
        if (!baseIntent.getComponent().equals(r.intent.getComponent())) {
            ActivityOptions.abort(options);
            throw new IllegalArgumentException("Trying to launch singleInstance/Task "
                    + r + " into different task " + inTask);
        }
        if (root != null) {
            ActivityOptions.abort(options);
            throw new IllegalArgumentException("Caller with inTask " + inTask
                    + " has root " + root + " but target is singleInstance/Task");
        }
    }

    // If task is empty, then adopt the interesting intent launch flags in to the
    // activity being started.
    if (root == null) {
        final int flagsOfInterest = Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
                | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
        launchFlags = (launchFlags&~flagsOfInterest)
                | (baseIntent.getFlags()&flagsOfInterest);
        intent.setFlags(launchFlags);
        inTask.setIntent(r);
        addingToTask = true;

    // If the task is not empty and the caller is asking to start it as the root
    // of a new task, then we don‘t actually want to start this on the task.  We
    // will bring the task to the front, and possibly give it a new intent.
    } else if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        addingToTask = false;

    } else {
        addingToTask = true;
    }

    reuseTask = inTask;
} else {
    inTask = null;
}

这里需要注意一下inTask这个方法参数,这个参数和android 5.0中的最近任务栏有关。android 5.0中引入了重启后恢复Task的功能,当用户从最近任务栏中启动“恢复的task”的时候,inTask是不为空的,但是这时候的sourceRecord是空的,这段代码就是处理从最近任务中启动一个activity的过程。首先判断的是查看inTask中的用于启动root activity的intent是不是为空,如果为空的话那就抛出IllegalArgumentException异常终止运行,因为没有root activity的intent整个task就不能构建了。接下来就是看当前activity的启动模式是不是single instance或者single task,如果是的话,并且是从一个不同的task中启动的话,那就抛出IllegalArgumentException,因为这两种启动模式都不能在别的task中运行。同时如果root activity不为空,那也会抛出IllegalArgumentException,因为singleInstance/Task启动的时候task中已经有root activity了。接下来如果root activity是空的话,就采用上面baseIntent中的标记位来启动目标activity,这些标记位上最近用户使用时候的标记位。
下面我们继续分析代码:

if (inTask == null) {
    if (sourceRecord == null) {
        // This activity is not being started from another...  in this
        // case we -always- start a new task.
        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
            Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                    "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        }
    } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        // The original activity who is starting us is running as a single
        // instance...  this new activity it is starting must go on its
        // own task.
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    } else if (launchSingleInstance || launchSingleTask) {
        // The activity being started is a single instance...  it always
        // gets launched into its own task.
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    }
}

这段代码是关于FLAG_ACTIVITY_NEW_TASK标记的处理,逻辑比较简单,就不赘述了。
接下来的代码是一个安全检查:

ActivityInfo newTaskInfo = null;
Intent newTaskIntent = null;
ActivityStack sourceStack;
if (sourceRecord != null) {
    if (sourceRecord.finishing) {
        // If the source is finishing, we can‘t further count it as our source.  This
        // is because the task it is associated with may now be empty and on its way out,
        // so we don‘t want to blindly throw it in to that task.  Instead we will take
        // the NEW_TASK flow and try to find a task for it. But save the task information
        // so it can be used when creating the new task.
        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
            Slog.w(TAG, "startActivity called from finishing " + sourceRecord
                    + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
            newTaskInfo = sourceRecord.info;
            newTaskIntent = sourceRecord.task.intent;
        }
        sourceRecord = null;
        sourceStack = null;
    } else {
        sourceStack = sourceRecord.task.stack;
    }
} else {
    sourceStack = null;
}

主要是检查启动它的activity是不是快要被销毁了,如果是的话那就需要启动一个新的task,从而将这个activity放到这个task中去。
下面的代码就是task查找和定位的过程:

// We may want to try to place the new activity in to an existing task.  We always
// do this if the target activity is singleTask or singleInstance; we will also do
// this if NEW_TASK has been requested, and there is not an additional qualifier telling
// us to still place it in a new task: multi task, always doc mode, or being asked to
// launch this as a new task behind the current one.
if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
        (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
        || launchSingleInstance || launchSingleTask) {
    // If bring to front is requested, and no result is requested and we have not
    // been given an explicit task to launch in to, and
    // we can find a task that was started with this same
    // component, then instead of launching bring that one to the front.
    if (inTask == null && r.resultTo == null) {
        // See if there is a task to bring to the front.  If this is
        // a SINGLE_INSTANCE activity, there can be one and only one
        // instance of it in the history, and it is always in its own
        // unique task, so we do a special search.
        ActivityRecord intentActivity = !launchSingleInstance ?
                findTaskLocked(r) : findActivityLocked(intent, r.info);
        if (intentActivity != null) {
            // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused
            // but still needs to be a lock task mode violation since the task gets
            // cleared out and the device would otherwise leave the locked task.
            if (isLockTaskModeViolation(intentActivity.task,
                    (launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
                showLockTaskToast();
                Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            if (r.task == null) {
                r.task = intentActivity.task;
            }
            if (intentActivity.task.intent == null) {
                // This task was started because of movement of
                // the activity based on affinity...  now that we
                // are actually launching it, we can assign the
                // base intent.
                intentActivity.task.setIntent(r);
            }
            targetStack = intentActivity.task.stack;
            targetStack.mLastPausedActivity = null;
            // If the target task is not in the front, then we need
            // to bring it to the front...  except...  well, with
            // SINGLE_TASK_LAUNCH it‘s not entirely clear.  We‘d like
            // to have the same behavior as if a new instance was
            // being started, which means not bringing it to the front
            // if the caller is not itself in the front.
            final ActivityStack focusStack = getFocusedStack();
            ActivityRecord curTop = (focusStack == null)
                    ? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
            boolean movedToFront = false;
            if (curTop != null && (curTop.task != intentActivity.task ||
                    curTop.task != focusStack.topTask())) {
                r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                if (sourceRecord == null || (sourceStack.topActivity() != null &&
                        sourceStack.topActivity().task == sourceRecord.task)) {
                    // We really do want to push this one into the user‘s face, right now.
                    if (launchTaskBehind && sourceRecord != null) {
                        intentActivity.setTaskToAffiliateWith(sourceRecord.task);
                    }
                    movedHome = true;
                    targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
                            options, r.appTimeTracker, "bringingFoundTaskToFront");
                    movedToFront = true;
                    if ((launchFlags &
                            (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                        // Caller wants to appear on home activity.
                        intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                    }
                    options = null;
                }
            }
            if (!movedToFront) {
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
                        + " from " + intentActivity);
                targetStack.moveToFront("intentActivityFound");
            }

            // If the caller has requested that the target task be
            // reset, then do so.
            if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
            }
            if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
                // We don‘t need to start a new activity, and
                // the client said not to do anything if that
                // is the case, so this is it!  And for paranoia, make
                // sure we have correctly resumed the top activity.
                if (doResume) {
                    resumeTopActivitiesLocked(targetStack, null, options);

                    // Make sure to notify Keyguard as well if we are not running an app
                    // transition later.
                    if (!movedToFront) {
                        notifyActivityDrawnForKeyguard();
                    }
                } else {
                    ActivityOptions.abort(options);
                }
                return ActivityManager.START_RETURN_INTENT_TO_CALLER;
            }
            if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
                // The caller has requested to completely replace any
                // existing task with its new activity.  Well that should
                // not be too hard...
                reuseTask = intentActivity.task;
                reuseTask.performClearTaskLocked();
                reuseTask.setIntent(r);
            } else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                    || launchSingleInstance || launchSingleTask) {
                // In this situation we want to remove all activities
                // from the task up to the one being started.  In most
                // cases this means we are resetting the task to its
                // initial state.
                ActivityRecord top =
                        intentActivity.task.performClearTaskLocked(r, launchFlags);
                if (top != null) {
                    if (top.frontOfTask) {
                        // Activity aliases may mean we use different
                        // intents for the top activity, so make sure
                        // the task now has the identity of the new
                        // intent.
                        top.task.setIntent(r);
                    }
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
                            r, top.task);
                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                } else {
                    // A special case: we need to start the activity because it is not
                    // currently running, and the caller has asked to clear the current
                    // task to have this activity at the top.
                    addingToTask = true;
                    // Now pretend like this activity is being started by the top of its
                    // task, so it is put in the right place.
                    sourceRecord = intentActivity;
                    TaskRecord task = sourceRecord.task;
                    if (task != null && task.stack == null) {
                        // Target stack got cleared when we all activities were removed
                        // above. Go ahead and reset it.
                        targetStack = computeStackFocus(sourceRecord, false /* newTask */);
                        targetStack.addTask(
                                task, !launchTaskBehind /* toTop */, false /* moving */);
                    }

                }
            } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
                // In this case the top activity on the task is the
                // same as the one being launched, so we take that
                // as a request to bring the task to the foreground.
                // If the top activity in the task is the root
                // activity, deliver this new intent to it if it
                // desires.
                if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
                        && intentActivity.realActivity.equals(r.realActivity)) {
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
                            intentActivity.task);
                    if (intentActivity.frontOfTask) {
                        intentActivity.task.setIntent(r);
                    }
                    intentActivity.deliverNewIntentLocked(callingUid, r.intent,
                            r.launchedFromPackage);
                } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
                    // In this case we are launching the root activity
                    // of the task, but with a different intent.  We
                    // should start a new instance on top.
                    addingToTask = true;
                    sourceRecord = intentActivity;
                }
            } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
                // In this case an activity is being launched in to an
                // existing task, without resetting that task.  This
                // is typically the situation of launching an activity
                // from a notification or shortcut.  We want to place
                // the new activity on top of the current task.
                addingToTask = true;
                sourceRecord = intentActivity;
            } else if (!intentActivity.task.rootWasReset) {
                // In this case we are launching in to an existing task
                // that has not yet been started from its front door.
                // The current task has been brought to the front.
                // Ideally, we‘d probably like to place this new task
                // at the bottom of its stack, but that‘s a little hard
                // to do with the current organization of the code so
                // for now we‘ll just drop it.
                intentActivity.task.setIntent(r);
            }
            if (!addingToTask && reuseTask == null) {
                // We didn‘t do anything...  but it was needed (a.k.a., client
                // don‘t use that intent!)  And for paranoia, make
                // sure we have correctly resumed the top activity.
                if (doResume) {
                    targetStack.resumeTopActivityLocked(null, options);
                    if (!movedToFront) {
                        // Make sure to notify Keyguard as well if we are not running an app
                        // transition later.
                        notifyActivityDrawnForKeyguard();
                    }
                } else {
                    ActivityOptions.abort(options);
                }
                return ActivityManager.START_TASK_TO_FRONT;
            }
        }
    }
}

这部分的代码就是在查找合适的已经存在的task,然后把activity放进去,如果可以的话,那就将这个activity resume。接下来的代码主要就是基于newTask是false的情况,不过也是有例外的,比如代码中设置了NEW_TASK的标记,但是经过后面的判断之后addingToTask为false,此时newTask还是为真。这里我们就不贴出代码了,大家可以自行查看,这部分的代码没有复杂的逻辑,都只是一些状态,标记的判断和处理。
我们的startActivityUncheckedLocked方法就是最后是通过ActivityStack的startActivityLocked方法实际启动了一个activity。这个方法不仅是AMS启动activity的关键,同时也是Activity后续能否再WMS中得到正常处理的关键。
startActivityLocked是启动activity的最后一站,现在我们梳理一下它的工作。
1). 首先,如果目标activity不是在新的task中启动的,也就是newTask为false的情况下,那么程序要找到目标activity位于那个老的task中,这个需要遍历mTaskHistory才能找到。找到后,如果这个task当前对用户是不可见的,那么只需要将它放到历史记录中,并且再WMS中做好注册,但是不要启动它。
2). 将这个activity放到task的最顶层,这样用户才能和它交互,代码如下:

// Slot the activity into the history stack and proceed
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
        new RuntimeException("here").fillInStackTrace());
task.addActivityToTop(r);
task.setFrontOfTask();

r.putInHistory();

3). 接下来,如果不是AMS中的第一个activity的话(numActivities() > 0),则执行切换动画,不过这也是取决于FLAG_ACTIVITY_NO_ANIMATION标记的。执行的动画类型分为两种:TRANSIT_TASK_OPEN表示启动新的task和TRANSIT_ACTIVITY_OPEN表示不启动新的task。
4). 一个activity的UI界面要想再终端屏幕上显示出来,很重要的一点就是他必须向WMS中添加token,以便于WMS在启动窗口的时候能够找到它。代码如下:

mWindowManager.addAppToken(task.mActivities.indexOf(r),
                    r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                    (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
                    r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);

5). 每一个activity可能在AndroidManifest中会指定affinity,这个属性就是指定了它想要运行的task的名称。因而如果启动了一个新的task,就需要检查是否存在对这个task同affinity的其他activity。另外,如果用户使用了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记的话,就满足了need需要了,此时需要调用resetTaskIfNeededLocked方法,保证task中目前这个activity是root。操作的代码如下:

if (newTask) {
    // Even though this activity is starting fresh, we still need
    // to reset it to make sure we apply affinities to move any
    // existing activities from other tasks in to it.
    // If the caller has requested that the target task be
    // reset, then do so.
    if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
        resetTaskIfNeededLocked(r, r);
        doShow = topRunningNonDelayedActivityLocked(null) == r;
    }
} else if (options != null && new ActivityOptions(options).getAnimationType()
        == ActivityOptions.ANIM_SCENE_TRANSITION) {
    doShow = false;
}

6). 最后调用resumeTopActivitiesLocked来恢复最上层的activity,并且pause之前的activity;这是一方面,另一方面,在activity切换的过程中还要展示切换动画,然后两个新旧activity还会向WMS分别申请和释放surface,最终完成老的activity不显示,新的activity显示的任务。
resumeTopActivitiesLocked是AMS中很多地方都会调用到的方法,主要作用是将位于栈顶的activity显示出来,这时,当前的activity(就是mResumedActivity指向的那个activity)还显示在前端。这里的操作就要将这个activity pause掉放到后端。下面我们看一下resumeTopActivitiesLocked方法的处理逻辑。
resumeTopActivitiesLocked@ActivityStackSupervisor.java

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
        Bundle targetOptions) {
    // 如果目标stack为空的话,那么就将目标栈赋值为mFocusedStack,这是正在前端和用户交互的栈
    if (targetStack == null) {
        targetStack = mFocusedStack;
    }
    // Do targetStack first.
    boolean result = false;
    // 如果目标stack是前端stack,那么就resume这个栈顶的activity
    if (isFrontStack(targetStack)) {
        result = targetStack.resumeTopActivityLocked(target, targetOptions);
    }

    // resume各个display上前端栈栈顶的activity
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);
            if (stack == targetStack) {
                // Already started above.
                continue;
            }
            if (isFrontStack(stack)) {
                stack.resumeTopActivityLocked(null);
            }
        }
    }
    return result;
}

我们看到这个方法最终还是调用ActivityStack的resumeTopActivityLocked来显示activity:
resumeTopActivityLocked@ActivityStack.java

final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
    // 如果当前正在resume顶端activity的话,那就直接返回false
    if (mStackSupervisor.inResumeTopActivity) {
        // Don‘t even start recursing.
        return false;
    }

    boolean result = false;
    try {
        // Protect against recursion.
        mStackSupervisor.inResumeTopActivity = true;
        if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
            mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
            mService.updateSleepIfNeededLocked();
        }
        // 进一步调用以显示activity
        result = resumeTopActivityInnerLocked(prev, options);
    } finally {
        mStackSupervisor.inResumeTopActivity = false;
    }
    return result;
}

上面的代码还是最后调用了resumeTopActivityInnerLocked这个方法来resume activity,下面我们开始分析一下resumeTopActivityInnerLocked这个方法,这个方法比较长,这里我们分段分析。
resumeTopActivityInnerLocked@ActivityStack.java

if (!mService.mBooting && !mService.mBooted) {
    // Not ready yet!
    return false;
}

ActivityRecord parent = mActivityContainer.mParentActivity;
if ((parent != null && parent.state != ActivityState.RESUMED) ||
        !mActivityContainer.isAttachedLocked()) {
    // Do not resume this stack if its parent is not resumed.
    // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
    return false;
}

这里的操作还是比较简单的,首先查看系统是否启动完成了,否则就直接返回。如果启动当前activity的activity本身的状态不是RESUMED的话,那么不能启动activity,直接返回false。

// Find the first activity that is not finishing.
// next就是我们需要启动的activity
final ActivityRecord next = topRunningActivityLocked(null);

// Remember how we‘ll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;

final TaskRecord prevTask = prev != null ? prev.task : null;
if (next == null) {
    // There are no more activities!
    // 当前task没有activity,则查找下一个可以显示的task
    final String reason = "noMoreActivities";
    if (!mFullscreen) {
        // Try to move focus to the next visible stack with a running activity if this
        // stack is not covering the entire screen.
        final ActivityStack stack = getNextVisibleStackLocked();
        if (adjustFocusToNextVisibleStackLocked(stack, reason)) {
            return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);
        }
    }
    // Let‘s just start up the Launcher...
    // 否则就显示home桌面
    ActivityOptions.abort(options);
    if (DEBUG_STATES) Slog.d(TAG_STATES,
            "resumeTopActivityLocked: No more activities go home");
    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    // Only resume home if on home display
    final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
            HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
    return isOnHomeDisplay() &&
            mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
}

上面的代码就是在正式启动之前的检查,我们继续看接下来的代码:

// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
            mStackSupervisor.allResumedActivitiesComplete()) {
    // Make sure we have executed any pending transitions, since there
    // should be nothing left to do at this point.
    mWindowManager.executeAppTransition();
    mNoAnimActivities.clear();
    ActivityOptions.abort(options);
    if (DEBUG_STATES) Slog.d(TAG_STATES,
            "resumeTopActivityLocked: Top activity resumed " + next);
    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    return false;
}

上面的代码会检测,如果我们要启动的activity现在就是在前台的话,那么我们就不用启动了,直接返回false。

// If we are sleeping, and there is no resumed activity, and the top
// activity is paused, well that is the state we want.
if (mService.isSleepingOrShuttingDown()
        && mLastPausedActivity == next
        && mStackSupervisor.allPausedActivitiesComplete()) {
    // Make sure we have executed any pending transitions, since there
    // should be nothing left to do at this point.
    mWindowManager.executeAppTransition();
    mNoAnimActivities.clear();
    ActivityOptions.abort(options);
    if (DEBUG_STATES) Slog.d(TAG_STATES,
            "resumeTopActivityLocked: Going to sleep and all paused");
    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    return false;
}

这里会检测,如果系统当前准备休眠或者关机,如果是的话,那么就放弃本次启动。

// The activity may be waiting for stop, but that is no longer
// appropriate for it.
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);

这里的注释也解释了,如果当前启动的activity正在等待stop,那么就放弃stop直接启动。因为现在已经没有必要将它stop了。

// If we are currently pausing an activity, then don‘t do anything
// until that is done.
if (!mStackSupervisor.allPausedActivitiesComplete()) {
   if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
           "resumeTopActivityLocked: Skip resume: some activity pausing.");
   if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
   return false;
}

如果我们当前正在pause一个activity,那么我们需要等到我们的pause动作完成了才能开始启动activity。

// We need to start pausing the current activity so the top one
// can be resumed...
boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
if (mResumedActivity != null) {
    if (DEBUG_STATES) Slog.d(TAG_STATES,
            "resumeTopActivityLocked: Pausing " + mResumedActivity);
    pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
}
if (pausing) {
    if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
            "resumeTopActivityLocked: Skip resume: need to start pausing");
    // At this point we want to put the upcoming activity‘s process
    // at the top of the LRU list, since we know we will be needing it
    // very soon and it would be a waste to let it get killed if it
    // happens to be sitting towards the end.
    if (next.app != null && next.app.thread != null) {
        mService.updateLruProcessLocked(next.app, true, null);
    }
    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    return true;
}

再启动新的activity之前,需要把当前的这个activity pause掉才行。另外如果前一个已经开始pause了,那么我们就把当前activity所在的app进程加入到LRU中去,关于这块的请参考我的博客Android ActivityManagerService(AMS)的进程管理

// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we‘re making a new activity topmost.
if (mService.isSleeping() && mLastNoHistoryActivity != null &&
       !mLastNoHistoryActivity.finishing) {
   if (DEBUG_STATES) Slog.d(TAG_STATES,
           "no-history finish of " + mLastNoHistoryActivity + " on new resume");
   requestFinishActivityLocked(mLastNoHistoryActivity.appToken, Activity.RESULT_CANCELED,
           null, "resume-no-history", false);
   mLastNoHistoryActivity = null;
}

如果当前在前台的activity是使用了FLAG_ACTIVITY_NO_HISTORY标记或者设置了noHistory属性的话,那么如果当前系统即将睡眠的话,那就将这个activity直接finish掉。

if (prev != null && prev != next) {
    if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
            && next != null && !next.nowVisible) {
        mStackSupervisor.mWaitingVisibleActivities.add(prev);
        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                "Resuming top, waiting visible to hide: " + prev);
    } else {
        // The next activity is already visible, so hide the previous
        // activity‘s windows right now so we can show the new one ASAP.
        // We only do this if the previous is finishing, which should mean
        // it is on top of the one being resumed so hiding it quickly
        // is good.  Otherwise, we want to do the normal route of allowing
        // the resumed activity to be shown so we can decide if the
        // previous should actually be hidden depending on whether the
        // new one is found to be full-screen or not.
        if (prev.finishing) {
            mWindowManager.setAppVisibility(prev.appToken, false);
            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                    "Not waiting for visible to hide: " + prev + ", waitingVisible="
                    + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                    + ", nowVisible=" + next.nowVisible);
        } else {
            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                    "Previous already visible but still waiting to hide: " + prev
                    + ", waitingVisible="
                    + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                    + ", nowVisible=" + next.nowVisible);
        }
    }
}

如果之前的一个activity没有在等待可见的列表中,也就是说此时我们的activity还不可见,那就把前一个activity加入mWaitingVisibleActivities列表;相反,如果activity已经是可以看见的状态,则需要把前一个隐藏起来。

// Launching this app‘s activity, make sure the app is no longer
// considered stopped.
try {
    AppGlobals.getPackageManager().setPackageStoppedState(
            next.packageName, false, next.userId); /* TODO: Verify if correct userid */
} catch (RemoteException e1) {
} catch (IllegalArgumentException e) {
    Slog.w(TAG, "Failed trying to unstop package "
            + next.packageName + ": " + e);
}

通过PackageManagerService将当前activity的包状态设置为非stop状态。

// We are starting up the next activity, so tell the window manager
// that the previous one will be hidden soon.  This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
if (prev != null) {
    if (prev.finishing) {
        if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                "Prepare close transition: prev=" + prev);
        if (mNoAnimActivities.contains(prev)) {
            anim = false;
            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
        } else {
            mWindowManager.prepareAppTransition(prev.task == next.task
                    ? AppTransition.TRANSIT_ACTIVITY_CLOSE
                    : AppTransition.TRANSIT_TASK_CLOSE, false);
        }
        mWindowManager.setAppWillBeHidden(prev.appToken);
        mWindowManager.setAppVisibility(prev.appToken, false);
    } else {
        if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                "Prepare open transition: prev=" + prev);
        if (mNoAnimActivities.contains(next)) {
            anim = false;
            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
        } else {
            mWindowManager.prepareAppTransition(prev.task == next.task
                    ? AppTransition.TRANSIT_ACTIVITY_OPEN
                    : next.mLaunchTaskBehind
                            ? AppTransition.TRANSIT_TASK_OPEN_BEHIND
                            : AppTransition.TRANSIT_TASK_OPEN, false);
        }
    }
    if (false) {
        mWindowManager.setAppWillBeHidden(prev.appToken);
        mWindowManager.setAppVisibility(prev.appToken, false);
    }
} else {
    if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
    if (mNoAnimActivities.contains(next)) {
        anim = false;
        mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
    } else {
        mWindowManager.prepareAppTransition(AppTransition.TRANSIT_ACTIVITY_OPEN, false);
    }
}

Bundle resumeAnimOptions = null;
if (anim) {
    ActivityOptions opts = next.getOptionsForTargetActivityLocked();
    if (opts != null) {
        resumeAnimOptions = opts.toBundle();
    }
    next.applyOptionsLocked();
} else {
    next.clearOptionsLocked();
}

这里我们通过WMS将前一个activity隐藏起来,这里通过WMS设置了一系列按照app设置的过渡动画效果。

ActivityStack lastStack = mStackSupervisor.getLastStack();
if (next.app != null && next.app.thread != null) {
    if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next);

    // This activity is now becoming visible.
    mWindowManager.setAppVisibility(next.appToken, true);

    // schedule launch ticks to collect information about slow apps.
    next.startLaunchTickingLocked();

    ActivityRecord lastResumedActivity =
            lastStack == null ? null :lastStack.mResumedActivity;
    ActivityState lastState = next.state;

    mService.updateCpuStats();

    if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next + " (in existing)");
    next.state = ActivityState.RESUMED;
    mResumedActivity = next;
    next.task.touchActiveTime();
    mRecentTasks.addLocked(next.task);
    mService.updateLruProcessLocked(next.app, true, null);
    updateLRUListLocked(next);
    mService.updateOomAdjLocked();

    // Have the window manager re-evaluate the orientation of
    // the screen based on the new activity order.
    boolean notUpdated = true;
    if (mStackSupervisor.isFrontStack(this)) {
        Configuration config = mWindowManager.updateOrientationFromAppTokens(
                mService.mConfiguration,
                next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
        if (config != null) {
            next.frozenBeforeDestroy = true;
        }
        notUpdated = !mService.updateConfigurationLocked(config, next, false, false);
    }

    if (notUpdated) {
        // The configuration update wasn‘t able to keep the existing
        // instance of the activity, and instead started a new one.
        // We should be all done, but let‘s just make sure our activity
        // is still at the top and schedule another run if something
        // weird happened.
        ActivityRecord nextNext = topRunningActivityLocked(null);
        if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
                "Activity config changed during resume: " + next
                + ", new next: " + nextNext);
        if (nextNext != next) {
            // Do over!
            mStackSupervisor.scheduleResumeTopActivities();
        }
        if (mStackSupervisor.reportResumedActivityLocked(next)) {
            mNoAnimActivities.clear();
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return true;
        }
        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return false;
    }

    try {
        // Deliver all pending results.
        ArrayList<ResultInfo> a = next.results;
        if (a != null) {
            final int N = a.size();
            if (!next.finishing && N > 0) {
                if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                        "Delivering results to " + next + ": " + a);
                next.app.thread.scheduleSendResult(next.appToken, a);
            }
        }

        if (next.newIntents != null) {
            next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
        }

        EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
                System.identityHashCode(next), next.task.taskId, next.shortComponentName);

        next.sleeping = false;
        mService.showAskCompatModeDialogLocked(next);
        next.app.pendingUiClean = true;
        next.app.forceProcessStateUpTo(mService.mTopProcessState);
        next.clearOptionsLocked();
        next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
                mService.isNextTransitionForward(), resumeAnimOptions);

        mStackSupervisor.checkReadyForSleepLocked();

        if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " + next);
    } catch (Exception e) {
        // Whoops, need to restart this activity!
        if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
                + lastState + ": " + next);
        next.state = lastState;
        if (lastStack != null) {
            lastStack.mResumedActivity = lastResumedActivity;
        }
        Slog.i(TAG, "Restarting because process died: " + next);
        if (!next.hasBeenLaunched) {
            next.hasBeenLaunched = true;
        } else  if (SHOW_APP_STARTING_PREVIEW && lastStack != null &&
                mStackSupervisor.isFrontStack(lastStack)) {
            mWindowManager.setAppStartingWindow(
                    next.appToken, next.packageName, next.theme,
                    mService.compatibilityInfoForPackageLocked(next.info.applicationInfo),
                    next.nonLocalizedLabel, next.labelRes, next.icon, next.logo,
                    next.windowFlags, null, true);
        }
        mStackSupervisor.startSpecificActivityLocked(next, true, false);
        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return true;
    }

    // From this point on, if something goes wrong there is no way
    // to recover the activity.
    try {
        next.visible = true;
        completeResumeLocked(next);
    } catch (Exception e) {
        // If any exception gets thrown, toss away this
        // activity and try the next one.
        Slog.w(TAG, "Exception thrown during resume of " + next, e);
        requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
                "resume-exception", true);
        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return true;
    }
    next.stopped = false;

} else {
    // Whoops, need to restart this activity!
    if (!next.hasBeenLaunched) {
        next.hasBeenLaunched = true;
    } else {
        if (SHOW_APP_STARTING_PREVIEW) {
            mWindowManager.setAppStartingWindow(
                    next.appToken, next.packageName, next.theme,
                    mService.compatibilityInfoForPackageLocked(
                            next.info.applicationInfo),
                    next.nonLocalizedLabel,
                    next.labelRes, next.icon, next.logo, next.windowFlags,
                    null, true);
        }
        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
    }
    if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
    mStackSupervisor.startSpecificActivityLocked(next, true, true);
}

这段代码调用WMS的方法来处理activity的显示,如果activity所在的进程的已经存在,那么只要把activity显示出来就可以了,直接回调应用的onNewIntent方法,之后调用activity的onResume;如果activity所在进程暂时不存在的话,就先调用startSpecificActivityLocked启动相应的进程。
到这里resumeTopActivityInnerLocked就基本分析完了,这个方法虽然比较长,但是没有十分复杂的逻辑,都是按照正常的启动流程在操作。上面我们提到了如果activity所在的进程不存在的话,那么我们会调用startSpecificActivityLocked方法来启动相应进程:
startSpecificActivityLocked@ActivityStackSupervisor.java

void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    // Is this activity‘s application already running?
    // 通过AMS查找进程记录,得到进程是不是已经启动并且正在运行。
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);

    r.task.stack.setLaunchTime(r);

    // 如果app == null的话,说明进程目前不存在;如果app.thread == null的话,说明进程正在启动。
    if (app != null && app.thread != null) {
        try {
            if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                    || !"android".equals(r.info.packageName)) {
                // Don‘t add this if it is a platform component that is marked
                // to run in multiple processes, because this is actually
                // part of the framework so doesn‘t make sense to track as a
                // separate apk in the process.
                app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                        mService.mProcessStats);
            }
            // 真正启动activity的地方
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }

        // If a dead object exception was thrown -- fall through to
        // restart the application.
    }

    // 程序走到这里说明进程不存在或者正在启动,因此需要先启动进程。
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

上面程序的逻辑很清楚,就是如果进程存在并且已经启动完毕,那么就直接启动activity,否则就先启动进程,然后在启动对应的activity。这里的startProcessLocked方法就是用于启动对应的进程的,关于AMS进程的启动和管理在我的Android ActivityManagerService(AMS)的进程管理这篇博客中已经有详述,这里就不赘述。
下面我们把重点放在realStartActivityLocked这个方法上,这个方法中核心就是调用了ApplicationThread的scheduleLaunchActivity方法启动activity:
scheduleLaunchActivity@ApplicationThread

// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
        ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
        CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
        int procState, Bundle state, PersistableBundle persistentState,
        List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
        boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

    updateProcessState(procState, false);

    ActivityClientRecord r = new ActivityClientRecord();

    r.token = token;
    r.ident = ident;
    r.intent = intent;
    r.referrer = referrer;
    r.voiceInteractor = voiceInteractor;
    r.activityInfo = info;
    r.compatInfo = compatInfo;
    r.state = state;
    r.persistentState = persistentState;

    r.pendingResults = pendingResults;
    r.pendingIntents = pendingNewIntents;

    r.startsNotResumed = notResumed;
    r.isForward = isForward;

    r.profilerInfo = profilerInfo;

    r.overrideConfig = overrideConfig;
    updatePendingConfiguration(curConfig);

    sendMessage(H.LAUNCH_ACTIVITY, r);
}

我们前面说过,ApplicationThread都是通过message的方式和ActivityThread通讯的,实际消息处理由ActivityThread中的Handler处理:

public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
    switch (msg.what) {
        case LAUNCH_ACTIVITY: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
            final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

            r.packageInfo = getPackageInfoNoCheck(
                    r.activityInfo.applicationInfo, r.compatInfo);
            // 处理activity的启动
            handleLaunchActivity(r, null);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        } break;

这里调用了handleLaunchActivity处理activity的启动:
handleLaunchActivity@ActivityThread.java

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();
    mSomeActivitiesChanged = true;

    if (r.profilerInfo != null) {
        mProfiler.setProfiler(r.profilerInfo);
        mProfiler.startProfiling();
    }

    // Make sure we are running with the most recent config.
    // 更新当前activity的配置(包括屏幕方向,尺寸等),保证使用最新的配置
    handleConfigurationChanged(null, null);

    if (localLOGV) Slog.v(
        TAG, "Handling launch of " + r);

    // Initialize before creating the activity
    WindowManagerGlobal.initialize();

    // 这里实际启动了activity,会回调onCreate方法
    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        // resume目标activity,会回调onResume方法
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed);

        if (!r.activity.mFinished && r.startsNotResumed) {
            // The activity manager actually wants this one to start out
            // paused, because it needs to be visible but isn‘t in the
            // foreground.  We accomplish this by going through the
            // normal startup (because activities expect to go through
            // onResume() the first time they run, before their window
            // is displayed), and then pausing it.  However, in this case
            // we do -not- need to do the full pause cycle (of freezing
            // and such) because the activity manager assumes it can just
            // retain the current state it has.
            // 将启动这个activity的activity pause,因为当前activity要启动了,需要遮住之前的activity。
            try {
                r.activity.mCalled = false;
                mInstrumentation.callActivityOnPause(r.activity);
                // We need to keep around the original state, in case
                // we need to be created again.  But we only do this
                // for pre-Honeycomb apps, which always save their state
                // when pausing, so we can not have them save their state
                // when restarting from a paused state.  For HC and later,
                // we want to (and can) let the state be saved as the normal
                // part of stopping the activity.
                if (r.isPreHoneycomb()) {
                    r.state = oldState;
                }
                if (!r.activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onPause()");
                }

            } catch (SuperNotCalledException e) {
                throw e;

            } catch (Exception e) {
                if (!mInstrumentation.onException(r.activity, e)) {
                    throw new RuntimeException(
                            "Unable to pause activity "
                            + r.intent.getComponent().toShortString()
                            + ": " + e.toString(), e);
                }
            }
            r.paused = true;
        }
    } else {
        // If there was an error, for any reason, tell the activity
        // manager to stop us.
        try {
            ActivityManagerNative.getDefault()
                .finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
        } catch (RemoteException ex) {
            // Ignore
        }
    }
}

我们看到上面主要的就是performLaunchActivity这步操作了,我们看下这个方法的实现:
performLaunchActivity@ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }

    ComponentName component = r.intent.getComponent();
    if (component == null) {
        component = r.intent.resolveActivity(
            mInitialApplication.getPackageManager());
        r.intent.setComponent(component);
    }

    if (r.activityInfo.targetActivity != null) {
        component = new ComponentName(r.activityInfo.packageName,
                r.activityInfo.targetActivity);
    }

    Activity activity = null;
    // 实例化activity对象
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
        if (localLOGV) Slog.v(
                TAG, r + ": app=" + app
                + ", appName=" + app.getPackageName()
                + ", pkg=" + r.packageInfo.getPackageName()
                + ", comp=" + r.intent.getComponent().toShortString()
                + ", dir=" + r.packageInfo.getAppDir());

        if (activity != null) {
            // 实例化context
            Context appContext = createBaseContextForActivity(r, activity);
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                    + r.activityInfo.name + " with config " + config);
            // 将activity和进程进行关系关联
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor);

            if (customIntent != null) {
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            activity.mStartedActivity = false;
            int theme = r.activityInfo.getThemeResource();
            if (theme != 0) {
                activity.setTheme(theme);
            }

            activity.mCalled = false;
            if (r.isPersistable()) {
                // 这里回调activity的onCreate方法
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            if (!activity.mCalled) {
                throw new SuperNotCalledException(
                    "Activity " + r.intent.getComponent().toShortString() +
                    " did not call through to super.onCreate()");
            }
            r.activity = activity;
            r.stopped = true;
            if (!r.activity.mFinished) {
                activity.performStart();
                r.stopped = false;
            }
            if (!r.activity.mFinished) {
                if (r.isPersistable()) {
                    // 回调OnRestoreInstanceState方法,以便恢复之前activity的状态
                    if (r.state != null || r.persistentState != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                r.persistentState);
                    }
                } else if (r.state != null) {
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
            }
            if (!r.activity.mFinished) {
                activity.mCalled = false;
                if (r.isPersistable()) {
                    // 回调OnPostCreate方法
                    mInstrumentation.callActivityOnPostCreate(activity, r.state,
                            r.persistentState);
                } else {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onPostCreate()");
                }
            }
        }
        r.paused = true;

        // 将启动这个activity的请求者记录放到mActivities中,统一调度管理
        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to start activity " + component
                + ": " + e.toString(), e);
        }
    }

    return activity;
}

这里我们看到了对activity启动初期的各种生命周期方法的回调。经过这个方法之后activity基本就创建完毕了,当时还没有显示出来,还需要在上面我们提到的handleLaunchActivity方法中继续调用handleResumeActivity去回调activity的onResume,并且做好显示前的最后准备工作才行。handleResumeActivity这个方法比较简单,大家可以自行看一下。
下面我们使用UML时序图的方式梳理一下AMS中activity的启动过程:
技术分享
如果图片太小看不清楚的话,你可以右击选择独立窗口打开这张图片,或者直接下载这张图片,就可以放大查看了。

Android ActivityManagerService(AMS)的Activity管理

标签:

原文地址:http://blog.csdn.net/baniel01/article/details/51848523

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!