1. 程式人生 > >Android應用程式啟動過程原始碼分析(2)

Android應用程式啟動過程原始碼分析(2)

Step 9. ActivityStack.startActivityUncheckedLocked

        這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java檔案中:


view plain
public class ActivityStack {  
  
    ......  
  
    final int startActivityUncheckedLocked(ActivityRecord r,  
        ActivityRecord sourceRecord, Uri[] grantedUriPermissions,  
        int grantedMode, boolean onlyIfNeeded, boolean doResume) {  
        final Intent intent = r.intent;  
        final int callingUid = r.launchedFromUid;  
  
        int launchFlags = intent.getFlags();  
  
        // 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;  
          
        ......  
  
        ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)  
            != 0 ? r : null;  
  
        // 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 (onlyIfNeeded) {  
            ......  
        }  
  
        if (sourceRecord == null) {  
            ......  
        } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {  
            ......  
        } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE  
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {  
            ......  
        }  
  
        if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {  
            ......  
        }  
  
        boolean addingToTask = false;  
        if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&  
            (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)  
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK  
            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {  
                // If bring to front is requested, and no result is requested, and  
                // we can find a task that was started with this same  
                // component, then instead of launching bring that one to the front.  
                if (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 taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE  
                        ? findTaskLocked(intent, r.info)  
                        : findActivityLocked(intent, r.info);  
                    if (taskTop != null) {  
                        ......  
                    }  
                }  
        }  
  
        ......  
  
        if (r.packageName != null) {  
            // If the activity being launched is the same as the one currently  
            // at the top, then we need to check if it should only be launched  
            // once.  
            ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);  
            if (top != null && r.resultTo == null) {  
                if (top.realActivity.equals(r.realActivity)) {  
                    ......  
                }  
            }  
  
        } else {  
            ......  
        }  
  
        boolean newTask = false;  
  
        // Should this be considered a new task?  
        if (r.resultTo == null && !addingToTask  
            && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {  
                // todo: should do better management of integers.  
                mService.mCurTask++;  
                if (mService.mCurTask <= 0) {  
                    mService.mCurTask = 1;  
                }  
                r.task = new TaskRecord(mService.mCurTask, r.info, intent,  
                    (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);  
                ......  
                newTask = true;  
                if (mMainStack) {  
                    mService.addRecentTaskLocked(r.task);  
                }  
  
        } else if (sourceRecord != null) {  
            ......  
        } else {  
            ......  
        }  
  
        ......  
  
        startActivityLocked(r, newTask, doResume);  
        return START_SUCCESS;  
    }  
  
    ......  
  
}  
        函式首先獲得intent的標誌值,儲存在launchFlags變數中。

        這個intent的標誌值的位Intent.FLAG_ACTIVITY_NO_USER_ACTION沒有置位,因此 ,成員變數mUserLeaving的值為true。

        這個intent的標誌值的位Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP也沒有置位,因此,變數notTop的值為null。

        由於在這個例子的AndroidManifest.xml檔案中,MainActivity沒有配置launchMode屬值,因此,這裡的r.launchMode為預設值0,表示以標準(Standard,或者稱為ActivityInfo.LAUNCH_MULTIPLE)的方式來啟動這個Activity。Activity的啟動方式有四種,其餘三種分別是ActivityInfo.LAUNCH_SINGLE_INSTANCE、ActivityInfo.LAUNCH_SINGLE_TASK和ActivityInfo.LAUNCH_SINGLE_TOP,具體可以參考官方網站

http://developer.android.com/reference/android/content/pm/ActivityInfo.html

        傳進來的引數r.resultTo為null,表示Launcher不需要等這個即將要啟動的MainActivity的執行結果。

        由於這個intent的標誌值的位Intent.FLAG_ACTIVITY_NEW_TASK被置位,而且Intent.FLAG_ACTIVITY_MULTIPLE_TASK沒有置位,因此,下面的if語句會被執行:


view plain
   if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&  
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)  
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK  
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {  
    // If bring to front is requested, and no result is requested, and  
    // we can find a task that was started with this same  
    // component, then instead of launching bring that one to the front.  
    if (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 taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE  
            ? findTaskLocked(intent, r.info)  
            : findActivityLocked(intent, r.info);  
        if (taskTop != null) {  
            ......  
        }  
    }  
   }  
        這段程式碼的邏輯是檢視一下,當前有沒有Task可以用來執行這個Activity。由於r.launchMode的值不為ActivityInfo.LAUNCH_SINGLE_INSTANCE,因此,它通過findTaskLocked函式來查詢存不存這樣的Task,這裡返回的結果是null,即taskTop為null,因此,需要建立一個新的Task來啟動這個Activity。

        接著往下看:


view plain
   if (r.packageName != null) {  
// If the activity being launched is the same as the one currently  
// at the top, then we need to check if it should only be launched  
// once.  
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);  
if (top != null && r.resultTo == null) {  
    if (top.realActivity.equals(r.realActivity)) {  
        ......  
    }  
}  
  
   }   
        這段程式碼的邏輯是看一下,當前在堆疊頂端的Activity是否就是即將要啟動的Activity,有些情況下,如果即將要啟動的Activity就在堆疊的頂端,那麼,就不會重新啟動這個Activity的別一個例項了,具體可以參考官方網站http://developer.android.com/reference/android/content/pm/ActivityInfo.html。現在處理堆疊頂端的Activity是Launcher,與我們即將要啟動的MainActivity不是同一個Activity,因此,這裡不用進一步處理上述介紹的情況。

       執行到這裡,我們知道,要在一個新的Task裡面來啟動這個Activity了,於是新建立一個Task:


view plain
  if (r.resultTo == null && !addingToTask  
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {  
// todo: should do better management of integers.  
mService.mCurTask++;  
if (mService.mCurTask <= 0) {  
    mService.mCurTask = 1;  
}  
r.task = new TaskRecord(mService.mCurTask, r.info, intent,  
    (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);  
......  
newTask = true;  
if (mMainStack) {  
    mService.addRecentTaskLocked(r.task);  
}  
  
   }  
        新建的Task儲存在r.task域中,同時,新增到mService中去,這裡的mService就是ActivityManagerService了。

        最後就進入startActivityLocked(r, newTask, doResume)進一步處理了。這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java檔案中:


view plain
public class ActivityStack {  
  
    ......  
  
    private final void startActivityLocked(ActivityRecord r, boolean newTask,  
            boolean doResume) {  
        final int NH = mHistory.size();  
  
        int addPos = -1;  
  
        if (!newTask) {  
            ......  
        }  
  
        // Place a new activity at top of stack, so it is next to interact  
        // with the user.  
        if (addPos < 0) {  
            addPos = NH;  
        }  
  
        // If we are not placing the new activity frontmost, we do not want  
        // to deliver the onUserLeaving callback to the actual frontmost  
        // activity  
        if (addPos < NH) {  
            ......  
        }  
  
        // Slot the activity into the history stack and proceed  
        mHistory.add(addPos, r);  
        r.inHistory = true;  
        r.frontOfTask = newTask;  
        r.task.numActivities++;  
        if (NH > 0) {  
            // We want to show the starting preview window if we are  
            // switching to a new task, or the next activity's process is  
            // not currently running.  
            ......  
        } else {  
            // If this is the first activity, don't do any fancy animations,  
            // because there is nothing for it to animate on top of.  
            ......  
        }  
          
        ......  
  
        if (doResume) {  
            resumeTopActivityLocked(null);  
        }  
    }  
  
    ......  
  
}  
        這裡的NH表示當前系統中歷史任務的個數,這裡肯定是大於0,因為Launcher已經跑起來了。當NH>0時,並且現在要切換新任務時,要做一些任務切的介面操作,這段程式碼我們就不看了,這裡不會影響到下面啟Activity的過程,有興趣的讀取可以自己研究一下。

        這裡傳進來的引數doResume為true,於是呼叫resumeTopActivityLocked進一步操作。

        Step 10. Activity.resumeTopActivityLocked

        這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java檔案中:


view plain
public class ActivityStack {  
  
    ......  
  
    /** 
    * Ensure that the top activity in the stack is resumed. 
    * 
    * @param prev The previously resumed activity, for when in the process 
    * of pausing; can be null to call from elsewhere. 
    * 
    * @return Returns true if something is being resumed, or false if 
    * nothing happened. 
    */  
    final boolean resumeTopActivityLocked(ActivityRecord prev) {  
        // Find the first activity that is not finishing.  
        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 = mUserLeaving;  
        mUserLeaving = false;  
  
        if (next == null) {  
            ......  
        }  
  
        next.delayedResume = false;  
  
        // If the top activity is the resumed one, nothing to do.  
        if (mResumedActivity == next && next.state == ActivityState.RESUMED) {  
            ......  
        }  
  
        // 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.mSleeping || mService.mShuttingDown)  
            && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {  
            ......  
        }  
  
        ......  
  
        // If we are currently pausing an activity, then don't do anything  
        // until that is done.  
        if (mPausingActivity != null) {  
            ......  
        }  
  
        ......  
  
        // We need to start pausing the current activity so the top one  
        // can be resumed...  
        if (mResumedActivity != null) {  
            ......  
            startPausingLocked(userLeaving, false);  
            return true;  
        }  
  
        ......  
    }  
  
    ......  
  
}  
        函式先通過呼叫topRunningActivityLocked函式獲得堆疊頂端的Activity,這裡就是MainActivity了,這是在上面的Step 9設定好的,儲存在next變數中。 

       接下來把mUserLeaving的儲存在本地變數userLeaving中,然後重新設定為false,在上面的Step 9中,mUserLeaving的值為true,因此,這裡的userLeaving為true。

       這裡的mResumedActivity為Launcher,因為Launcher是當前正被執行的Activity。

       當我們處理休眠狀態時,mLastPausedActivity儲存堆疊頂端的Activity,因為當前不是休眠狀態,所以mLastPausedActivity為null。

       有了這些資訊之後,下面的語句就容易理解了:


view plain
   // If the top activity is the resumed one, nothing to do.  
   if (mResumedActivity == next && next.state == ActivityState.RESUMED) {  
......  
   }  
  
   // 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.mSleeping || mService.mShuttingDown)  
&& mLastPausedActivity == next && next.state == ActivityState.PAUSED) {  
......  
   }  
        它首先看要啟動的Activity是否就是當前處理Resumed狀態的Activity,如果是的話,那就什麼都不用做,直接返回就可以了;否則再看一下系統當前是否休眠狀態,如果是的話,再看看要啟動的Activity是否就是當前處於堆疊頂端的Activity,如果是的話,也是什麼都不用做。

        上面兩個條件都不滿足,因此,在繼續往下執行之前,首先要把當處於Resumed狀態的Activity推入Paused狀態,然後才可以啟動新的Activity。但是在將當前這個Resumed狀態的Activity推入Paused狀態之前,首先要看一下當前是否有Activity正在進入Pausing狀態,如果有的話,當前這個Resumed狀態的Activity就要稍後才能進入Paused狀態了,這樣就保證了所有需要進入Paused狀態的Activity序列處理。

        這裡沒有處於Pausing狀態的Activity,即mPausingActivity為null,而且mResumedActivity也不為null,於是就呼叫startPausingLocked函式把Launcher推入Paused狀態去了。

        Step 11. ActivityStack.startPausingLocked

        這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java檔案中:


view plain
public class ActivityStack {  
  
    ......  
  
    private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {  
        if (mPausingActivity != null) {  
            ......  
        }  
        ActivityRecord prev = mResumedActivity;  
        if (prev == null) {  
            ......  
        }  
        ......  
        mResumedActivity = null;  
        mPausingActivity = prev;  
        mLastPausedActivity = prev;  
        prev.state = ActivityState.PAUSING;  
        ......  
  
        if (prev.app != null && prev.app.thread != null) {  
            ......  
            try {  
                ......  
                prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,  
                    prev.configChangeFlags);  
                ......  
            } catch (Exception e) {  
                ......  
            }  
        } else {  
            ......  
        }  
  
        ......  
      
    }  
  
    ......  
  
}  

        函式首先把mResumedActivity儲存在本地變數prev中。在上一步Step 10中,說到mResumedActivity就是Launcher,因此,這裡把Launcher程序中的ApplicationThread物件取出來,通過它來通知Launcher這個Activity它要進入Paused狀態了。當然,這裡的prev.app.thread是一個ApplicationThread物件的遠端介面,通過呼叫這個遠端介面的schedulePauseActivity來通知Launcher進入Paused狀態。

       引數prev.finishing表示prev所代表的Activity是否正在等待結束的Activity列表中,由於Laucher這個Activity還沒結束,所以這裡為false;引數prev.configChangeFlags表示哪些config發生了變化,這裡我們不關心它的值。

       Step 12. ApplicationThreadProxy.schedulePauseActivity

       這個函式定義在frameworks/base/core/java/android/app/ApplicationThreadNative.java檔案中:


view plain
class ApplicationThreadProxy implements IApplicationThread {  
      
    ......  
  
    public final void schedulePauseActivity(IBinder token, boolean finished,  
    boolean userLeaving, int configChanges) throws RemoteException {  
        Parcel data = Parcel.obtain();  
        data.writeInterfaceToken(IApplicationThread.descriptor);  
        data.writeStrongBinder(token);  
        data.writeInt(finished ? 1 : 0);  
        data.writeInt(userLeaving ? 1 :0);  
        data.writeInt(configChanges);  
        mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,  
            IBinder.FLAG_ONEWAY);  
        data.recycle();  
    }  
  
    ......  
  
}  

        這個函式通過Binder程序間通訊機制進入到ApplicationThread.schedulePauseActivity函式中。

        Step 13. ApplicationThread.schedulePauseActivity

        這個函式定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中,它是ActivityThread的內部類:


view plain
public final class ActivityThread {  
      
    ......  
  
    private final class ApplicationThread extends ApplicationThreadNative {  
          
        ......  
  
        public final void schedulePauseActivity(IBinder token, boolean finished,  
                boolean userLeaving, int configChanges) {  
            queueOrSendMessage(  
                finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,  
                token,  
                (userLeaving ? 1 : 0),  
                configChanges);  
        }  
  
        ......  
  
    }  
  
    ......  
  
}  
        這裡呼叫的函式queueOrSendMessage是ActivityThread類的成員函式。

       上面說到,這裡的finished值為false,因此,queueOrSendMessage的第一個引數值為H.PAUSE_ACTIVITY,表示要暫停token所代表的Activity,即Launcher。

       Step 14. ActivityThread.queueOrSendMessage

       這個函式定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中:


view plain
public final class ActivityThread {  
      
    ......  
  
    private final void queueOrSendMessage(int what, Object obj, int arg1) {  
        queueOrSendMessage(what, obj, arg1, 0);  
    }  
  
    private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {  
        synchronized (this) {  
            ......  
            Message msg = Message.obtain();  
            msg.what = what;  
            msg.obj = obj;  
            msg.arg1 = arg1;  
            msg.arg2 = arg2;  
            mH.sendMessage(msg);  
        }  
    }  
  
    ......  
  
}  
        這裡首先將相關資訊組裝成一個msg,然後通過mH成員變數傳送出去,mH的型別是H,繼承於Handler類,是ActivityThread的內部類,因此,這個訊息最後由H.handleMessage來處理。

        Step 15. H.handleMessage

        這個函式定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中:


view plain
public final class ActivityThread {  
      
    ......  
  
    private final class H extends Handler {  
  
        ......  
  
        public void handleMessage(Message msg) {  
            ......  
            switch (msg.what) {  
              
            ......  
              
            case PAUSE_ACTIVITY:  
                handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);  
                maybeSnapshot();  
                break;  
  
            ......  
  
            }  
        ......  
  
    }  
  
    ......  
  
}  

        這裡呼叫ActivityThread.handlePauseActivity進一步操作,msg.obj是一個ActivityRecord物件的引用,它代表的是Launcher這個Activity。