Android ActivityManagerService(AMS)的Activity管理

對於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)的,不過通常我們都是調用一個參數的,下面是一個參數的實現:
[email protected]

@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因此這裏走第一個分支:
[email protected]

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實現:
[email protected]

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實現:
[email protected]

@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:
[email protected]

@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獲得到的。
[email protected]

@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,這個方法比較長,我們分段來分析:
[email protected]

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的實現,由於這個函數比較長,我們就只關注重點部分的操作,同樣的我們分步分析:
[email protected]

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方法的處理邏輯。
[email protected]

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:
[email protected]

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這個方法,這個方法比較長,這裏我們分段分析。
[email protected]

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方法來啓動相應進程:
[email protected]

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的啓動:
[email protected]

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這步操作了,我們看下這個方法的實現:
[email protected]

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的啓動過程:
這裏寫圖片描述
如果圖片太小看不清楚的話,你可以右擊選擇獨立窗口打開這張圖片,或者直接下載這張圖片,就可以放大查看了。

發佈了89 篇原創文章 · 獲贊 110 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章