Task&Activity&ActivityRecord...

1、Activity
2、Stack
3、Task :一個Task是一系列Activity的集合,這個集合是以堆棧的形式來組織的,遵循後進先出的原則。事實上,Task是一個非常複雜的概念,有興趣的讀者可以到官網http://developer.android.com/guide/topics/manifest/activity-element.html查看相關的資料。
4、ActivityRecord
5、TaskRecord ActivityRecor 中有成員變量類型爲TaskRecord
實現原理
三者之間的關係
activity for result 的實現
問題:切換或者是退出Activity的時候閃出其他頁面

startActivity() ->startActivityForResult() ->

Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, who,
                intent, requestCode, options);

上面的mMainThread是應用程序的主線程

在Instrumentation中的:
(Intrumentation用於監控系統和應用程序之間的交互)

 int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);

ActivityManagerNative
ActivityManagerService
ActivityManagerProxy
IActivityManager

ActivityManagerProxy、ActivityManagerNative都實現了IActivityManager接口
ActivityManagerNative 繼承了 Binder
ActivityManagerService 繼承了 ActivityManagerNative

最終進行startActivity是在類ActivityManagerService中,

ActivityManagerService的startActivity()中

//mMainStack是ActivityStack
mMainStack.startActivityMayWait(caller, intent, resolvedType,
                grantedUriPermissions, grantedMode, resultTo, resultWho,
                requestCode, onlyIfNeeded, debug, null, null);

ActivityStack中的startActivityMayWait()方法 調用了startActivityLocked()方法:

startActivityLocked(caller, intent, resolvedType,
                    grantedUriPermissions, grantedMode, aInfo,
                    resultTo, resultWho, requestCode, callingPid, callingUid,
                    onlyIfNeeded, componentSpecified);

ActivityManagerService是管理Activity的生命週週期的。

每個應用程序都有一個ActivityThread來表示應用程序的主進程,每個ActivityThread都包含一個ApplicationThread實例

activity啓動過程:
Step 1. 無論是通過Launcher來啓動Activity,還是通過Activity內部調用startActivity接口來啓動新的Activity,都通過Binder進程間通信進入到ActivityManagerService進程中,並且調用ActivityManagerService.startActivity接口;

Step 2. ActivityManagerService調用ActivityStack.startActivityMayWait來做準備要啓動的Activity的相關信息;

Step 3. ActivityStack通知ApplicationThread要進行Activity啓動調度了,這裏的ApplicationThread代表的是調用ActivityManagerService.startActivity接口的進程,對於通過點擊應用程序圖標的情景來說,這個進程就是Launcher了,而對於通過在Activity內部調用startActivity的情景來說,這個進程就是這個Activity所在的進程了;

Step 4. ApplicationThread不執行真正的啓動操作,它通過調用ActivityManagerService.activityPaused接口進入到ActivityManagerService進程中,看看是否需要創建新的進程來啓動Activity;

Step 5. 對於通過點擊應用程序圖標來啓動Activity的情景來說,ActivityManagerService在這一步中,會調用startProcessLocked來創建一個新的進程,而對於通過在Activity內部調用startActivity來啓動新的Activity來說,這一步是不需要執行的,因爲新的Activity就在原來的Activity所在的進程中進行啓動;

Step 6. ActivityManagerServic調用ApplicationThread.scheduleLaunchActivity接口,通知相應的進程執行啓動Activity的操作;

Step 7. ApplicationThread把這個啓動Activity的操作轉發給ActivityThread,ActivityThread通過ClassLoader導入相應的Activity類,然後把它啓動起來。

這樣,Android應用程序的Activity啓動過程就簡要介紹到這裏了,在接下來的兩篇文章中,我們將根據Activity的這兩種啓動情景,深入到應用程序框架層的源代碼裏面去,一步一步地分析它們的啓動過程:


在方法ActivityStack.startActivityMayWait()方法中:

public class ActivityStack {  

    ......  

    final int startActivityMayWait(IApplicationThread caller,  
            Intent intent, String resolvedType, Uri[] grantedUriPermissions,  
            int grantedMode, IBinder resultTo,  
            String resultWho, int requestCode, boolean onlyIfNeeded,  
            boolean debug, WaitResult outResult, Configuration config) {  

        ......  

        boolean componentSpecified = intent.getComponent() != null;  

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

        // Collect information about the target of the Intent.  
        ActivityInfo aInfo;  
        try {  
            ResolveInfo rInfo =  
                AppGlobals.getPackageManager().resolveIntent(  
                intent, resolvedType,  
                PackageManager.MATCH_DEFAULT_ONLY  
                | ActivityManagerService.STOCK_PM_FLAGS);  
            aInfo = rInfo != null ? rInfo.activityInfo : null;  
        } catch (RemoteException e) {  
            ......  
        }  

        if (aInfo != null) {  
            // Store the found target back into the intent, because now that  
            // we have it we never want to do this again.  For example, if the  
            // user navigates back to this point in the history, we should  
            // always restart the exact same activity.  
            intent.setComponent(new ComponentName(  
                aInfo.applicationInfo.packageName, aInfo.name));  
            ......  
        }  

        synchronized (mService) {  
            int callingPid;  
            int callingUid;  
            if (caller == null) {  
                ......  
            } else {  
                callingPid = callingUid = -1;  
            }  

            mConfigWillChange = config != null  
                && mService.mConfiguration.diff(config) != 0;  

            ......  

            if (mMainStack && aInfo != null &&  
                (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {  

                      ......  

            }  

            int res = startActivityLocked(caller, intent, resolvedType,  
                grantedUriPermissions, grantedMode, aInfo,  
                resultTo, resultWho, requestCode, callingPid, callingUid,  
                onlyIfNeeded, componentSpecified);  

            if (mConfigWillChange && mMainStack) {  
                ......  
            }  

            ......  

            if (outResult != null) {  
                ......  
            }  

            return res;  
        }  

    }  

    ......  

}  

上面代碼中:

 ActivityInfo aInfo;  
        try {  
            ResolveInfo rInfo =  
                AppGlobals.getPackageManager().resolveIntent(  
                intent, resolvedType,  
                PackageManager.MATCH_DEFAULT_ONLY  
                | ActivityManagerService.STOCK_PM_FLAGS);  
            aInfo = rInfo != null ? rInfo.activityInfo : null;  
        } catch (RemoteException e) {  
            ......  
        }  

是將Intent中的信息解析出來得到Activity的相關信息保存在aInfo中

在方法startActivityLocked()中:

 final int startActivityLocked(IApplicationThread caller,  
            Intent intent, String resolvedType,  
            Uri[] grantedUriPermissions,  
            int grantedMode, ActivityInfo aInfo, IBinder resultTo,  
                String resultWho, int requestCode,  
            int callingPid, int callingUid, boolean onlyIfNeeded,  
            boolean componentSpecified) {  
            int err = START_SUCCESS;  

        ProcessRecord callerApp = null;  
        if (caller != null) {  
            callerApp = mService.getRecordForAppLocked(caller);  
            if (callerApp != null) {  
                callingPid = callerApp.pid;  
                callingUid = callerApp.info.uid;  
            } else {  
                ......  
            }  
        }  

        ......  

        ActivityRecord sourceRecord = null;  
        ActivityRecord resultRecord = null;  
        if (resultTo != null) {  
            int index = indexOfTokenLocked(resultTo);  

            ......  

            if (index >= 0) {  
                sourceRecord = (ActivityRecord)mHistory.get(index);  
                if (requestCode >= 0 && !sourceRecord.finishing) {  
                    ......  
                }  
            }  
        }  

        int launchFlags = intent.getFlags();  

        if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0  
            && sourceRecord != null) {  
            ......  
        }  

        if (err == START_SUCCESS && intent.getComponent() == null) {  
            ......  
        }  

        if (err == START_SUCCESS && aInfo == null) {  
            ......  
        }  

        if (err != START_SUCCESS) {  
            ......  
        }  

        ......  

        ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,  
            intent, resolvedType, aInfo, mService.mConfiguration,  
            resultRecord, resultWho, requestCode, componentSpecified);  

        ......  

        return startActivityUncheckedLocked(r, sourceRecord,  
            grantedUriPermissions, grantedMode, onlyIfNeeded, true);  
    }  

sourceRecord = (ActivityRecord)mHistory.get(index);

 ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
                intent, resolvedType, aInfo, mService.mConfiguration,
                resultRecord, resultWho, requestCode, componentSpecified);

即將要啓動的Activity的相關信息,並保存在r變量中(r變量是ActivityRecord)
從參數caller得到調用者的進程信息,並保存在callApp中
參數resultTo是Launcher這個Activity裏面的一個Binder對象,通過它可以獲得Launcher這個Activity的相關信息,保存在sourceRecord變量中。


launcher也是一個Activity,
他的方法startActivitySafely():
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 會在一個新的task中加載Activity。

    // Refuse possible leaked file descriptors
    if (intent != null && intent.hasFileDescriptors()) {
        throw new IllegalArgumentException("File descriptors passed in 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.
    ActivityInfo aInfo;
    try {
        ResolveInfo rInfo =
            AppGlobals.getPackageManager().resolveIntent(
                    intent, resolvedType,
                    PackageManager.MATCH_DEFAULT_ONLY
                    | ActivityManagerService.STOCK_PM_FLAGS);
        aInfo = rInfo != null ? rInfo.activityInfo : null;
    } catch (RemoteException e) {
        aInfo = null;
    }

    if (aInfo != null) {
        // Store the found target back into the intent, because now that
        // we have it we never want to do this again.  For example, if the
        // user navigates back to this point in the history, we should
        // always restart the exact same activity.
        intent.setComponent(new ComponentName(
                aInfo.applicationInfo.packageName, aInfo.name));

        // Don't debug things in the system process
        if (debug) {
            if (!aInfo.processName.equals("system")) {
                mService.setDebugApp(aInfo.processName, true, false);
            }
        }
    }

    synchronized (mService) {
        int callingPid;
        int callingUid;
        if (caller == null) {
            callingPid = Binder.getCallingPid();
            callingUid = Binder.getCallingUid();
        } else {
            callingPid = callingUid = -1;
        }

        mConfigWillChange = config != null
                && mService.mConfiguration.diff(config) != 0;
        if (DEBUG_CONFIGURATION) Slog.v(TAG,
                "Starting activity when config will change = " + mConfigWillChange);

        final long origId = Binder.clearCallingIdentity();

        if (mMainStack && aInfo != null &&
                (aInfo.applicationInfo.flags&ApplicationInfo.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 realCallingPid = callingPid;
                    int realCallingUid = callingUid;
                    if (caller != null) {
                        ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
                        if (callerApp != null) {
                            realCallingPid = callerApp.pid;
                            realCallingUid = callerApp.info.uid;
                        } else {
                            Slog.w(TAG, "Unable to find app for caller " + caller
                                  + " (pid=" + realCallingPid + ") when starting: "
                                  + intent.toString());
                            return START_PERMISSION_DENIED;
                        }
                    }

                    IIntentSender target = mService.getIntentSenderLocked(
                            IActivityManager.INTENT_SENDER_ACTIVITY, "android",
                            realCallingUid, null, null, 0, intent,
                            resolvedType, PendingIntent.FLAG_CANCEL_CURRENT
                            | PendingIntent.FLAG_ONE_SHOT);

                    Intent newIntent = new Intent();
                    if (requestCode >= 0) {
                        // Caller is requesting a result.
                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
                    }
                    newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
                            new IntentSender(target));
                    if (mService.mHeavyWeightProcess.activities.size() > 0) {
                        ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
                                hist.packageName);
                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
                                hist.task.taskId);
                    }
                    newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
                            aInfo.packageName);
                    newIntent.setFlags(intent.getFlags());
                    newIntent.setClassName("android",
                            HeavyWeightSwitcherActivity.class.getName());
                    intent = newIntent;
                    resolvedType = null;
                    caller = null;
                    callingUid = Binder.getCallingUid();
                    callingPid = Binder.getCallingPid();
                    componentSpecified = true;
                    try {
                        ResolveInfo rInfo =
                            AppGlobals.getPackageManager().resolveIntent(
                                    intent, null,
                                    PackageManager.MATCH_DEFAULT_ONLY
                                    | ActivityManagerService.STOCK_PM_FLAGS);
                        aInfo = rInfo != null ? rInfo.activityInfo : null;
                    } catch (RemoteException e) {
                        aInfo = null;
                    }
                }
            }
        }

        int res = startActivityLocked(caller, intent, resolvedType,
                grantedUriPermissions, grantedMode, aInfo,
                resultTo, resultWho, requestCode, callingPid, callingUid,
                onlyIfNeeded, componentSpecified);

        if (mConfigWillChange && mMainStack) {
            // If the caller also wants to switch to a new configuration,
            // do so now.  This allows a clean switch, as we are waiting
            // for the current activity to pause (so we will not destroy
            // it), and have not yet started the next activity.
            mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                    "updateConfiguration()");
            mConfigWillChange = false;
            if (DEBUG_CONFIGURATION) Slog.v(TAG,
                    "Updating to new configuration after starting activity.");
            mService.updateConfigurationLocked(config, null);
        }

        Binder.restoreCallingIdentity(origId);

        if (outResult != null) {
            outResult.result = res;
            if (res == IActivityManager.START_SUCCESS) {
                mWaitingActivityLaunched.add(outResult);
                do {
                    try {
                        mService.wait();
                    } catch (InterruptedException e) {
                    }
                } while (!outResult.timeout && outResult.who == null);
            } else if (res == IActivityManager.START_TASK_TO_FRONT) {
                ActivityRecord r = this.topRunningActivityLocked(null);
                if (r.nowVisible) {
                    outResult.timeout = false;
                    outResult.who = new ComponentName(r.info.packageName, r.info.name);
                    outResult.totalTime = 0;
                    outResult.thisTime = 0;
                } else {
                    outResult.thisTime = SystemClock.uptimeMillis();
                    mWaitingActivityVisible.add(outResult);
                    do {
                        try {
                            mService.wait();
                        } catch (InterruptedException e) {
                        }
                    } while (!outResult.timeout && outResult.who == null);
                }
            }
        }

        return res;
    }
}




//______________________________________________________________________________________________________________
Binder對象的遠程接口

要想將新的Activity在新的Task中打開,則必須設置intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),並且設置
這個Activity在Manifest.xml中的聲明中添加了Task affinity,這個與之前的Activity所在棧的affinity不相同,才能在新的Task中打開新的Activity

adb dump 工具:adb shell dumpsys activity >c:\activity.txt :生成dump文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章